Merge branch 'embassy-rs:master' into master

This commit is contained in:
Chuck Davis 2023-05-03 21:07:28 -05:00 committed by GitHub
commit 91d1fff4ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 750 additions and 505 deletions

View File

@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
use crate::pac::common::{Reg, RW}; use crate::pac::common::{Reg, RW};
use crate::pac::SIO; use crate::pac::SIO;
use crate::{interrupt, pac, peripherals, Peripheral}; use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
const PIN_COUNT: usize = 30; const PIN_COUNT: usize = 30;
const NEW_AW: AtomicWaker = AtomicWaker::new(); const NEW_AW: AtomicWaker = AtomicWaker::new();
@ -136,16 +136,11 @@ pub enum InterruptTrigger {
AnyEdge, AnyEdge,
} }
impl InterruptTrigger { pub(crate) unsafe fn init() {
fn from_u32(value: u32) -> Option<InterruptTrigger> { let irq = interrupt::IO_IRQ_BANK0::steal();
match value { irq.disable();
1 => Some(InterruptTrigger::LevelLow), irq.set_priority(interrupt::Priority::P3);
2 => Some(InterruptTrigger::LevelHigh), irq.enable();
3 => Some(InterruptTrigger::EdgeLow),
4 => Some(InterruptTrigger::EdgeHigh),
_ => None,
}
}
} }
#[interrupt] #[interrupt]
@ -166,27 +161,15 @@ unsafe fn IO_IRQ_BANK0() {
let pin_group = (pin % 8) as usize; let pin_group = (pin % 8) as usize;
let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32; let event = (intsx.read().0 >> pin_group * 4) & 0xf as u32;
if let Some(trigger) = InterruptTrigger::from_u32(event) { // no more than one event can be awaited per pin at any given time, so
critical_section::with(|_| { // we can just clear all interrupt enables for that pin without having
proc_intx.inte(pin / 8).modify(|w| match trigger { // to check which event was signalled.
InterruptTrigger::AnyEdge => { if event != 0 {
w.set_edge_high(pin_group, false); proc_intx.inte(pin / 8).write_clear(|w| {
w.set_edge_low(pin_group, false); w.set_edge_high(pin_group, true);
} w.set_edge_low(pin_group, true);
InterruptTrigger::LevelHigh => { w.set_level_high(pin_group, true);
trace!("IO_IRQ_BANK0 pin {} LevelHigh triggered", pin); w.set_level_low(pin_group, true);
w.set_level_high(pin_group, false);
}
InterruptTrigger::LevelLow => {
w.set_level_low(pin_group, false);
}
InterruptTrigger::EdgeHigh => {
w.set_edge_high(pin_group, false);
}
InterruptTrigger::EdgeLow => {
w.set_edge_low(pin_group, false);
}
});
}); });
INTERRUPT_WAKERS[pin as usize].wake(); INTERRUPT_WAKERS[pin as usize].wake();
} }
@ -203,16 +186,26 @@ impl<'d, T: Pin> InputFuture<'d, T> {
pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self { pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
into_ref!(pin); into_ref!(pin);
unsafe { unsafe {
let irq = interrupt::IO_IRQ_BANK0::steal(); let pin_group = (pin.pin() % 8) as usize;
irq.disable(); // first, clear the INTR register bits. without this INTR will still
irq.set_priority(interrupt::Priority::P3); // contain reports of previous edges, causing the IRQ to fire early
// on stale state. clearing these means that we can only detect edges
// that occur *after* the clear happened, but since both this and the
// alternative are fundamentally racy it's probably fine.
// (the alternative being checking the current level and waiting for
// its inverse, but that requires reading the current level and thus
// missing anything that happened before the level was read.)
pac::IO_BANK0.intr(pin.pin() as usize / 8).write(|w| {
w.set_edge_high(pin_group, true);
w.set_edge_low(pin_group, true);
});
// Each INTR register is divided into 8 groups, one group for each // Each INTR register is divided into 8 groups, one group for each
// pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, // pin, and each group consists of LEVEL_LOW, LEVEL_HIGH, EDGE_LOW,
// and EGDE_HIGH. // and EGDE_HIGH.
let pin_group = (pin.pin() % 8) as usize; pin.int_proc()
critical_section::with(|_| { .inte((pin.pin() / 8) as usize)
pin.int_proc().inte((pin.pin() / 8) as usize).modify(|w| match level { .write_set(|w| match level {
InterruptTrigger::LevelHigh => { InterruptTrigger::LevelHigh => {
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
w.set_level_high(pin_group, true); w.set_level_high(pin_group, true);
@ -227,12 +220,10 @@ impl<'d, T: Pin> InputFuture<'d, T> {
w.set_edge_low(pin_group, true); w.set_edge_low(pin_group, true);
} }
InterruptTrigger::AnyEdge => { InterruptTrigger::AnyEdge => {
// noop w.set_edge_high(pin_group, true);
w.set_edge_low(pin_group, true);
} }
}); });
});
irq.enable();
} }
Self { pin, level } Self { pin, level }
@ -257,48 +248,22 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
// LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin. // LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
let pin_group = (self.pin.pin() % 8) as usize; let pin_group = (self.pin.pin() % 8) as usize;
// This should check the the level of the interrupt trigger level of // since the interrupt handler clears all INTE flags we'll check that
// the pin and if it has been disabled that means it was done by the // all have been cleared and unconditionally return Ready(()) if so.
// interrupt service routine, so we then know that the event/trigger // we don't need further handshaking since only a single event wait
// happened and Poll::Ready will be returned. // is possible for any given pin at any given time.
trace!("{:?} for pin {}", self.level, self.pin.pin()); if !inte.edge_high(pin_group)
match self.level { && !inte.edge_low(pin_group)
InterruptTrigger::AnyEdge => { && !inte.level_high(pin_group)
if !inte.edge_high(pin_group) && !inte.edge_low(pin_group) { && !inte.level_low(pin_group)
#[rustfmt::skip] {
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin()); trace!(
"{:?} for pin {} was cleared, return Poll::Ready",
self.level,
self.pin.pin()
);
return Poll::Ready(()); return Poll::Ready(());
} }
}
InterruptTrigger::LevelHigh => {
if !inte.level_high(pin_group) {
#[rustfmt::skip]
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
InterruptTrigger::LevelLow => {
if !inte.level_low(pin_group) {
#[rustfmt::skip]
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
InterruptTrigger::EdgeHigh => {
if !inte.edge_high(pin_group) {
#[rustfmt::skip]
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
InterruptTrigger::EdgeLow => {
if !inte.edge_low(pin_group) {
#[rustfmt::skip]
trace!("{:?} for pin {} was cleared, return Poll::Ready", self.level, self.pin.pin());
return Poll::Ready(());
}
}
}
trace!("InputFuture::poll return Poll::Pending"); trace!("InputFuture::poll return Poll::Pending");
Poll::Pending Poll::Pending
} }
@ -644,23 +609,17 @@ impl<'d, T: Pin> Flex<'d, T> {
#[inline] #[inline]
pub async fn wait_for_rising_edge(&mut self) { pub async fn wait_for_rising_edge(&mut self) {
self.wait_for_low().await; InputFuture::new(&mut self.pin, InterruptTrigger::EdgeHigh).await;
self.wait_for_high().await;
} }
#[inline] #[inline]
pub async fn wait_for_falling_edge(&mut self) { pub async fn wait_for_falling_edge(&mut self) {
self.wait_for_high().await; InputFuture::new(&mut self.pin, InterruptTrigger::EdgeLow).await;
self.wait_for_low().await;
} }
#[inline] #[inline]
pub async fn wait_for_any_edge(&mut self) { pub async fn wait_for_any_edge(&mut self) {
if self.is_high() { InputFuture::new(&mut self.pin, InterruptTrigger::AnyEdge).await;
self.wait_for_low().await;
} else {
self.wait_for_high().await;
}
} }
} }

View File

@ -157,6 +157,7 @@ pub fn init(_config: config::Config) -> Peripherals {
timer::init(); timer::init();
dma::init(); dma::init();
pio::init(); pio::init();
gpio::init();
} }
peripherals peripherals

View File

@ -33,7 +33,7 @@ use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
use crate::interrupt::{Interrupt, InterruptExt}; use crate::interrupt::{Interrupt, InterruptExt};
use crate::peripherals::CORE1; use crate::peripherals::CORE1;
use crate::{interrupt, pac}; use crate::{gpio, interrupt, pac};
const PAUSE_TOKEN: u32 = 0xDEADBEEF; const PAUSE_TOKEN: u32 = 0xDEADBEEF;
const RESUME_TOKEN: u32 = !0xDEADBEEF; const RESUME_TOKEN: u32 = !0xDEADBEEF;
@ -68,6 +68,9 @@ fn install_stack_guard(stack_bottom: *mut usize) {
#[inline(always)] #[inline(always)]
fn core1_setup(stack_bottom: *mut usize) { fn core1_setup(stack_bottom: *mut usize) {
install_stack_guard(stack_bottom); install_stack_guard(stack_bottom);
unsafe {
gpio::init();
}
} }
/// Data type for a properly aligned stack of N bytes /// Data type for a properly aligned stack of N bytes

View File

@ -5,14 +5,14 @@ use core::sync::atomic::{compiler_fence, Ordering};
use core::task::{Context, Poll}; use core::task::{Context, Poll};
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
use embassy_hal_common::PeripheralRef; use embassy_hal_common::{Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use crate::dma::{Channel, Transfer}; use crate::dma::{Channel, Transfer, Word};
use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::sealed::Pin as SealedPin;
use crate::gpio::{Drive, Pin, Pull, SlewRate}; use crate::gpio::{Drive, Pin, Pull, SlewRate};
use crate::pac::dma::vals::{DataSize, TreqSel}; use crate::pac::dma::vals::TreqSel;
use crate::pio::sealed::{PioInstance as _, SmInstance as _}; use crate::pio::sealed::PioInstance as _;
use crate::{interrupt, pac, peripherals, RegExt}; use crate::{interrupt, pac, peripherals, RegExt};
struct Wakers([AtomicWaker; 12]); struct Wakers([AtomicWaker; 12]);
@ -119,10 +119,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture
if self.get_mut().sm.try_push_tx(value) { if self.get_mut().sm.try_push_tx(value) {
Poll::Ready(()) Poll::Ready(())
} else { } else {
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker()); WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::SM as usize].register(cx.waker());
unsafe { unsafe {
PIO::PIO.irqs(0).inte().write_set(|m| { PIO::PIO.irqs(0).inte().write_set(|m| {
m.0 = TXNFULL_MASK << SM::Sm::SM_NO; m.0 = TXNFULL_MASK << SM::SM;
}); });
} }
// debug!("Pending"); // debug!("Pending");
@ -135,7 +135,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
PIO::PIO.irqs(0).inte().write_clear(|m| { PIO::PIO.irqs(0).inte().write_clear(|m| {
m.0 = TXNFULL_MASK << SM::Sm::SM_NO; m.0 = TXNFULL_MASK << SM::SM;
}); });
} }
} }
@ -164,10 +164,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO,
if let Some(v) = self.sm.try_pull_rx() { if let Some(v) = self.sm.try_pull_rx() {
Poll::Ready(v) Poll::Ready(v)
} else { } else {
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker()); WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::SM].register(cx.waker());
unsafe { unsafe {
PIO::PIO.irqs(0).inte().write_set(|m| { PIO::PIO.irqs(0).inte().write_set(|m| {
m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; m.0 = RXNEMPTY_MASK << SM::SM;
}); });
} }
//debug!("Pending"); //debug!("Pending");
@ -180,7 +180,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
PIO::PIO.irqs(0).inte().write_clear(|m| { PIO::PIO.irqs(0).inte().write_clear(|m| {
m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; m.0 = RXNEMPTY_MASK << SM::SM;
}); });
} }
} }
@ -277,15 +277,14 @@ impl<PIO: PioInstance> PioPin<PIO> {
#[inline] #[inline]
pub fn set_pull(&mut self, pull: Pull) { pub fn set_pull(&mut self, pull: Pull) {
unsafe { unsafe {
self.pad_ctrl().modify(|w| match pull { self.pad_ctrl().modify(|w| {
Pull::Up => w.set_pue(true), w.set_pue(pull == Pull::Up);
Pull::Down => w.set_pde(true), w.set_pde(pull == Pull::Down);
Pull::None => {}
}); });
} }
} }
/// Set the pin's pull. /// Set the pin's schmitt trigger.
#[inline] #[inline]
pub fn set_schmitt(&mut self, enable: bool) { pub fn set_schmitt(&mut self, enable: bool) {
unsafe { unsafe {
@ -298,9 +297,11 @@ impl<PIO: PioInstance> PioPin<PIO> {
pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
let mask = 1 << self.pin(); let mask = 1 << self.pin();
unsafe { unsafe {
PIO::PIO if bypass {
.input_sync_bypass() PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
.modify(|w| *w = if bypass { *w & !mask } else { *w | mask }); } else {
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
}
} }
} }
@ -315,16 +316,15 @@ impl<PIO: PioInstance> SealedPin for PioPin<PIO> {
} }
} }
pub struct PioStateMachineInstance<PIO: PioInstance, SM: SmInstance> { pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> {
pio: PhantomData<PIO>, pio: PhantomData<&'d PIO>,
sm: PhantomData<SM>,
} }
impl<PIO: PioInstance, SM: SmInstance> sealed::PioStateMachine for PioStateMachineInstance<PIO, SM> { impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {
type Pio = PIO; type Pio = PIO;
type Sm = SM; const SM: usize = SM;
} }
impl<PIO: PioInstance, SM: SmInstance> PioStateMachine for PioStateMachineInstance<PIO, SM> {} impl<'d, PIO: PioInstance, const SM: usize> PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {}
pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn pio_no(&self) -> u8 { fn pio_no(&self) -> u8 {
@ -332,60 +332,61 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
fn sm_no(&self) -> u8 { fn sm_no(&self) -> u8 {
Self::Sm::SM_NO Self::SM as u8
} }
fn restart(&mut self) { fn restart(&mut self) {
let mask = 1u8 << Self::SM;
unsafe { unsafe {
Self::Pio::PIO Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
.ctrl()
.modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO));
} }
} }
fn set_enable(&mut self, enable: bool) { fn set_enable(&mut self, enable: bool) {
let mask = 1u8 << Self::Sm::SM_NO; let mask = 1u8 << Self::SM;
unsafe { unsafe {
Self::Pio::PIO if enable {
.ctrl() Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
.modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 }))); } else {
Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
}
} }
} }
fn is_enabled(&self) -> bool { fn is_enabled(&self) -> bool {
unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 } unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::SM) != 0 }
} }
fn is_tx_empty(&self) -> bool { fn is_tx_empty(&self) -> bool {
unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 } unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::SM) != 0 }
} }
fn is_tx_full(&self) -> bool { fn is_tx_full(&self) -> bool {
unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 } unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::SM) != 0 }
} }
fn is_rx_empty(&self) -> bool { fn is_rx_empty(&self) -> bool {
unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 } unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::SM) != 0 }
} }
fn is_rx_full(&self) -> bool { fn is_rx_full(&self) -> bool {
unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 } unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::SM) != 0 }
} }
fn tx_level(&self) -> u8 { fn tx_level(&self) -> u8 {
unsafe { unsafe {
let flevel = Self::Pio::PIO.flevel().read().0; let flevel = Self::Pio::PIO.flevel().read().0;
(flevel >> (Self::Sm::SM_NO * 8)) as u8 & 0x0f (flevel >> (Self::SM * 8)) as u8 & 0x0f
} }
} }
fn rx_level(&self) -> u8 { fn rx_level(&self) -> u8 {
unsafe { unsafe {
let flevel = Self::Pio::PIO.flevel().read().0; let flevel = Self::Pio::PIO.flevel().read().0;
(flevel >> (Self::Sm::SM_NO * 8 + 4)) as u8 & 0x0f (flevel >> (Self::SM * 8 + 4)) as u8 & 0x0f
} }
} }
fn push_tx(&mut self, v: u32) { fn push_tx(&mut self, v: u32) {
unsafe { unsafe {
Self::Pio::PIO.txf(Self::Sm::SM_NO as usize).write_value(v); Self::Pio::PIO.txf(Self::SM).write_value(v);
} }
} }
@ -398,7 +399,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
fn pull_rx(&mut self) -> u32 { fn pull_rx(&mut self) -> u32 {
unsafe { Self::Pio::PIO.rxf(Self::Sm::SM_NO as usize).read() } unsafe { Self::Pio::PIO.rxf(Self::SM).read() }
} }
fn try_pull_rx(&mut self) -> Option<u32> { fn try_pull_rx(&mut self) -> Option<u32> {
@ -410,73 +411,54 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_clkdiv(&mut self, div_x_256: u32) { fn set_clkdiv(&mut self, div_x_256: u32) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8);
.sm(Self::Sm::SM_NO as usize)
.clkdiv()
.write(|w| w.0 = div_x_256 << 8);
} }
} }
fn get_clkdiv(&self) -> u32 { fn get_clkdiv(&self) -> u32 {
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).clkdiv().read().0 >> 8 } unsafe { Self::this_sm().clkdiv().read().0 >> 8 }
} }
fn clkdiv_restart(&mut self) { fn clkdiv_restart(&mut self) {
let mask = 1u8 << Self::SM;
unsafe { unsafe {
Self::Pio::PIO Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
.ctrl()
.modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO));
} }
} }
fn set_side_enable(&self, enable: bool) { fn set_side_enable(&self, enable: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().execctrl().modify(|w| w.set_side_en(enable));
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.modify(|w| w.set_side_en(enable));
} }
} }
fn is_side_enabled(&self) -> bool { fn is_side_enabled(&self) -> bool {
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().side_en() } unsafe { Self::this_sm().execctrl().read().side_en() }
} }
fn set_side_pindir(&mut self, pindir: bool) { fn set_side_pindir(&mut self, pindir: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir));
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.modify(|w| w.set_side_pindir(pindir));
} }
} }
fn is_side_pindir(&self) -> bool { fn is_side_pindir(&self) -> bool {
unsafe { unsafe { Self::this_sm().execctrl().read().side_pindir() }
Self::Pio::PIO
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.read()
.side_pindir()
}
} }
fn set_jmp_pin(&mut self, pin: u8) { fn set_jmp_pin(&mut self, pin: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin));
.sm(Self::Sm::SM_NO as usize)
.execctrl()
.modify(|w| w.set_jmp_pin(pin));
} }
} }
fn get_jmp_pin(&mut self) -> u8 { fn get_jmp_pin(&mut self) -> u8 {
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().jmp_pin() } unsafe { Self::this_sm().execctrl().read().jmp_pin() }
} }
fn set_wrap(&self, source: u8, target: u8) { fn set_wrap(&self, source: u8, target: u8) {
unsafe { unsafe {
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().modify(|w| { Self::this_sm().execctrl().modify(|w| {
w.set_wrap_top(source); w.set_wrap_top(source);
w.set_wrap_bottom(target) w.set_wrap_bottom(target)
}); });
@ -486,7 +468,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
/// Get wrapping addresses. Returns (source, target). /// Get wrapping addresses. Returns (source, target).
fn get_wrap(&self) -> (u8, u8) { fn get_wrap(&self) -> (u8, u8) {
unsafe { unsafe {
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read(); let r = Self::this_sm().execctrl().read();
(r.wrap_top(), r.wrap_bottom()) (r.wrap_top(), r.wrap_bottom())
} }
} }
@ -498,7 +480,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
FifoJoin::TxOnly => (false, true), FifoJoin::TxOnly => (false, true),
}; };
unsafe { unsafe {
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().modify(|w| { Self::this_sm().shiftctrl().modify(|w| {
w.set_fjoin_rx(rx); w.set_fjoin_rx(rx);
w.set_fjoin_tx(tx) w.set_fjoin_tx(tx)
}); });
@ -506,7 +488,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
fn get_fifo_join(&self) -> FifoJoin { fn get_fifo_join(&self) -> FifoJoin {
unsafe { unsafe {
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); let r = Self::this_sm().shiftctrl().read();
// Ignores the invalid state when both bits are set // Ignores the invalid state when both bits are set
if r.fjoin_rx() { if r.fjoin_rx() {
FifoJoin::RxOnly FifoJoin::RxOnly
@ -521,7 +503,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn clear_fifos(&mut self) { fn clear_fifos(&mut self) {
// Toggle FJOIN_RX to flush FIFOs // Toggle FJOIN_RX to flush FIFOs
unsafe { unsafe {
let shiftctrl = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl(); let shiftctrl = Self::this_sm().shiftctrl();
shiftctrl.modify(|w| { shiftctrl.modify(|w| {
w.set_fjoin_rx(!w.fjoin_rx()); w.set_fjoin_rx(!w.fjoin_rx());
}); });
@ -533,51 +515,33 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_pull_threshold(&mut self, threshold: u8) { fn set_pull_threshold(&mut self, threshold: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_pull_thresh(threshold));
} }
} }
fn get_pull_threshold(&self) -> u8 { fn get_pull_threshold(&self) -> u8 {
unsafe { unsafe { Self::this_sm().shiftctrl().read().pull_thresh() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read();
r.pull_thresh()
}
} }
fn set_push_threshold(&mut self, threshold: u8) { fn set_push_threshold(&mut self, threshold: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_push_thresh(threshold));
} }
} }
fn get_push_threshold(&self) -> u8 { fn get_push_threshold(&self) -> u8 {
unsafe { unsafe { Self::this_sm().shiftctrl().read().push_thresh() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read();
r.push_thresh()
}
} }
fn set_out_shift_dir(&mut self, dir: ShiftDirection) { fn set_out_shift_dir(&mut self, dir: ShiftDirection) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm()
.sm(Self::Sm::SM_NO as usize)
.shiftctrl() .shiftctrl()
.modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right));
} }
} }
fn get_out_shiftdir(&self) -> ShiftDirection { fn get_out_shiftdir(&self) -> ShiftDirection {
unsafe { unsafe {
if Self::Pio::PIO if Self::this_sm().shiftctrl().read().out_shiftdir() {
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.out_shiftdir()
{
ShiftDirection::Right ShiftDirection::Right
} else { } else {
ShiftDirection::Left ShiftDirection::Left
@ -587,20 +551,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_in_shift_dir(&mut self, dir: ShiftDirection) { fn set_in_shift_dir(&mut self, dir: ShiftDirection) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm()
.sm(Self::Sm::SM_NO as usize)
.shiftctrl() .shiftctrl()
.modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right));
} }
} }
fn get_in_shiftdir(&self) -> ShiftDirection { fn get_in_shiftdir(&self) -> ShiftDirection {
unsafe { unsafe {
if Self::Pio::PIO if Self::this_sm().shiftctrl().read().in_shiftdir() {
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.in_shiftdir()
{
ShiftDirection::Right ShiftDirection::Right
} else { } else {
ShiftDirection::Left ShiftDirection::Left
@ -610,76 +568,46 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_autopull(&mut self, auto: bool) { fn set_autopull(&mut self, auto: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_autopull(auto));
} }
} }
fn is_autopull(&self) -> bool { fn is_autopull(&self) -> bool {
unsafe { unsafe { Self::this_sm().shiftctrl().read().autopull() }
Self::Pio::PIO
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.autopull()
}
} }
fn set_autopush(&mut self, auto: bool) { fn set_autopush(&mut self, auto: bool) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto));
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.modify(|w| w.set_autopush(auto));
} }
} }
fn is_autopush(&self) -> bool { fn is_autopush(&self) -> bool {
unsafe { unsafe { Self::this_sm().shiftctrl().read().autopush() }
Self::Pio::PIO
.sm(Self::Sm::SM_NO as usize)
.shiftctrl()
.read()
.autopush()
}
} }
fn get_addr(&self) -> u8 { fn get_addr(&self) -> u8 {
unsafe { unsafe { Self::this_sm().addr().read().addr() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).addr().read();
r.addr()
}
} }
fn set_sideset_count(&mut self, count: u8) { fn set_sideset_count(&mut self, count: u8) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count));
.sm(Self::Sm::SM_NO as usize)
.pinctrl()
.modify(|w| w.set_sideset_count(count));
} }
} }
fn get_sideset_count(&self) -> u8 { fn get_sideset_count(&self) -> u8 {
unsafe { unsafe { Self::this_sm().pinctrl().read().sideset_count() }
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read();
r.sideset_count()
}
} }
fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) { fn set_sideset_base_pin(&mut self, base_pin: &PioPin<Self::Pio>) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin()));
.sm(Self::Sm::SM_NO as usize)
.pinctrl()
.modify(|w| w.set_sideset_base(base_pin.pin()));
} }
} }
fn get_sideset_base(&self) -> u8 { fn get_sideset_base(&self) -> u8 {
unsafe { unsafe {
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); let r = Self::this_sm().pinctrl().read();
r.sideset_base() r.sideset_base()
} }
} }
@ -688,7 +616,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_set_range(&mut self, base: u8, count: u8) { fn set_set_range(&mut self, base: u8, count: u8) {
assert!(base + count < 32); assert!(base + count < 32);
unsafe { unsafe {
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { Self::this_sm().pinctrl().modify(|w| {
w.set_set_base(base); w.set_set_base(base);
w.set_set_count(count) w.set_set_count(count)
}); });
@ -698,23 +626,20 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
/// Get the range of out pins affected by a set instruction. Returns (base, count). /// Get the range of out pins affected by a set instruction. Returns (base, count).
fn get_set_range(&self) -> (u8, u8) { fn get_set_range(&self) -> (u8, u8) {
unsafe { unsafe {
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); let r = Self::this_sm().pinctrl().read();
(r.set_base(), r.set_count()) (r.set_base(), r.set_count())
} }
} }
fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) { fn set_in_base_pin(&mut self, base: &PioPin<Self::Pio>) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin()));
.sm(Self::Sm::SM_NO as usize)
.pinctrl()
.modify(|w| w.set_in_base(base.pin()));
} }
} }
fn get_in_base(&self) -> u8 { fn get_in_base(&self) -> u8 {
unsafe { unsafe {
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); let r = Self::this_sm().pinctrl().read();
r.in_base() r.in_base()
} }
} }
@ -722,7 +647,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn set_out_range(&mut self, base: u8, count: u8) { fn set_out_range(&mut self, base: u8, count: u8) {
assert!(base + count < 32); assert!(base + count < 32);
unsafe { unsafe {
Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { Self::this_sm().pinctrl().modify(|w| {
w.set_out_base(base); w.set_out_base(base);
w.set_out_count(count) w.set_out_count(count)
}); });
@ -732,7 +657,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
/// Get the range of out pins affected by a set instruction. Returns (base, count). /// Get the range of out pins affected by a set instruction. Returns (base, count).
fn get_out_range(&self) -> (u8, u8) { fn get_out_range(&self) -> (u8, u8) {
unsafe { unsafe {
let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); let r = Self::this_sm().pinctrl().read();
(r.out_base(), r.out_count()) (r.out_base(), r.out_count())
} }
} }
@ -760,15 +685,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
fn get_current_instr() -> u32 { fn get_current_instr() -> u32 {
unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).instr().read().0 } unsafe { Self::this_sm().instr().read().0 }
} }
fn exec_instr(&mut self, instr: u16) { fn exec_instr(&mut self, instr: u16) {
unsafe { unsafe {
Self::Pio::PIO Self::this_sm().instr().write(|w| w.set_instr(instr));
.sm(Self::Sm::SM_NO as usize)
.instr()
.write(|w| w.set_instr(instr));
} }
} }
@ -787,8 +709,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_tx_stalled(&self) -> bool { fn has_tx_stalled(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().txstall() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_txstall(1 << Self::SM));
ret ret
} }
} }
@ -796,8 +718,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_tx_overflowed(&self) -> bool { fn has_tx_overflowed(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().txover() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_txover(1 << Self::SM));
ret ret
} }
} }
@ -805,8 +727,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_rx_stalled(&self) -> bool { fn has_rx_stalled(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().rxstall() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_rxstall(1 << Self::SM));
ret ret
} }
} }
@ -814,25 +736,25 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
fn has_rx_underflowed(&self) -> bool { fn has_rx_underflowed(&self) -> bool {
unsafe { unsafe {
let fdebug = Self::Pio::PIO.fdebug(); let fdebug = Self::Pio::PIO.fdebug();
let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0; let ret = fdebug.read().rxunder() & (1 << Self::SM) != 0;
fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO)); fdebug.write(|w| w.set_rxunder(1 << Self::SM));
ret ret
} }
} }
fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> { fn dma_push<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
unsafe { unsafe {
let pio_no = Self::Pio::PIO_NO; let pio_no = Self::Pio::PIO_NO;
let sm_no = Self::Sm::SM_NO; let sm_no = Self::SM;
let p = ch.regs(); let p = ch.regs();
p.read_addr().write_value(data.as_ptr() as u32); p.read_addr().write_value(data.as_ptr() as u32);
p.write_addr() p.write_addr().write_value(Self::Pio::PIO.txf(sm_no).ptr() as u32);
.write_value(Self::Pio::PIO.txf(sm_no as usize).ptr() as u32);
p.trans_count().write_value(data.len() as u32); p.trans_count().write_value(data.len() as u32);
compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| { p.ctrl_trig().write(|w| {
// Set TX DREQ for this statemachine // Set TX DREQ for this statemachine
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no)); w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8));
w.set_data_size(DataSize::SIZE_WORD); w.set_data_size(W::size());
w.set_chain_to(ch.number()); w.set_chain_to(ch.number());
w.set_incr_read(true); w.set_incr_read(true);
w.set_incr_write(false); w.set_incr_write(false);
@ -843,19 +765,19 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
Transfer::new(ch) Transfer::new(ch)
} }
fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> { fn dma_pull<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [W]) -> Transfer<'a, C> {
unsafe { unsafe {
let pio_no = Self::Pio::PIO_NO; let pio_no = Self::Pio::PIO_NO;
let sm_no = Self::Sm::SM_NO; let sm_no = Self::SM;
let p = ch.regs(); let p = ch.regs();
p.write_addr().write_value(data.as_ptr() as u32); p.write_addr().write_value(data.as_ptr() as u32);
p.read_addr() p.read_addr().write_value(Self::Pio::PIO.rxf(sm_no).ptr() as u32);
.write_value(Self::Pio::PIO.rxf(sm_no as usize).ptr() as u32);
p.trans_count().write_value(data.len() as u32); p.trans_count().write_value(data.len() as u32);
compiler_fence(Ordering::SeqCst);
p.ctrl_trig().write(|w| { p.ctrl_trig().write(|w| {
// Set TX DREQ for this statemachine // Set RX DREQ for this statemachine
w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4)); w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8 + 4));
w.set_data_size(DataSize::SIZE_WORD); w.set_data_size(W::size());
w.set_chain_to(ch.number()); w.set_chain_to(ch.number());
w.set_incr_read(false); w.set_incr_read(false);
w.set_incr_write(true); w.set_incr_write(true);
@ -867,21 +789,18 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin {
} }
} }
pub struct PioCommonInstance<PIO: PioInstance> { pub struct PioCommon<'d, PIO: PioInstance> {
instructions_used: u32, instructions_used: u32,
pio: PhantomData<PIO>, pio: PhantomData<&'d PIO>,
} }
pub struct PioInstanceMemory<PIO: PioInstance> { pub struct PioInstanceMemory<'d, PIO: PioInstance> {
used_mask: u32, used_mask: u32,
pio: PhantomData<PIO>, pio: PhantomData<&'d PIO>,
} }
impl<PIO: PioInstance> sealed::PioCommon for PioCommonInstance<PIO> { impl<'d, PIO: PioInstance> PioCommon<'d, PIO> {
type Pio = PIO; pub fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO>
}
impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
where where
I: Iterator<Item = u16>, I: Iterator<Item = u16>,
{ {
@ -908,66 +827,50 @@ impl<PIO: PioInstance> PioCommon for PioCommonInstance<PIO> {
} }
} }
fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>) { // TODO make instruction memory that is currently in use unfreeable
pub fn free_instr(&mut self, instrs: PioInstanceMemory<PIO>) {
self.instructions_used &= !instrs.used_mask; self.instructions_used &= !instrs.used_mask;
} }
}
pub trait PioCommon: sealed::PioCommon + Sized { pub fn is_irq_set(&self, irq_no: u8) -> bool {
fn write_instr<I>(&mut self, start: usize, instrs: I) -> PioInstanceMemory<Self::Pio>
where
I: Iterator<Item = u16>;
// TODO make instruction memory that is currently in use unfreeable
fn free_instr(&mut self, instrs: PioInstanceMemory<Self::Pio>);
fn is_irq_set(&self, irq_no: u8) -> bool {
assert!(irq_no < 8); assert!(irq_no < 8);
unsafe { unsafe {
let irq_flags = Self::Pio::PIO.irq(); let irq_flags = PIO::PIO.irq();
irq_flags.read().0 & (1 << irq_no) != 0 irq_flags.read().0 & (1 << irq_no) != 0
} }
} }
fn clear_irq(&mut self, irq_no: usize) { pub fn clear_irq(&mut self, irq_no: usize) {
assert!(irq_no < 8); assert!(irq_no < 8);
unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } unsafe { PIO::PIO.irq().write(|w| w.set_irq(1 << irq_no)) }
} }
fn clear_irqs(&mut self, mask: u8) { pub fn clear_irqs(&mut self, mask: u8) {
unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(mask)) } unsafe { PIO::PIO.irq().write(|w| w.set_irq(mask)) }
} }
fn force_irq(&mut self, irq_no: usize) { pub fn force_irq(&mut self, irq_no: usize) {
assert!(irq_no < 8); assert!(irq_no < 8);
unsafe { Self::Pio::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) }
} }
fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
unsafe { unsafe {
Self::Pio::PIO // this can interfere with per-pin bypass functions. splitting the
.input_sync_bypass() // modification is going to be fine since nothing that relies on
.modify(|w| *w = (*w & !mask) | (bypass & mask)); // it can reasonably run before we finish.
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
} }
} }
fn get_input_sync_bypass(&self) -> u32 { pub fn get_input_sync_bypass(&self) -> u32 {
unsafe { Self::Pio::PIO.input_sync_bypass().read() } unsafe { PIO::PIO.input_sync_bypass().read() }
} }
fn make_pio_pin(&self, pin: impl Pin) -> PioPin<Self::Pio> { pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin<PIO> {
unsafe { unsafe {
pin.io().ctrl().write(|w| { pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
w.set_funcsel(
if Self::Pio::PIO_NO == 1 {
pac::io::vals::Gpio0ctrlFuncsel::PIO1_0
} else {
// PIO == 0
pac::io::vals::Gpio0ctrlFuncsel::PIO0_0
}
.0,
);
});
} }
PioPin { PioPin {
pin_bank: pin.pin_bank(), pin_bank: pin.pin_bank(),
@ -976,112 +879,63 @@ pub trait PioCommon: sealed::PioCommon + Sized {
} }
} }
// Identifies a specific state machine inside a PIO device pub struct Pio<'d, PIO: PioInstance> {
pub struct SmInstanceBase<const SM_NO: u8> {} pub common: PioCommon<'d, PIO>,
pub sm0: PioStateMachineInstance<'d, PIO, 0>,
pub trait SmInstance: sealed::SmInstance + Unpin {} pub sm1: PioStateMachineInstance<'d, PIO, 1>,
pub sm2: PioStateMachineInstance<'d, PIO, 2>,
impl<const SM_NO: u8> sealed::SmInstance for SmInstanceBase<SM_NO> { pub sm3: PioStateMachineInstance<'d, PIO, 3>,
const SM_NO: u8 = SM_NO;
}
impl<const SM_NO: u8> SmInstance for SmInstanceBase<SM_NO> {}
pub trait PioPeripheral: sealed::PioPeripheral + Sized {
fn pio(&self) -> u8 {
Self::Pio::PIO_NO
} }
fn split( impl<'d, PIO: PioInstance> Pio<'d, PIO> {
self, pub fn new(_pio: impl Peripheral<P = PIO> + 'd) -> Self {
) -> ( Self {
PioCommonInstance<Self::Pio>, common: PioCommon {
PioStateMachineInstance<Self::Pio, SmInstanceBase<0>>,
PioStateMachineInstance<Self::Pio, SmInstanceBase<1>>,
PioStateMachineInstance<Self::Pio, SmInstanceBase<2>>,
PioStateMachineInstance<Self::Pio, SmInstanceBase<3>>,
) {
(
PioCommonInstance {
instructions_used: 0, instructions_used: 0,
pio: PhantomData::default(), pio: PhantomData,
}, },
PioStateMachineInstance { sm0: PioStateMachineInstance { pio: PhantomData },
sm: PhantomData::default(), sm1: PioStateMachineInstance { pio: PhantomData },
pio: PhantomData::default(), sm2: PioStateMachineInstance { pio: PhantomData },
}, sm3: PioStateMachineInstance { pio: PhantomData },
PioStateMachineInstance { }
sm: PhantomData::default(), }
pio: PhantomData::default(), }
},
PioStateMachineInstance { pub trait PioInstance: sealed::PioInstance + Sized + Unpin {
sm: PhantomData::default(), fn pio(&self) -> u8 {
pio: PhantomData::default(), Self::PIO_NO
},
PioStateMachineInstance {
sm: PhantomData::default(),
pio: PhantomData::default(),
},
)
} }
} }
mod sealed { mod sealed {
pub trait PioStateMachine {
type Pio: super::PioInstance;
const SM: usize;
#[inline(always)]
fn this_sm() -> crate::pac::pio::StateMachine {
Self::Pio::PIO.sm(Self::SM as usize)
}
}
pub trait PioInstance { pub trait PioInstance {
const PIO_NO: u8; const PIO_NO: u8;
const PIO: &'static crate::pac::pio::Pio; const PIO: &'static crate::pac::pio::Pio;
} const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel;
pub trait PioCommon {
type Pio: super::PioInstance;
}
pub trait PioStateMachine {
type Pio: super::PioInstance;
type Sm: super::SmInstance;
}
pub trait SmInstance {
const SM_NO: u8;
}
pub trait PioPeripheral {
type Pio: super::PioInstance;
} }
} }
// Identifies a specific PIO device macro_rules! impl_pio {
pub struct PioInstanceBase<const PIO_NO: u8> {} ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => {
impl sealed::PioInstance for peripherals::$name {
pub trait PioInstance: sealed::PioInstance + Unpin {} const PIO_NO: u8 = $pio;
const PIO: &'static pac::pio::Pio = &pac::$pac;
impl sealed::PioInstance for PioInstanceBase<0> { const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel;
const PIO_NO: u8 = 0;
const PIO: &'static pac::pio::Pio = &pac::PIO0;
} }
impl PioInstance for PioInstanceBase<0> {} impl PioInstance for peripherals::$name {}
impl sealed::PioInstance for PioInstanceBase<1> {
const PIO_NO: u8 = 1;
const PIO: &'static pac::pio::Pio = &pac::PIO1;
}
impl PioInstance for PioInstanceBase<1> {}
pub type Pio0 = PioInstanceBase<0>;
pub type Pio1 = PioInstanceBase<1>;
pub type Sm0 = SmInstanceBase<0>;
pub type Sm1 = SmInstanceBase<1>;
pub type Sm2 = SmInstanceBase<2>;
pub type Sm3 = SmInstanceBase<3>;
macro_rules! impl_pio_sm {
($name:ident, $pio:expr) => {
impl sealed::PioPeripheral for peripherals::$name {
type Pio = PioInstanceBase<$pio>;
}
impl PioPeripheral for peripherals::$name {}
}; };
} }
impl_pio_sm!(PIO0, 0); impl_pio!(PIO0, 0, PIO0, PIO0_0);
impl_pio_sm!(PIO1, 1); impl_pio!(PIO1, 1, PIO1, PIO1_0);

View File

@ -874,7 +874,6 @@ mod sealed {
pub trait Instance { pub trait Instance {
const TX_DREQ: u8; const TX_DREQ: u8;
const RX_DREQ: u8; const RX_DREQ: u8;
const ID: usize;
type Interrupt: crate::interrupt::Interrupt; type Interrupt: crate::interrupt::Interrupt;
@ -909,11 +908,10 @@ impl_mode!(Async);
pub trait Instance: sealed::Instance {} pub trait Instance: sealed::Instance {}
macro_rules! impl_instance { macro_rules! impl_instance {
($inst:ident, $irq:ident, $id:expr, $tx_dreq:expr, $rx_dreq:expr) => { ($inst:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => {
impl sealed::Instance for peripherals::$inst { impl sealed::Instance for peripherals::$inst {
const TX_DREQ: u8 = $tx_dreq; const TX_DREQ: u8 = $tx_dreq;
const RX_DREQ: u8 = $rx_dreq; const RX_DREQ: u8 = $rx_dreq;
const ID: usize = $id;
type Interrupt = crate::interrupt::$irq; type Interrupt = crate::interrupt::$irq;
@ -939,8 +937,8 @@ macro_rules! impl_instance {
}; };
} }
impl_instance!(UART0, UART0_IRQ, 0, 20, 21); impl_instance!(UART0, UART0_IRQ, 20, 21);
impl_instance!(UART1, UART1_IRQ, 1, 22, 23); impl_instance!(UART1, UART1_IRQ, 22, 23);
pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {} pub trait TxPin<T: Instance>: sealed::TxPin<T> + crate::gpio::Pin {}
pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {} pub trait RxPin<T: Instance>: sealed::RxPin<T> + crate::gpio::Pin {}

View File

@ -58,7 +58,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"
stm32-metapac = "6" stm32-metapac = "7"
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { version = "6", default-features = false, features = ["metadata"]} stm32-metapac = { version = "7", default-features = false, features = ["metadata"]}
[features] [features]
default = ["stm32-metapac/rt"] default = ["stm32-metapac/rt"]

View File

@ -84,7 +84,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config) Self::new_inner(peri, irq, rx, tx, tx_buffer, rx_buffer, config)
} }
#[cfg(not(usart_v1))] #[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de( pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
irq: impl Peripheral<P = T::Interrupt> + 'd, irq: impl Peripheral<P = T::Interrupt> + 'd,
@ -133,7 +133,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
tx.set_as_af(tx.af_num(), AFType::OutputPushPull); tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
} }
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true); configure(r, &config, T::frequency(), T::KIND, true, true);
unsafe { unsafe {
r.cr1().modify(|w| { r.cr1().modify(|w| {

View File

@ -12,10 +12,11 @@ use futures::future::{select, Either};
use crate::dma::{NoDma, Transfer}; use crate::dma::{NoDma, Transfer};
use crate::gpio::sealed::AFType; use crate::gpio::sealed::AFType;
#[cfg(any(lpuart_v1, lpuart_v2))] #[cfg(not(any(usart_v1, usart_v2)))]
use crate::pac::lpuart::{regs, vals, Lpuart as Regs}; use crate::pac::usart::Lpuart as Regs;
#[cfg(not(any(lpuart_v1, lpuart_v2)))] #[cfg(any(usart_v1, usart_v2))]
use crate::pac::usart::{regs, vals, Usart as Regs}; use crate::pac::usart::Usart as Regs;
use crate::pac::usart::{regs, vals};
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
@ -159,7 +160,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
tx.set_as_af(tx.af_num(), AFType::OutputPushPull); tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
} }
configure(r, &config, T::frequency(), T::MULTIPLIER, false, true); configure(r, &config, T::frequency(), T::KIND, false, true);
// create state once! // create state once!
let _s = T::state(); let _s = T::state();
@ -261,7 +262,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
rx.set_as_af(rx.af_num(), AFType::Input); rx.set_as_af(rx.af_num(), AFType::Input);
} }
configure(r, &config, T::frequency(), T::MULTIPLIER, true, false); configure(r, &config, T::frequency(), T::KIND, true, false);
irq.set_handler(Self::on_interrupt); irq.set_handler(Self::on_interrupt);
irq.unpend(); irq.unpend();
@ -653,7 +654,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config) Self::new_inner(peri, rx, tx, irq, tx_dma, rx_dma, config)
} }
#[cfg(not(usart_v1))] #[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de( pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -696,7 +697,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
tx.set_as_af(tx.af_num(), AFType::OutputPushPull); tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
} }
configure(r, &config, T::frequency(), T::MULTIPLIER, true, true); configure(r, &config, T::frequency(), T::KIND, true, true);
irq.set_handler(UartRx::<T, RxDma>::on_interrupt); irq.set_handler(UartRx::<T, RxDma>::on_interrupt);
irq.unpend(); irq.unpend();
@ -763,16 +764,74 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
} }
} }
fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable_rx: bool, enable_tx: bool) { fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: bool, enable_tx: bool) {
if !enable_rx && !enable_tx { if !enable_rx && !enable_tx {
panic!("USART: At least one of RX or TX should be enabled"); panic!("USART: At least one of RX or TX should be enabled");
} }
// TODO: better calculation, including error checking and OVER8 if possible. #[cfg(not(usart_v4))]
let div = (pclk_freq.0 + (config.baudrate / 2)) / config.baudrate * multiplier; static DIVS: [(u16, ()); 1] = [(1, ())];
#[cfg(usart_v4)]
static DIVS: [(u16, vals::Presc); 12] = [
(1, vals::Presc::DIV1),
(2, vals::Presc::DIV2),
(4, vals::Presc::DIV4),
(6, vals::Presc::DIV6),
(8, vals::Presc::DIV8),
(10, vals::Presc::DIV10),
(12, vals::Presc::DIV12),
(16, vals::Presc::DIV16),
(32, vals::Presc::DIV32),
(64, vals::Presc::DIV64),
(128, vals::Presc::DIV128),
(256, vals::Presc::DIV256),
];
let (mul, brr_min, brr_max) = match kind {
#[cfg(any(usart_v3, usart_v4))]
Kind::Lpuart => (256, 0x300, 0x10_0000),
Kind::Uart => (1, 0x10, 0x1_0000),
};
#[cfg(not(usart_v1))]
let mut over8 = false;
let mut found = false;
for &(presc, _presc_val) in &DIVS {
let denom = (config.baudrate * presc as u32) as u64;
let div = (pclk_freq.0 as u64 * mul + (denom / 2)) / denom;
trace!("USART: presc={} div={:08x}", presc, div);
if div < brr_min {
#[cfg(not(usart_v1))]
if div * 2 >= brr_min && kind == Kind::Uart && !cfg!(usart_v1) {
over8 = true;
let div = div as u32;
unsafe {
r.brr().write_value(regs::Brr(((div << 1) & !0xF) | (div & 0x07)));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
}
found = true;
break;
}
panic!("USART: baudrate too high");
}
if div < brr_max {
unsafe {
r.brr().write_value(regs::Brr(div as u32));
#[cfg(usart_v4)]
r.presc().write(|w| w.set_prescaler(_presc_val));
}
found = true;
break;
}
}
assert!(found, "USART: baudrate too low");
unsafe { unsafe {
r.brr().write_value(regs::Brr(div));
r.cr2().write(|w| { r.cr2().write(|w| {
w.set_stop(match config.stop_bits { w.set_stop(match config.stop_bits {
StopBits::STOP0P5 => vals::Stop::STOP0P5, StopBits::STOP0P5 => vals::Stop::STOP0P5,
@ -801,6 +860,8 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, multiplier: u32, enable
Parity::ParityEven => vals::Ps::EVEN, Parity::ParityEven => vals::Ps::EVEN,
_ => vals::Ps::EVEN, _ => vals::Ps::EVEN,
}); });
#[cfg(not(usart_v1))]
w.set_over8(vals::Over8(over8 as _));
}); });
} }
} }
@ -986,43 +1047,45 @@ mod rx_ringbuffered;
#[cfg(not(gpdma))] #[cfg(not(gpdma))]
pub use rx_ringbuffered::RingBufferedUartRx; pub use rx_ringbuffered::RingBufferedUartRx;
#[cfg(usart_v1)] use self::sealed::Kind;
#[cfg(any(usart_v1, usart_v2))]
fn tdr(r: crate::pac::usart::Usart) -> *mut u8 { fn tdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.dr().ptr() as _ r.dr().ptr() as _
} }
#[cfg(usart_v1)] #[cfg(any(usart_v1, usart_v2))]
fn rdr(r: crate::pac::usart::Usart) -> *mut u8 { fn rdr(r: crate::pac::usart::Usart) -> *mut u8 {
r.dr().ptr() as _ r.dr().ptr() as _
} }
#[cfg(usart_v1)] #[cfg(any(usart_v1, usart_v2))]
fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> { fn sr(r: crate::pac::usart::Usart) -> crate::pac::common::Reg<regs::Sr, crate::pac::common::RW> {
r.sr() r.sr()
} }
#[cfg(usart_v1)] #[cfg(any(usart_v1, usart_v2))]
#[allow(unused)] #[allow(unused)]
unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) { unsafe fn clear_interrupt_flags(_r: Regs, _sr: regs::Sr) {
// On v1 the flags are cleared implicitly by reads and writes to DR. // On v1 the flags are cleared implicitly by reads and writes to DR.
} }
#[cfg(usart_v2)] #[cfg(any(usart_v3, usart_v4))]
fn tdr(r: Regs) -> *mut u8 { fn tdr(r: Regs) -> *mut u8 {
r.tdr().ptr() as _ r.tdr().ptr() as _
} }
#[cfg(usart_v2)] #[cfg(any(usart_v3, usart_v4))]
fn rdr(r: Regs) -> *mut u8 { fn rdr(r: Regs) -> *mut u8 {
r.rdr().ptr() as _ r.rdr().ptr() as _
} }
#[cfg(usart_v2)] #[cfg(any(usart_v3, usart_v4))]
fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> { fn sr(r: Regs) -> crate::pac::common::Reg<regs::Isr, crate::pac::common::R> {
r.isr() r.isr()
} }
#[cfg(usart_v2)] #[cfg(any(usart_v3, usart_v4))]
#[allow(unused)] #[allow(unused)]
unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) { unsafe fn clear_interrupt_flags(r: Regs, sr: regs::Isr) {
r.icr().write(|w| *w = regs::Icr(sr.0)); r.icr().write(|w| *w = regs::Icr(sr.0));
@ -1033,6 +1096,13 @@ pub(crate) mod sealed {
use super::*; use super::*;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Kind {
Uart,
#[cfg(any(usart_v3, usart_v4))]
Lpuart,
}
pub struct State { pub struct State {
pub rx_waker: AtomicWaker, pub rx_waker: AtomicWaker,
pub tx_waker: AtomicWaker, pub tx_waker: AtomicWaker,
@ -1048,7 +1118,7 @@ pub(crate) mod sealed {
} }
pub trait BasicInstance: crate::rcc::RccPeripheral { pub trait BasicInstance: crate::rcc::RccPeripheral {
const MULTIPLIER: u32; const KIND: Kind;
type Interrupt: crate::interrupt::Interrupt; type Interrupt: crate::interrupt::Interrupt;
fn regs() -> Regs; fn regs() -> Regs;
@ -1077,10 +1147,10 @@ pin_trait!(DePin, BasicInstance);
dma_trait!(TxDma, BasicInstance); dma_trait!(TxDma, BasicInstance);
dma_trait!(RxDma, BasicInstance); dma_trait!(RxDma, BasicInstance);
macro_rules! impl_lpuart { macro_rules! impl_usart {
($inst:ident, $irq:ident, $mul:expr) => { ($inst:ident, $irq:ident, $kind:expr) => {
impl sealed::BasicInstance for crate::peripherals::$inst { impl sealed::BasicInstance for crate::peripherals::$inst {
const MULTIPLIER: u32 = $mul; const KIND: Kind = $kind;
type Interrupt = crate::interrupt::$irq; type Interrupt = crate::interrupt::$irq;
fn regs() -> Regs { fn regs() -> Regs {
@ -1104,21 +1174,19 @@ macro_rules! impl_lpuart {
} }
foreach_interrupt!( foreach_interrupt!(
($inst:ident, lpuart, $block:ident, $signal_name:ident, $irq:ident) => { ($inst:ident, usart, LPUART, $signal_name:ident, $irq:ident) => {
impl_lpuart!($inst, $irq, 256); impl_usart!($inst, $irq, Kind::Lpuart);
}; };
($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => { ($inst:ident, usart, $block:ident, $signal_name:ident, $irq:ident) => {
impl_lpuart!($inst, $irq, 1); impl_usart!($inst, $irq, Kind::Uart);
impl sealed::FullInstance for peripherals::$inst { impl sealed::FullInstance for peripherals::$inst {
fn regs_uart() -> crate::pac::usart::Usart { fn regs_uart() -> crate::pac::usart::Usart {
crate::pac::$inst crate::pac::$inst
} }
} }
impl FullInstance for peripherals::$inst { impl FullInstance for peripherals::$inst {}
}
}; };
); );

View File

@ -4,15 +4,13 @@
use defmt::info; use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio::{AnyPin, Pin}; use embassy_rp::gpio::{AnyPin, Pin};
use embassy_rp::pio::{ use embassy_rp::peripherals::PIO0;
Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection};
Sm1, Sm2,
};
use embassy_rp::pio_instr_util; use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm0>, pin: AnyPin) { fn setup_pio_task_sm0(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 0>, pin: AnyPin) {
// Setup sm0 // Setup sm0
// Send data serially to pin // Send data serially to pin
@ -40,7 +38,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
} }
#[embassy_executor::task] #[embassy_executor::task]
async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) { async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) {
sm.set_enable(true); sm.set_enable(true);
let mut v = 0x0f0caffa; let mut v = 0x0f0caffa;
@ -51,7 +49,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<Pio0, Sm0>) {
} }
} }
fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm1>) { fn setup_pio_task_sm1(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 1>) {
// Setupm sm1 // Setupm sm1
// Read 0b10101 repeatedly until ISR is full // Read 0b10101 repeatedly until ISR is full
@ -70,7 +68,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
} }
#[embassy_executor::task] #[embassy_executor::task]
async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) { async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) {
sm.set_enable(true); sm.set_enable(true);
loop { loop {
let rx = sm.wait_pull().await; let rx = sm.wait_pull().await;
@ -78,7 +76,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<Pio0, Sm1>) {
} }
} }
fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachineInstance<Pio0, Sm2>) { fn setup_pio_task_sm2(pio: &mut PioCommon<PIO0>, sm: &mut PioStateMachineInstance<PIO0, 2>) {
// Setup sm2 // Setup sm2
// Repeatedly trigger IRQ 3 // Repeatedly trigger IRQ 3
@ -102,7 +100,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance<Pio0>, sm: &mut PioStateMachin
} }
#[embassy_executor::task] #[embassy_executor::task]
async fn pio_task_sm2(mut sm: PioStateMachineInstance<Pio0, Sm2>) { async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, 2>) {
sm.set_enable(true); sm.set_enable(true);
loop { loop {
sm.wait_irq(3).await; sm.wait_irq(3).await;
@ -115,11 +113,17 @@ async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let pio = p.PIO0; let pio = p.PIO0;
let (mut pio0, mut sm0, mut sm1, mut sm2, ..) = pio.split(); let Pio {
mut common,
mut sm0,
mut sm1,
mut sm2,
..
} = Pio::new(pio);
setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade()); setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0.degrade());
setup_pio_task_sm1(&mut pio0, &mut sm1); setup_pio_task_sm1(&mut common, &mut sm1);
setup_pio_task_sm2(&mut pio0, &mut sm2); setup_pio_task_sm2(&mut common, &mut sm2);
spawner.spawn(pio_task_sm0(sm0)).unwrap(); spawner.spawn(pio_task_sm0(sm0)).unwrap();
spawner.spawn(pio_task_sm1(sm1)).unwrap(); spawner.spawn(pio_task_sm1(sm1)).unwrap();
spawner.spawn(pio_task_sm2(sm2)).unwrap(); spawner.spawn(pio_task_sm2(sm2)).unwrap();

View File

@ -4,7 +4,7 @@
use defmt::info; use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_futures::join::join; use embassy_futures::join::join;
use embassy_rp::pio::{PioCommon, PioPeripheral, PioStateMachine, ShiftDirection}; use embassy_rp::pio::{Pio, PioStateMachine, ShiftDirection};
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
use embassy_rp::{pio_instr_util, Peripheral}; use embassy_rp::{pio_instr_util, Peripheral};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -19,7 +19,11 @@ fn swap_nibbles(v: u32) -> u32 {
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let pio = p.PIO0; let pio = p.PIO0;
let (mut pio0, mut sm, ..) = pio.split(); let Pio {
mut common,
sm0: mut sm,
..
} = Pio::new(pio);
let prg = pio_proc::pio_asm!( let prg = pio_proc::pio_asm!(
".origin 0", ".origin 0",
@ -34,7 +38,7 @@ async fn main(_spawner: Spawner) {
); );
let relocated = RelocatedProgram::new(&prg.program); let relocated = RelocatedProgram::new(&prg.program);
pio0.write_instr(relocated.origin() as usize, relocated.code()); common.write_instr(relocated.origin() as usize, relocated.code());
pio_instr_util::exec_jmp(&mut sm, relocated.origin()); pio_instr_util::exec_jmp(&mut sm, relocated.origin());
sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32);
let pio::Wrap { source, target } = relocated.wrap(); let pio::Wrap { source, target } = relocated.wrap();

View File

@ -0,0 +1,243 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Spawner;
use embassy_rp::dma::{AnyChannel, Channel};
use embassy_rp::gpio::Pin;
use embassy_rp::peripherals::PIO0;
use embassy_rp::pio::{FifoJoin, Pio, PioStateMachine, PioStateMachineInstance, ShiftDirection};
use embassy_rp::pwm::{Config, Pwm};
use embassy_rp::relocate::RelocatedProgram;
use embassy_rp::{into_ref, Peripheral, PeripheralRef};
use embassy_time::{Duration, Instant, Timer};
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
// this test assumes a 2x16 HD44780 display attached as follow:
// rs = PIN0
// rw = PIN1
// e = PIN2
// db4 = PIN3
// db5 = PIN4
// db6 = PIN5
// db7 = PIN6
// additionally a pwm signal for a bias voltage charge pump is provided on pin 15,
// allowing direct connection of the display to the RP2040 without level shifters.
let p = embassy_rp::init(Default::default());
let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, {
let mut c = Config::default();
c.divider = 125.into();
c.top = 100;
c.compare_b = 50;
c
});
let mut hd = HD44780::new(
p.PIO0, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6,
)
.await;
loop {
struct Buf<const N: usize>([u8; N], usize);
impl<const N: usize> Write for Buf<N> {
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
for b in s.as_bytes() {
if self.1 >= N {
return Err(core::fmt::Error);
}
self.0[self.1] = *b;
self.1 += 1;
}
Ok(())
}
}
let mut buf = Buf([0; 16], 0);
write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap();
hd.add_line(&buf.0[0..buf.1]).await;
Timer::after(Duration::from_secs(1)).await;
}
}
pub struct HD44780<'l> {
dma: PeripheralRef<'l, AnyChannel>,
sm: PioStateMachineInstance<'l, PIO0, 0>,
buf: [u8; 40],
}
impl<'l> HD44780<'l> {
pub async fn new(
pio: impl Peripheral<P = PIO0> + 'l,
dma: impl Peripheral<P = impl Channel> + 'l,
rs: impl Pin,
rw: impl Pin,
e: impl Pin,
db4: impl Pin,
db5: impl Pin,
db6: impl Pin,
db7: impl Pin,
) -> HD44780<'l> {
into_ref!(dma);
let db7pin = db7.pin();
let Pio {
mut common, mut sm0, ..
} = Pio::new(pio);
// takes command words (<wait:24> <command:4> <0:4>)
let prg = pio_proc::pio_asm!(
r#"
.side_set 1 opt
loop:
out x, 24
delay:
jmp x--, delay
out pins, 4 side 1
out null, 4 side 0
jmp !osre, loop
irq 0
"#,
);
let rs = common.make_pio_pin(rs);
let rw = common.make_pio_pin(rw);
let e = common.make_pio_pin(e);
let db4 = common.make_pio_pin(db4);
let db5 = common.make_pio_pin(db5);
let db6 = common.make_pio_pin(db6);
let db7 = common.make_pio_pin(db7);
sm0.set_set_pins(&[&rs, &rw]);
embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11);
sm0.set_set_pins(&[&e]);
embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b1);
sm0.set_set_pins(&[&db4, &db5, &db6, &db7]);
embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11111);
let relocated = RelocatedProgram::new(&prg.program);
common.write_instr(relocated.origin() as usize, relocated.code());
embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin());
sm0.set_clkdiv(125 * 256);
let pio::Wrap { source, target } = relocated.wrap();
sm0.set_wrap(source, target);
sm0.set_side_enable(true);
sm0.set_out_pins(&[&db4, &db5, &db6, &db7]);
sm0.set_sideset_base_pin(&e);
sm0.set_sideset_count(2);
sm0.set_out_shift_dir(ShiftDirection::Left);
sm0.set_fifo_join(FifoJoin::TxOnly);
sm0.set_autopull(true);
sm0.set_pull_threshold(32);
sm0.set_enable(true);
// init to 8 bit thrice
sm0.push_tx((50000 << 8) | 0x30);
sm0.push_tx((5000 << 8) | 0x30);
sm0.push_tx((200 << 8) | 0x30);
// init 4 bit
sm0.push_tx((200 << 8) | 0x20);
// set font and lines
sm0.push_tx((50 << 8) | 0x20);
sm0.push_tx(0b1100_0000);
sm0.wait_irq(0).await;
sm0.set_enable(false);
// takes command sequences (<rs:1> <count:7>, data...)
// many side sets are only there to free up a delay bit!
let prg = pio_proc::pio_asm!(
r#"
.origin 7
.side_set 1
.wrap_target
pull side 0
out x 1 side 0 ; !rs
out y 7 side 0 ; #data - 1
; rs/rw to e: >= 60ns
; e high time: >= 500ns
; e low time: >= 500ns
; read data valid after e falling: ~5ns
; write data hold after e falling: ~10ns
loop:
pull side 0
jmp !x data side 0
command:
set pins 0b00 side 0
jmp shift side 0
data:
set pins 0b01 side 0
shift:
out pins 4 side 1 [9]
nop side 0 [9]
out pins 4 side 1 [9]
mov osr null side 0 [7]
out pindirs 4 side 0
set pins 0b10 side 0
busy:
nop side 1 [9]
jmp pin more side 0 [9]
mov osr ~osr side 1 [9]
nop side 0 [4]
out pindirs 4 side 0
jmp y-- loop side 0
.wrap
more:
nop side 1 [9]
jmp busy side 0 [9]
"#
);
let relocated = RelocatedProgram::new(&prg.program);
common.write_instr(relocated.origin() as usize, relocated.code());
embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin());
let pio::Wrap { source, target } = relocated.wrap();
sm0.set_clkdiv(8 * 256); // ~64ns/insn
sm0.set_side_enable(false);
sm0.set_jmp_pin(db7pin);
sm0.set_wrap(source, target);
sm0.set_set_pins(&[&rs, &rw]);
sm0.set_out_pins(&[&db4, &db5, &db6, &db7]);
sm0.set_sideset_base_pin(&e);
sm0.set_sideset_count(1);
sm0.set_out_shift_dir(ShiftDirection::Left);
sm0.set_fifo_join(FifoJoin::TxOnly);
sm0.set_enable(true);
// display on and cursor on and blinking, reset display
sm0.dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
Self {
dma: dma.map_into(),
sm: sm0,
buf: [0x20; 40],
}
}
pub async fn add_line(&mut self, s: &[u8]) {
// move cursor to 0:0, prepare 16 characters
self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]);
// move line 2 up
self.buf.copy_within(22..38, 3);
// move cursor to 1:0, prepare 16 characters
self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]);
// file line 2 with spaces
self.buf[22..38].fill(0x20);
// copy input line
let len = s.len().min(16);
self.buf[22..22 + len].copy_from_slice(&s[0..len]);
// set cursor to 1:15
self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
self.sm.dma_push(self.dma.reborrow(), &self.buf).await;
}
}

View File

@ -6,20 +6,19 @@ use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio::{self, Pin}; use embassy_rp::gpio::{self, Pin};
use embassy_rp::pio::{ use embassy_rp::pio::{
FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection,
ShiftDirection, SmInstance,
}; };
use embassy_rp::pio_instr_util; use embassy_rp::pio_instr_util;
use embassy_rp::relocate::RelocatedProgram; use embassy_rp::relocate::RelocatedProgram;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use smart_leds::RGB8; use smart_leds::RGB8;
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
pub struct Ws2812<P: PioInstance, S: SmInstance> { pub struct Ws2812<'d, P: PioInstance, const S: usize> {
sm: PioStateMachineInstance<P, S>, sm: PioStateMachineInstance<'d, P, S>,
} }
impl<P: PioInstance, S: SmInstance> Ws2812<P, S> { impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> {
pub fn new(mut pio: PioCommonInstance<P>, mut sm: PioStateMachineInstance<P, S>, pin: gpio::AnyPin) -> Self { pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self {
// Setup sm0 // Setup sm0
// prepare the PIO program // prepare the PIO program
@ -116,7 +115,7 @@ async fn main(_spawner: Spawner) {
info!("Start"); info!("Start");
let p = embassy_rp::init(Default::default()); let p = embassy_rp::init(Default::default());
let (pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split(); let Pio { common, sm0, .. } = Pio::new(p.PIO0);
// This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
// feather boards for the 2040 both have one built in. // feather boards for the 2040 both have one built in.
@ -125,7 +124,7 @@ async fn main(_spawner: Spawner) {
// For the thing plus, use pin 8 // For the thing plus, use pin 8
// For the feather, use pin 16 // For the feather, use pin 16
let mut ws2812 = Ws2812::new(pio0, sm0, p.PIN_8.degrade()); let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8.degrade());
// Loop forever making RGB values and pushing them out to the WS2812. // Loop forever making RGB values and pushing them out to the WS2812.
loop { loop {

View File

@ -0,0 +1,63 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::{info, unwrap};
use embassy_executor::Executor;
use embassy_executor::_export::StaticCell;
use embassy_rp::gpio::{Input, Level, Output, Pull};
use embassy_rp::multicore::{spawn_core1, Stack};
use embassy_rp::peripherals::{PIN_0, PIN_1};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use {defmt_rtt as _, panic_probe as _};
static mut CORE1_STACK: Stack<1024> = Stack::new();
static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
static CHANNEL0: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
static CHANNEL1: Channel<CriticalSectionRawMutex, (), 1> = Channel::new();
#[cortex_m_rt::entry]
fn main() -> ! {
let p = embassy_rp::init(Default::default());
spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
let executor1 = EXECUTOR1.init(Executor::new());
executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(p.PIN_1))));
});
let executor0 = EXECUTOR0.init(Executor::new());
executor0.run(|spawner| unwrap!(spawner.spawn(core0_task(p.PIN_0))));
}
#[embassy_executor::task]
async fn core0_task(p: PIN_0) {
info!("CORE0 is running");
let mut pin = Output::new(p, Level::Low);
CHANNEL0.send(()).await;
CHANNEL1.recv().await;
pin.set_high();
CHANNEL1.recv().await;
info!("Test OK");
cortex_m::asm::bkpt();
}
#[embassy_executor::task]
async fn core1_task(p: PIN_1) {
info!("CORE1 is running");
CHANNEL0.recv().await;
let mut pin = Input::new(p, Pull::Down);
let wait = pin.wait_for_rising_edge();
CHANNEL1.send(()).await;
wait.await;
CHANNEL1.send(()).await;
}

View File

@ -53,10 +53,6 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0); let (mut tx, mut rx, mut uart) = (p.PIN_0, p.PIN_1, p.UART0);
let mut irq = interrupt::take!(UART0_IRQ); let mut irq = interrupt::take!(UART0_IRQ);
// TODO
// nuclear error reporting. just abort the entire transfer and invalidate the
// dma buffer, buffered buffer, fifo etc.
// We can't send too many bytes, they have to fit in the FIFO. // We can't send too many bytes, they have to fit in the FIFO.
// This is because we aren't sending+receiving at the same time. // This is because we aren't sending+receiving at the same time.
{ {

View File

@ -3,6 +3,7 @@ edition = "2021"
name = "embassy-stm32-tests" name = "embassy-stm32-tests"
version = "0.1.0" version = "0.1.0"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
autobins = false
[features] [features]
stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill

View File

@ -6,15 +6,16 @@ fn main() -> Result<(), Box<dyn Error>> {
let out = PathBuf::from(env::var("OUT_DIR").unwrap()); let out = PathBuf::from(env::var("OUT_DIR").unwrap());
fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap(); fs::write(out.join("link_ram.x"), include_bytes!("link_ram.x")).unwrap();
println!("cargo:rustc-link-search={}", out.display()); println!("cargo:rustc-link-search={}", out.display());
println!("cargo:rerun-if-changed=link_ram.x");
println!("cargo:rustc-link-arg-bins=--nmagic"); println!("cargo:rustc-link-arg-bins=--nmagic");
// too little RAM to run from RAM. // too little RAM to run from RAM.
#[cfg(any(feature = "stm32c031c6"))] if cfg!(any(feature = "stm32f103c8", feature = "stm32c031c6")) {
println!("cargo:rustc-link-arg-bins=-Tlink.x"); println!("cargo:rustc-link-arg-bins=-Tlink.x");
#[cfg(not(any(feature = "stm32c031c6")))] println!("cargo:rerun-if-changed=link.x");
} else {
println!("cargo:rustc-link-arg-bins=-Tlink_ram.x"); println!("cargo:rustc-link-arg-bins=-Tlink_ram.x");
println!("cargo:rerun-if-changed=link_ram.x");
}
println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); println!("cargo:rustc-link-arg-bins=-Tdefmt.x");

View File

@ -35,7 +35,6 @@ async fn main(_spawner: Spawner) {
#[cfg(feature = "stm32c031c6")] #[cfg(feature = "stm32c031c6")]
let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6); let (spi, sck, mosi, miso) = (p.SPI1, p.PA5, p.PA7, p.PA6);
info!("asdfa;");
let mut spi = Spi::new( let mut spi = Spi::new(
spi, spi,
sck, // Arduino D13 sck, // Arduino D13

View File

@ -9,6 +9,7 @@ use embassy_executor::Spawner;
use embassy_stm32::dma::NoDma; use embassy_stm32::dma::NoDma;
use embassy_stm32::interrupt; use embassy_stm32::interrupt;
use embassy_stm32::usart::{Config, Uart}; use embassy_stm32::usart::{Config, Uart};
use embassy_time::{Duration, Instant};
use example_common::*; use example_common::*;
#[embassy_executor::main] #[embassy_executor::main]
@ -19,26 +20,27 @@ async fn main(_spawner: Spawner) {
// Arduino pins D0 and D1 // Arduino pins D0 and D1
// They're connected together with a 1K resistor. // They're connected together with a 1K resistor.
#[cfg(feature = "stm32f103c8")] #[cfg(feature = "stm32f103c8")]
let (tx, rx, usart, irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1)); let (mut tx, mut rx, mut usart, mut irq) = (p.PA9, p.PA10, p.USART1, interrupt::take!(USART1));
#[cfg(feature = "stm32g491re")] #[cfg(feature = "stm32g491re")]
let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
#[cfg(feature = "stm32g071rb")] #[cfg(feature = "stm32g071rb")]
let (tx, rx, usart, irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1)); let (mut tx, mut rx, mut usart, mut irq) = (p.PC4, p.PC5, p.USART1, interrupt::take!(USART1));
#[cfg(feature = "stm32f429zi")] #[cfg(feature = "stm32f429zi")]
let (tx, rx, usart, irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6)); let (mut tx, mut rx, mut usart, mut irq) = (p.PG14, p.PG9, p.USART6, interrupt::take!(USART6));
#[cfg(feature = "stm32wb55rg")] #[cfg(feature = "stm32wb55rg")]
let (tx, rx, usart, irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1)); let (mut tx, mut rx, mut usart, mut irq) = (p.PA2, p.PA3, p.LPUART1, interrupt::take!(LPUART1));
#[cfg(feature = "stm32h755zi")] #[cfg(feature = "stm32h755zi")]
let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
#[cfg(feature = "stm32u585ai")] #[cfg(feature = "stm32u585ai")]
let (tx, rx, usart, irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3)); let (mut tx, mut rx, mut usart, mut irq) = (p.PD8, p.PD9, p.USART3, interrupt::take!(USART3));
#[cfg(feature = "stm32h563zi")] #[cfg(feature = "stm32h563zi")]
let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1)); let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.LPUART1, interrupt::take!(LPUART1));
#[cfg(feature = "stm32c031c6")] #[cfg(feature = "stm32c031c6")]
let (tx, rx, usart, irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1)); let (mut tx, mut rx, mut usart, mut irq) = (p.PB6, p.PB7, p.USART1, interrupt::take!(USART1));
{
let config = Config::default(); let config = Config::default();
let mut usart = Uart::new(usart, rx, tx, irq, NoDma, NoDma, config); let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config);
// We can't send too many bytes, they have to fit in the FIFO. // We can't send too many bytes, they have to fit in the FIFO.
// This is because we aren't sending+receiving at the same time. // This is because we aren't sending+receiving at the same time.
@ -49,6 +51,45 @@ async fn main(_spawner: Spawner) {
let mut buf = [0; 2]; let mut buf = [0; 2];
usart.blocking_read(&mut buf).unwrap(); usart.blocking_read(&mut buf).unwrap();
assert_eq!(buf, data); assert_eq!(buf, data);
}
// Test that baudrate divider is calculated correctly.
// Do it by comparing the time it takes to send a known number of bytes.
for baudrate in [
300,
9600,
115200,
250_000,
337_934,
#[cfg(not(feature = "stm32f103c8"))]
1_000_000,
#[cfg(not(feature = "stm32f103c8"))]
2_000_000,
] {
info!("testing baudrate {}", baudrate);
let mut config = Config::default();
config.baudrate = baudrate;
let mut usart = Uart::new(&mut usart, &mut rx, &mut tx, &mut irq, NoDma, NoDma, config);
let n = (baudrate as usize / 100).max(64);
let start = Instant::now();
for _ in 0..n {
usart.blocking_write(&[0x00]).unwrap();
}
let dur = Instant::now() - start;
let want_dur = Duration::from_micros(n as u64 * 10 * 1_000_000 / (baudrate as u64));
let fuzz = want_dur / 5;
if dur < want_dur - fuzz || dur > want_dur + fuzz {
defmt::panic!(
"bad duration for baudrate {}: got {:?} want {:?}",
baudrate,
dur,
want_dur
);
}
}
info!("Test OK"); info!("Test OK");
cortex_m::asm::bkpt(); cortex_m::asm::bkpt();

View File

@ -94,6 +94,9 @@ async fn main(_spawner: Spawner) {
let rx_fut = async { let rx_fut = async {
rx.read(&mut rx_buf).await.unwrap(); rx.read(&mut rx_buf).await.unwrap();
}; };
// note: rx needs to be polled first, to workaround this bug:
// https://github.com/embassy-rs/embassy/issues/1426
join(rx_fut, tx_fut).await; join(rx_fut, tx_fut).await;
assert_eq!(tx_buf, rx_buf); assert_eq!(tx_buf, rx_buf);

View File

@ -145,13 +145,16 @@ async fn main(spawner: Spawner) {
#[embassy_executor::task] #[embassy_executor::task]
async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) { async fn transmit_task(mut tx: UartTx<'static, board::Uart, board::TxDma>) {
// workaround https://github.com/embassy-rs/embassy/issues/1426
Timer::after(Duration::from_millis(100) as _).await;
let mut rng = ChaCha8Rng::seed_from_u64(1337); let mut rng = ChaCha8Rng::seed_from_u64(1337);
info!("Starting random transmissions into void..."); info!("Starting random transmissions into void...");
let mut i: u8 = 0; let mut i: u8 = 0;
loop { loop {
let mut buf = [0; 32]; let mut buf = [0; 256];
let len = 1 + (rng.next_u32() as usize % buf.len()); let len = 1 + (rng.next_u32() as usize % buf.len());
for b in &mut buf[..len] { for b in &mut buf[..len] {
*b = i; *b = i;
@ -172,7 +175,7 @@ async fn receive_task(mut rx: RingBufferedUartRx<'static, board::Uart, board::Rx
let mut i = 0; let mut i = 0;
let mut expected = 0; let mut expected = 0;
loop { loop {
let mut buf = [0; 100]; let mut buf = [0; 256];
let max_len = 1 + (rng.next_u32() as usize % buf.len()); let max_len = 1 + (rng.next_u32() as usize % buf.len());
let received = match rx.read(&mut buf[..max_len]).await { let received = match rx.read(&mut buf[..max_len]).await {
Ok(r) => r, Ok(r) => r,

View File

@ -16,5 +16,10 @@ pub fn config() -> Config {
config.rcc.pll1.q_ck = Some(Hertz(100_000_000)); config.rcc.pll1.q_ck = Some(Hertz(100_000_000));
} }
#[cfg(feature = "stm32u585ai")]
{
config.rcc.mux = embassy_stm32::rcc::ClockSrc::MSI(embassy_stm32::rcc::MSIRange::Range48mhz);
}
config config
} }