From a10850a6dacc0672f998069457bf104eb970c746 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 02:27:56 +0200 Subject: [PATCH 1/9] rp/pio: handle all pio irqs in one handler dma does this too, also with 12 bits to check. this decreases code size significantly (increasing speed when the cache is cold), frees up an interrupt handler, and avoids read-modify-write cycles (which makes each processed flag cheaper). due to more iterations per handler invocation the actual runtime of the handler body remains roughly the same (slightly faster at O2, slightly slower at Oz). notably wakers are now kept in one large array indexed by the irq register bit number instead of three different arrays, this allows for machine code-level optimizations of waker lookups. --- embassy-rp/src/pio.rs | 134 ++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 90 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 3c7abea25..e3b6ca97c 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -12,14 +12,29 @@ use crate::dma::{self, Channel, Transfer}; use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::{Drive, Pin, Pull, SlewRate}; use crate::pac::dma::vals::{DataSize, TreqSel}; -use crate::{interrupt, pac, peripherals}; +use crate::{interrupt, pac, peripherals, RegExt}; + +struct Wakers([AtomicWaker; 12]); + +impl Wakers { + #[inline(always)] + fn fifo_in(&self) -> &[AtomicWaker] { + &self.0[0..4] + } + #[inline(always)] + fn fifo_out(&self) -> &[AtomicWaker] { + &self.0[4..8] + } + #[inline(always)] + fn irq(&self) -> &[AtomicWaker] { + &self.0[8..12] + } +} const PIOS: [&pac::pio::Pio; 2] = [&pac::PIO0, &pac::PIO1]; const NEW_AW: AtomicWaker = AtomicWaker::new(); -const PIO_WAKERS_INIT: [AtomicWaker; 4] = [NEW_AW; 4]; -static FIFO_OUT_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2]; -static FIFO_IN_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2]; -static IRQ_WAKERS: [[AtomicWaker; 4]; 2] = [PIO_WAKERS_INIT; 2]; +const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]); +static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2]; pub enum FifoJoin { /// Both TX and RX fifo is enabled @@ -40,83 +55,28 @@ const RXNEMPTY_MASK: u32 = 1 << 0; const TXNFULL_MASK: u32 = 1 << 4; const SMIRQ_MASK: u32 = 1 << 8; -#[interrupt] -unsafe fn PIO0_IRQ_1() { - use crate::pac; - let ints = pac::PIO0.irqs(1).ints().read().0; - let inte = pac::PIO0.irqs(1).inte(); - for i in 0..4 { - // Check RXNEMPTY - if ints & (RXNEMPTY_MASK << i) != 0 { - inte.modify(|m| { - m.0 &= !(RXNEMPTY_MASK << i); - }); - FIFO_IN_WAKERS[0][i].wake(); - } - // Check IRQ flgs - if ints & (SMIRQ_MASK << i) != 0 { - inte.modify(|m| { - m.0 &= !(SMIRQ_MASK << i); - }); - IRQ_WAKERS[0][i].wake(); - } - } -} - -#[interrupt] -unsafe fn PIO1_IRQ_1() { - use crate::pac; - let ints = pac::PIO1.irqs(1).ints().read().0; - let inte = pac::PIO1.irqs(1).inte(); - for i in 0..4 { - // Check all RXNEMPTY - if ints & (RXNEMPTY_MASK << i) != 0 { - inte.modify(|m| { - m.0 &= !(RXNEMPTY_MASK << i); - }); - FIFO_IN_WAKERS[1][i].wake(); - } - // Check IRQ flgs - if ints & (SMIRQ_MASK << i) != 0 { - inte.modify(|m| { - m.0 &= !(SMIRQ_MASK << i); - }); - IRQ_WAKERS[1][i].wake(); - } - } -} - #[interrupt] unsafe fn PIO0_IRQ_0() { use crate::pac; let ints = pac::PIO0.irqs(0).ints().read().0; - let inte = pac::PIO0.irqs(0).inte(); - //debug!("!{:04x}",ints); - // Check all TXNFULL - for i in 0..4 { - if ints & (TXNFULL_MASK << i) != 0 { - inte.modify(|m| { - m.0 &= !(TXNFULL_MASK << i); - }); - FIFO_OUT_WAKERS[0][i].wake(); + for bit in 0..12 { + if ints & (1 << bit) != 0 { + WAKERS[0].0[bit].wake(); } } + pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints); } #[interrupt] unsafe fn PIO1_IRQ_0() { use crate::pac; let ints = pac::PIO1.irqs(0).ints().read().0; - let inte = pac::PIO1.irqs(0).inte(); - // Check all TXNFULL - for i in 0..4 { - if ints & (TXNFULL_MASK << i) != 0 { - inte.modify(|m| { - m.0 &= !(TXNFULL_MASK << i); - }); - FIFO_OUT_WAKERS[1][i].wake(); + for bit in 0..12 { + if ints & (1 << bit) != 0 { + WAKERS[1].0[bit].wake(); } } + pac::PIO1.irqs(0).inte().write_clear(|m| m.0 = ints); } /// Future that waits for TX-FIFO to become writable @@ -131,7 +91,7 @@ impl<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> FifoOutFuture<'a, PIO, S pub fn new(sm: &'a mut SM, value: u32) -> Self { unsafe { critical_section::with(|_| { - let irq = PIO::IrqOut::steal(); + let irq = PIO::Irq::steal(); irq.set_priority(interrupt::Priority::P3); irq.enable(); @@ -153,9 +113,9 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture if self.get_mut().sm.try_push_tx(value) { Poll::Ready(()) } else { - FIFO_OUT_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker()); unsafe { - let irq = PIO::IrqOut::steal(); + let irq = PIO::Irq::steal(); irq.disable(); critical_section::with(|_| { PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { @@ -193,7 +153,7 @@ impl<'a, PIO: PioInstance, SM: PioStateMachine> FifoInFuture<'a, PIO, SM> { pub fn new(sm: &'a mut SM) -> Self { unsafe { critical_section::with(|_| { - let irq = PIO::IrqIn::steal(); + let irq = PIO::Irq::steal(); irq.set_priority(interrupt::Priority::P3); irq.enable(); @@ -213,12 +173,12 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, if let Some(v) = self.sm.try_pull_rx() { Poll::Ready(v) } else { - FIFO_IN_WAKERS[PIO::PIO_NO as usize][SM::Sm::SM_NO as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker()); unsafe { - let irq = PIO::IrqIn::steal(); + let irq = PIO::Irq::steal(); irq.disable(); critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { + PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { m.0 |= RXNEMPTY_MASK << SM::Sm::SM_NO; }); }); @@ -234,7 +194,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S fn drop(&mut self) { unsafe { critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { + PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { m.0 &= !(RXNEMPTY_MASK << SM::Sm::SM_NO); }); }); @@ -253,7 +213,7 @@ impl<'a, PIO: PioInstance> IrqFuture { pub fn new(irq_no: u8) -> Self { unsafe { critical_section::with(|_| { - let irq = PIO::IrqSm::steal(); + let irq = PIO::Irq::steal(); irq.set_priority(interrupt::Priority::P3); irq.enable(); @@ -286,12 +246,12 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { return Poll::Ready(()); } - IRQ_WAKERS[PIO::PIO_NO as usize][self.irq_no as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); unsafe { - let irq = PIO::IrqSm::steal(); + let irq = PIO::Irq::steal(); irq.disable(); critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { + PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { m.0 |= SMIRQ_MASK << self.irq_no; }); }); @@ -305,7 +265,7 @@ impl<'d, PIO: PioInstance> Drop for IrqFuture { fn drop(&mut self) { unsafe { critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(1).inte().modify(|m| { + PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { m.0 &= !(SMIRQ_MASK << self.irq_no); }); }); @@ -1223,23 +1183,17 @@ pub struct PioInstanceBase {} pub trait PioInstance: Unpin { const PIO_NO: u8; - type IrqOut: Interrupt; - type IrqIn: Interrupt; - type IrqSm: Interrupt; + type Irq: Interrupt; } impl PioInstance for PioInstanceBase<0> { const PIO_NO: u8 = 0; - type IrqOut = interrupt::PIO0_IRQ_0; - type IrqIn = interrupt::PIO0_IRQ_1; - type IrqSm = interrupt::PIO0_IRQ_1; + type Irq = interrupt::PIO0_IRQ_0; } impl PioInstance for PioInstanceBase<1> { const PIO_NO: u8 = 1; - type IrqOut = interrupt::PIO1_IRQ_0; - type IrqIn = interrupt::PIO1_IRQ_1; - type IrqSm = interrupt::PIO1_IRQ_1; + type Irq = interrupt::PIO1_IRQ_0; } pub type Pio0 = PioInstanceBase<0>; From f2469776f4f229dff23eb7f0bf59c00290620d9c Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 18:44:02 +0200 Subject: [PATCH 2/9] rp/pio: use atomic accesses, not critical sections atomic accesses are not only faster but also can't conflict with other critical sections. --- embassy-rp/src/pio.rs | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index e3b6ca97c..f0d550d95 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -117,10 +117,8 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture unsafe { let irq = PIO::Irq::steal(); irq.disable(); - critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { - m.0 |= TXNFULL_MASK << SM::Sm::SM_NO; - }); + PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { + m.0 = TXNFULL_MASK << SM::Sm::SM_NO; }); irq.enable(); } @@ -133,10 +131,8 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'d, PIO, SM> { fn drop(&mut self) { unsafe { - critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { - m.0 &= !(TXNFULL_MASK << SM::Sm::SM_NO); - }); + PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_clear(|m| { + m.0 = TXNFULL_MASK << SM::Sm::SM_NO; }); } } @@ -177,10 +173,8 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, unsafe { let irq = PIO::Irq::steal(); irq.disable(); - critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { - m.0 |= RXNEMPTY_MASK << SM::Sm::SM_NO; - }); + PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { + m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; }); irq.enable(); } @@ -193,10 +187,8 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, SM> { fn drop(&mut self) { unsafe { - critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { - m.0 &= !(RXNEMPTY_MASK << SM::Sm::SM_NO); - }); + PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_clear(|m| { + m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; }); } } @@ -250,10 +242,8 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { unsafe { let irq = PIO::Irq::steal(); irq.disable(); - critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { - m.0 |= SMIRQ_MASK << self.irq_no; - }); + PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { + m.0 = SMIRQ_MASK << self.irq_no; }); irq.enable(); } @@ -264,10 +254,8 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { impl<'d, PIO: PioInstance> Drop for IrqFuture { fn drop(&mut self) { unsafe { - critical_section::with(|_| { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().modify(|m| { - m.0 &= !(SMIRQ_MASK << self.irq_no); - }); + PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_clear(|m| { + m.0 = SMIRQ_MASK << self.irq_no; }); } } From a9074fd09bb2fa6265808f32e5cf303285fc0ec6 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 18:47:51 +0200 Subject: [PATCH 3/9] rp/pio: enable pio interrupts only once since we never actually *disable* these interrupts for any length of time we can simply enable them globally. we also initialize all pio interrupt flags to not cause system interrupts since state machine irqa are not necessarily meant to cause a system interrupt when set. the fifo interrupts are sticky and can likewise only be cleared inside the handler by disabling them. --- embassy-rp/src/lib.rs | 1 + embassy-rp/src/pio.rs | 50 ++++++++++++------------------------------- 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index 697f4308b..d69d12a30 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -156,6 +156,7 @@ pub fn init(_config: config::Config) -> Peripherals { #[cfg(feature = "time-driver")] timer::init(); dma::init(); + pio::init(); } peripherals diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index f0d550d95..00a7aa372 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -79,6 +79,20 @@ unsafe fn PIO1_IRQ_0() { pac::PIO1.irqs(0).inte().write_clear(|m| m.0 = ints); } +pub(crate) unsafe fn init() { + let irq = interrupt::PIO0_IRQ_0::steal(); + irq.disable(); + irq.set_priority(interrupt::Priority::P3); + pac::PIO0.irqs(0).inte().write(|m| m.0 = 0); + irq.enable(); + + let irq = interrupt::PIO1_IRQ_0::steal(); + irq.disable(); + irq.set_priority(interrupt::Priority::P3); + pac::PIO1.irqs(0).inte().write(|m| m.0 = 0); + irq.enable(); +} + /// Future that waits for TX-FIFO to become writable #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> { @@ -89,14 +103,6 @@ pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> { impl<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> FifoOutFuture<'a, PIO, SM> { pub fn new(sm: &'a mut SM, value: u32) -> Self { - unsafe { - critical_section::with(|_| { - let irq = PIO::Irq::steal(); - irq.set_priority(interrupt::Priority::P3); - - irq.enable(); - }); - } FifoOutFuture { sm, pio: PhantomData::default(), @@ -115,12 +121,9 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture } else { WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker()); unsafe { - let irq = PIO::Irq::steal(); - irq.disable(); PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { m.0 = TXNFULL_MASK << SM::Sm::SM_NO; }); - irq.enable(); } // debug!("Pending"); Poll::Pending @@ -147,14 +150,6 @@ pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> { impl<'a, PIO: PioInstance, SM: PioStateMachine> FifoInFuture<'a, PIO, SM> { pub fn new(sm: &'a mut SM) -> Self { - unsafe { - critical_section::with(|_| { - let irq = PIO::Irq::steal(); - irq.set_priority(interrupt::Priority::P3); - - irq.enable(); - }); - } FifoInFuture { sm, pio: PhantomData::default(), @@ -171,12 +166,9 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, } else { WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker()); unsafe { - let irq = PIO::Irq::steal(); - irq.disable(); PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; }); - irq.enable(); } //debug!("Pending"); Poll::Pending @@ -203,14 +195,6 @@ pub struct IrqFuture { impl<'a, PIO: PioInstance> IrqFuture { pub fn new(irq_no: u8) -> Self { - unsafe { - critical_section::with(|_| { - let irq = PIO::Irq::steal(); - irq.set_priority(interrupt::Priority::P3); - - irq.enable(); - }); - } IrqFuture { pio: PhantomData::default(), irq_no, @@ -240,12 +224,9 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); unsafe { - let irq = PIO::Irq::steal(); - irq.disable(); PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { m.0 = SMIRQ_MASK << self.irq_no; }); - irq.enable(); } Poll::Pending } @@ -1171,17 +1152,14 @@ pub struct PioInstanceBase {} pub trait PioInstance: Unpin { const PIO_NO: u8; - type Irq: Interrupt; } impl PioInstance for PioInstanceBase<0> { const PIO_NO: u8 = 0; - type Irq = interrupt::PIO0_IRQ_0; } impl PioInstance for PioInstanceBase<1> { const PIO_NO: u8 = 1; - type Irq = interrupt::PIO1_IRQ_0; } pub type Pio0 = PioInstanceBase<0>; From db16b6ff3f94e48f50c4212c164d018741b61b42 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 18:48:36 +0200 Subject: [PATCH 4/9] rp/pio: don't call dma::init so much this is already done during platform init. it wasn't even sound in the original implementation because futures would meddle with the nvic in critical sections, while another (interrupt) executor could meddle with the nvic without critical sections here. it is only accidentally sound now and only if irq1 of both pios isn't used by user code. luckily the worst we can expect to happen is interrupt priorities being set wrong, but wrong is wrong is wrong. --- embassy-rp/src/pio.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 00a7aa372..3775060f0 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -8,7 +8,7 @@ use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_hal_common::PeripheralRef; use embassy_sync::waitqueue::AtomicWaker; -use crate::dma::{self, Channel, Transfer}; +use crate::dma::{Channel, Transfer}; use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::{Drive, Pin, Pull, SlewRate}; use crate::pac::dma::vals::{DataSize, TreqSel}; @@ -949,7 +949,6 @@ pub trait PioStateMachine: Sized + Unpin { fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> { unsafe { - dma::init(); let pio_no = Self::Pio::PIO_NO; let sm_no = Self::Sm::SM_NO; let p = ch.regs(); @@ -973,7 +972,6 @@ pub trait PioStateMachine: Sized + Unpin { fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> { unsafe { - dma::init(); let pio_no = Self::Pio::PIO_NO; let sm_no = Self::Sm::SM_NO; let p = ch.regs(); From 4618b79b22bee36ef9485a2b0e8562121b84c54b Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 19:28:01 +0200 Subject: [PATCH 5/9] rp/pio: seal PioInstance, SmInstance seems prudent to hide access to the internals. --- embassy-rp/src/pio.rs | 61 +++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 3775060f0..756f0e928 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -12,6 +12,7 @@ use crate::dma::{Channel, Transfer}; use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::{Drive, Pin, Pull, SlewRate}; use crate::pac::dma::vals::{DataSize, TreqSel}; +use crate::pio::sealed::{PioInstance as _, SmInstance as _}; use crate::{interrupt, pac, peripherals, RegExt}; struct Wakers([AtomicWaker; 12]); @@ -320,14 +321,13 @@ pub struct PioStateMachineInstance { sm: PhantomData, } -impl PioStateMachine for PioStateMachineInstance { +impl sealed::PioStateMachine for PioStateMachineInstance { type Pio = PIO; type Sm = SM; } +impl PioStateMachine for PioStateMachineInstance {} -pub trait PioStateMachine: Sized + Unpin { - type Pio: PioInstance; - type Sm: SmInstance; +pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn pio_no(&self) -> u8 { let _ = self; Self::Pio::PIO_NO @@ -1027,9 +1027,10 @@ pub struct PioCommonInstance { pio: PhantomData, } -impl PioCommon for PioCommonInstance { +impl sealed::PioCommon for PioCommonInstance { type Pio = PIO; } +impl PioCommon for PioCommonInstance {} fn write_instr(pio_no: u8, start: usize, instrs: I, mem_user: u32) where @@ -1051,9 +1052,7 @@ where } } -pub trait PioCommon: Sized { - type Pio: PioInstance; - +pub trait PioCommon: sealed::PioCommon + Sized { fn write_instr(&mut self, start: usize, instrs: I) where I: Iterator, @@ -1096,16 +1095,14 @@ pub trait PioCommon: Sized { // Identifies a specific state machine inside a PIO device pub struct SmInstanceBase {} -pub trait SmInstance: Unpin { - const SM_NO: u8; -} +pub trait SmInstance: sealed::SmInstance + Unpin {} -impl SmInstance for SmInstanceBase { +impl sealed::SmInstance for SmInstanceBase { const SM_NO: u8 = SM_NO; } +impl SmInstance for SmInstanceBase {} -pub trait PioPeripheral: Sized { - type Pio: PioInstance; +pub trait PioPeripheral: sealed::PioPeripheral + Sized { fn pio(&self) -> u8 { let _ = self; Self::Pio::PIO_NO @@ -1145,20 +1142,43 @@ pub trait PioPeripheral: Sized { } } +mod sealed { + pub trait PioInstance { + const PIO_NO: u8; + } + + 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 pub struct PioInstanceBase {} -pub trait PioInstance: Unpin { - const PIO_NO: u8; -} +pub trait PioInstance: sealed::PioInstance + Unpin {} -impl PioInstance for PioInstanceBase<0> { +impl sealed::PioInstance for PioInstanceBase<0> { const PIO_NO: u8 = 0; } +impl PioInstance for PioInstanceBase<0> {} -impl PioInstance for PioInstanceBase<1> { +impl sealed::PioInstance for PioInstanceBase<1> { const PIO_NO: u8 = 1; } +impl PioInstance for PioInstanceBase<1> {} pub type Pio0 = PioInstanceBase<0>; pub type Pio1 = PioInstanceBase<1>; @@ -1170,9 +1190,10 @@ pub type Sm3 = SmInstanceBase<3>; macro_rules! impl_pio_sm { ($name:ident, $pio:expr) => { - impl PioPeripheral for peripherals::$name { + impl sealed::PioPeripheral for peripherals::$name { type Pio = PioInstanceBase<$pio>; } + impl PioPeripheral for peripherals::$name {} }; } From 4cd5ed81aa7931b8b0ff3e09c3604cf5d65f2107 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 20:02:52 +0200 Subject: [PATCH 6/9] rp/pio: remove top-level PIOS array this mainly removes the need for explicit indexing to get the pac object. runtime effect is zero, but arguably things are a bit easier to read with less indexing. --- embassy-rp/src/pio.rs | 252 +++++++++++++++--------------------------- 1 file changed, 90 insertions(+), 162 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 756f0e928..088944b66 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -32,7 +32,6 @@ impl Wakers { } } -const PIOS: [&pac::pio::Pio; 2] = [&pac::PIO0, &pac::PIO1]; const NEW_AW: AtomicWaker = AtomicWaker::new(); const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]); static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2]; @@ -122,7 +121,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture } else { WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker()); unsafe { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { + PIO::PIO.irqs(0).inte().write_set(|m| { m.0 = TXNFULL_MASK << SM::Sm::SM_NO; }); } @@ -135,7 +134,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'d, PIO, SM> { fn drop(&mut self) { unsafe { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_clear(|m| { + PIO::PIO.irqs(0).inte().write_clear(|m| { m.0 = TXNFULL_MASK << SM::Sm::SM_NO; }); } @@ -167,7 +166,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, } else { WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker()); unsafe { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { + PIO::PIO.irqs(0).inte().write_set(|m| { m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; }); } @@ -180,7 +179,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, SM> { fn drop(&mut self) { unsafe { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_clear(|m| { + PIO::PIO.irqs(0).inte().write_clear(|m| { m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; }); } @@ -210,7 +209,7 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { // Check if IRQ flag is already set if critical_section::with(|_| unsafe { - let irq_flags = PIOS[PIO::PIO_NO as usize].irq(); + let irq_flags = PIO::PIO.irq(); if irq_flags.read().0 & (1 << self.irq_no) != 0 { irq_flags.write(|m| { m.0 = 1 << self.irq_no; @@ -225,7 +224,7 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker()); unsafe { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_set(|m| { + PIO::PIO.irqs(0).inte().write_set(|m| { m.0 = SMIRQ_MASK << self.irq_no; }); } @@ -236,7 +235,7 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { impl<'d, PIO: PioInstance> Drop for IrqFuture { fn drop(&mut self) { unsafe { - PIOS[PIO::PIO_NO as usize].irqs(0).inte().write_clear(|m| { + PIO::PIO.irqs(0).inte().write_clear(|m| { m.0 = SMIRQ_MASK << self.irq_no; }); } @@ -299,7 +298,7 @@ impl PioPin { pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { let mask = 1 << self.pin(); unsafe { - PIOS[PIO::PIO_NO as usize] + PIO::PIO .input_sync_bypass() .modify(|w| *w = if bypass { *w & !mask } else { *w | mask }); } @@ -340,7 +339,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn restart(&mut self) { let _ = self; unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .ctrl() .modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO)); } @@ -349,7 +348,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { let _ = self; let mask = 1u8 << Self::Sm::SM_NO; unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .ctrl() .modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 }))); } @@ -357,46 +356,44 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn is_enabled(&self) -> bool { let _ = self; - unsafe { PIOS[Self::Pio::PIO_NO as usize].ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_tx_empty(&self) -> bool { let _ = self; - unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_tx_full(&self) -> bool { let _ = self; - unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_rx_empty(&self) -> bool { let _ = self; - unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_rx_full(&self) -> bool { let _ = self; - unsafe { PIOS[Self::Pio::PIO_NO as usize].fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 } } fn tx_level(&self) -> u8 { unsafe { - let flevel = PIOS[Self::Pio::PIO_NO as usize].flevel().read().0; + let flevel = Self::Pio::PIO.flevel().read().0; (flevel >> (Self::Sm::SM_NO * 8)) as u8 & 0x0f } } fn rx_level(&self) -> u8 { unsafe { - let flevel = PIOS[Self::Pio::PIO_NO as usize].flevel().read().0; + let flevel = Self::Pio::PIO.flevel().read().0; (flevel >> (Self::Sm::SM_NO * 8 + 4)) as u8 & 0x0f } } fn push_tx(&mut self, v: u32) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .txf(Self::Sm::SM_NO as usize) - .write_value(v); + Self::Pio::PIO.txf(Self::Sm::SM_NO as usize).write_value(v); } } @@ -409,7 +406,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn pull_rx(&mut self) -> u32 { - unsafe { PIOS[Self::Pio::PIO_NO as usize].rxf(Self::Sm::SM_NO as usize).read() } + unsafe { Self::Pio::PIO.rxf(Self::Sm::SM_NO as usize).read() } } fn try_pull_rx(&mut self) -> Option { @@ -421,7 +418,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_clkdiv(&mut self, div_x_256: u32) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .clkdiv() .write(|w| w.0 = div_x_256 << 8); @@ -429,20 +426,13 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_clkdiv(&self) -> u32 { - unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .clkdiv() - .read() - .0 - >> 8 - } + unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).clkdiv().read().0 >> 8 } } fn clkdiv_restart(&mut self) { let _ = self; unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .ctrl() .modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO)); } @@ -450,7 +440,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_side_enable(&self, enable: bool) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .execctrl() .modify(|w| w.set_side_en(enable)); @@ -458,18 +448,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn is_side_enabled(&self) -> bool { - unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .read() - .side_en() - } + unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().side_en() } } fn set_side_pindir(&mut self, pindir: bool) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .execctrl() .modify(|w| w.set_side_pindir(pindir)); @@ -478,7 +462,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn is_side_pindir(&self) -> bool { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .execctrl() .read() @@ -488,7 +472,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_jmp_pin(&mut self, pin: u8) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .execctrl() .modify(|w| w.set_jmp_pin(pin)); @@ -496,34 +480,22 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_jmp_pin(&mut self) -> u8 { - unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .read() - .jmp_pin() - } + unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().jmp_pin() } } fn set_wrap(&self, source: u8, target: u8) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .modify(|w| { - w.set_wrap_top(source); - w.set_wrap_bottom(target) - }); + Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().modify(|w| { + w.set_wrap_top(source); + w.set_wrap_bottom(target) + }); } } /// Get wrapping addresses. Returns (source, target). fn get_wrap(&self) -> (u8, u8) { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read(); (r.wrap_top(), r.wrap_bottom()) } } @@ -535,21 +507,15 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { FifoJoin::TxOnly => (false, true), }; unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| { - w.set_fjoin_rx(rx); - w.set_fjoin_tx(tx) - }); + Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().modify(|w| { + w.set_fjoin_rx(rx); + w.set_fjoin_tx(tx) + }); } } fn get_fifo_join(&self) -> FifoJoin { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); // Ignores the invalid state when both bits are set if r.fjoin_rx() { FifoJoin::RxOnly @@ -564,9 +530,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn clear_fifos(&mut self) { // Toggle FJOIN_RX to flush FIFOs unsafe { - let shiftctrl = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .shiftctrl(); + let shiftctrl = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl(); shiftctrl.modify(|w| { w.set_fjoin_rx(!w.fjoin_rx()); }); @@ -578,7 +542,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_pull_threshold(&mut self, threshold: u8) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .modify(|w| w.set_pull_thresh(threshold)); @@ -587,16 +551,13 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn get_pull_threshold(&self) -> u8 { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read(); + 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) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .modify(|w| w.set_push_thresh(threshold)); @@ -605,17 +566,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn get_push_threshold(&self) -> u8 { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read(); + 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) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); @@ -623,7 +581,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_out_shiftdir(&self) -> ShiftDirection { unsafe { - if PIOS[Self::Pio::PIO_NO as usize] + if Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .read() @@ -638,7 +596,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_in_shift_dir(&mut self, dir: ShiftDirection) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); @@ -646,7 +604,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_in_shiftdir(&self) -> ShiftDirection { unsafe { - if PIOS[Self::Pio::PIO_NO as usize] + if Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .read() @@ -661,7 +619,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_autopull(&mut self, auto: bool) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .modify(|w| w.set_autopull(auto)); @@ -670,7 +628,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn is_autopull(&self) -> bool { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .read() @@ -680,7 +638,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_autopush(&mut self, auto: bool) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .modify(|w| w.set_autopush(auto)); @@ -689,7 +647,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn is_autopush(&self) -> bool { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .shiftctrl() .read() @@ -699,16 +657,13 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn get_addr(&self) -> u8 { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .addr() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).addr().read(); r.addr() } } fn set_sideset_count(&mut self, count: u8) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .pinctrl() .modify(|w| w.set_sideset_count(count)); @@ -717,10 +672,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn get_sideset_count(&self) -> u8 { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); r.sideset_count() } } @@ -747,7 +699,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_sideset_base_pin(&mut self, base_pin: &PioPin) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .pinctrl() .modify(|w| w.set_sideset_base(base_pin.pin())); @@ -756,10 +708,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn get_sideset_base(&self) -> u8 { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); r.sideset_base() } } @@ -768,30 +717,24 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_set_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| { - w.set_set_base(base); - w.set_set_count(count) - }); + Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { + w.set_set_base(base); + w.set_set_count(count) + }); } } /// Get the range of out pins affected by a set instruction. Returns (base, count). fn get_set_range(&self) -> (u8, u8) { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); (r.set_base(), r.set_count()) } } fn set_in_base_pin(&mut self, base: &PioPin) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .pinctrl() .modify(|w| w.set_in_base(base.pin())); @@ -800,10 +743,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn get_in_base(&self) -> u8 { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); r.in_base() } } @@ -811,23 +751,17 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_out_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| { - w.set_out_base(base); - w.set_out_count(count) - }); + Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { + w.set_out_base(base); + w.set_out_count(count) + }); } } /// Get the range of out pins affected by a set instruction. Returns (base, count). fn get_out_range(&self) -> (u8, u8) { unsafe { - let r = PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .read(); + let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); (r.out_base(), r.out_count()) } } @@ -855,18 +789,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_current_instr() -> u32 { - unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .sm(Self::Sm::SM_NO as usize) - .instr() - .read() - .0 - } + unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).instr().read().0 } } fn exec_instr(&mut self, instr: u16) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .sm(Self::Sm::SM_NO as usize) .instr() .write(|w| w.set_instr(instr)); @@ -879,6 +807,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { { let _ = self; write_instr( + Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, @@ -889,14 +818,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn is_irq_set(&self, irq_no: u8) -> bool { assert!(irq_no < 8); unsafe { - let irq_flags = PIOS[Self::Pio::PIO_NO as usize].irq(); + let irq_flags = Self::Pio::PIO.irq(); irq_flags.read().0 & (1 << irq_no) != 0 } } fn clear_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); - unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(1 << irq_no)) } + unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } } fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> { @@ -913,7 +842,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_tx_stalled(&self) -> bool { unsafe { - let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug(); + let fdebug = Self::Pio::PIO.fdebug(); let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0; fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO)); ret @@ -922,7 +851,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_tx_overflowed(&self) -> bool { unsafe { - let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug(); + let fdebug = Self::Pio::PIO.fdebug(); let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0; fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO)); ret @@ -931,7 +860,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_rx_stalled(&self) -> bool { unsafe { - let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug(); + let fdebug = Self::Pio::PIO.fdebug(); let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0; fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO)); ret @@ -940,7 +869,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_rx_underflowed(&self) -> bool { unsafe { - let fdebug = PIOS[Self::Pio::PIO_NO as usize].fdebug(); + let fdebug = Self::Pio::PIO.fdebug(); let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0; fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO)); ret @@ -954,7 +883,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { let p = ch.regs(); p.read_addr().write_value(data.as_ptr() as u32); p.write_addr() - .write_value(PIOS[pio_no as usize].txf(sm_no as usize).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.ctrl_trig().write(|w| { // Set TX DREQ for this statemachine @@ -977,7 +906,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { let p = ch.regs(); p.write_addr().write_value(data.as_ptr() as u32); p.read_addr() - .write_value(PIOS[pio_no as usize].rxf(sm_no as usize).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.ctrl_trig().write(|w| { // Set TX DREQ for this statemachine @@ -1032,7 +961,7 @@ impl sealed::PioCommon for PioCommonInstance { } impl PioCommon for PioCommonInstance {} -fn write_instr(pio_no: u8, start: usize, instrs: I, mem_user: u32) +fn write_instr(pio: &pac::pio::Pio, pio_no: u8, start: usize, instrs: I, mem_user: u32) where I: Iterator, { @@ -1044,7 +973,7 @@ where addr ); unsafe { - PIOS[pio_no as usize].instr_mem(addr as usize).write(|w| { + pio.instr_mem(addr as usize).write(|w| { w.set_instr_mem(instr); }); instr_mem_set_status(pio_no, addr, mem_user); @@ -1058,37 +987,33 @@ pub trait PioCommon: sealed::PioCommon + Sized { I: Iterator, { let _ = self; - write_instr(Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); + write_instr(Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); } fn clear_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); - unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(1 << irq_no)) } + unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } } fn clear_irqs(&mut self, mask: u8) { - unsafe { PIOS[Self::Pio::PIO_NO as usize].irq().write(|w| w.set_irq(mask)) } + unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(mask)) } } fn force_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); - unsafe { - PIOS[Self::Pio::PIO_NO as usize] - .irq_force() - .write(|w| w.set_irq_force(1 << irq_no)) - } + unsafe { Self::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) { unsafe { - PIOS[Self::Pio::PIO_NO as usize] + Self::Pio::PIO .input_sync_bypass() .modify(|w| *w = (*w & !mask) | (bypass & mask)); } } fn get_input_sync_bypass(&self) -> u32 { - unsafe { PIOS[Self::Pio::PIO_NO as usize].input_sync_bypass().read() } + unsafe { Self::Pio::PIO.input_sync_bypass().read() } } } @@ -1145,6 +1070,7 @@ pub trait PioPeripheral: sealed::PioPeripheral + Sized { mod sealed { pub trait PioInstance { const PIO_NO: u8; + const PIO: &'static crate::pac::pio::Pio; } pub trait PioCommon { @@ -1172,11 +1098,13 @@ pub trait PioInstance: sealed::PioInstance + Unpin {} impl sealed::PioInstance for PioInstanceBase<0> { const PIO_NO: u8 = 0; + const PIO: &'static pac::pio::Pio = &pac::PIO0; } impl PioInstance for PioInstanceBase<0> {} impl sealed::PioInstance for PioInstanceBase<1> { const PIO_NO: u8 = 1; + const PIO: &'static pac::pio::Pio = &pac::PIO1; } impl PioInstance for PioInstanceBase<1> {} From 58e727d3b9aa9d54f7c20f618fada176dcd533a9 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 20:16:27 +0200 Subject: [PATCH 7/9] rp/pio: move non-sm-specific methods to PioCommon pin and irq operations affect the entire pio block. with pins this is not very problematic since pins themselves are resources, but irqs are not treated like that and can thus interfere across state machines. the ability to wait for an irq on a state machine is kept to make synchronization with user code easier, and since we can't inspect loaded programs at build time we wouldn't gain much from disallowing waits from state machines anyway. --- embassy-rp/src/pio.rs | 61 ++++++++++++++----------------- examples/rp/src/bin/pio_async.rs | 20 ++++++---- examples/rp/src/bin/ws2812-pio.rs | 11 +++--- 3 files changed, 47 insertions(+), 45 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 088944b66..b43244da2 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -677,26 +677,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - fn make_pio_pin(&self, pin: impl Pin) -> PioPin { - unsafe { - pin.io().ctrl().write(|w| { - 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 { - pin_bank: pin.pin_bank(), - pio: PhantomData::default(), - } - } - fn set_sideset_base_pin(&mut self, base_pin: &PioPin) { unsafe { Self::Pio::PIO @@ -815,19 +795,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { ); } - fn is_irq_set(&self, irq_no: u8) -> bool { - assert!(irq_no < 8); - unsafe { - let irq_flags = Self::Pio::PIO.irq(); - irq_flags.read().0 & (1 << irq_no) != 0 - } - } - - fn clear_irq(&mut self, irq_no: usize) { - assert!(irq_no < 8); - unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } - } - fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> { FifoOutFuture::new(self, value) } @@ -990,6 +957,14 @@ pub trait PioCommon: sealed::PioCommon + Sized { write_instr(Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); } + fn is_irq_set(&self, irq_no: u8) -> bool { + assert!(irq_no < 8); + unsafe { + let irq_flags = Self::Pio::PIO.irq(); + irq_flags.read().0 & (1 << irq_no) != 0 + } + } + fn clear_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } @@ -1015,6 +990,26 @@ pub trait PioCommon: sealed::PioCommon + Sized { fn get_input_sync_bypass(&self) -> u32 { unsafe { Self::Pio::PIO.input_sync_bypass().read() } } + + fn make_pio_pin(&self, pin: impl Pin) -> PioPin { + unsafe { + pin.io().ctrl().write(|w| { + 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 { + pin_bank: pin.pin_bank(), + pio: PhantomData::default(), + } + } } // Identifies a specific state machine inside a PIO device diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index e616d8c5a..3cfeec71f 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -4,13 +4,15 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{AnyPin, Pin}; -use embassy_rp::pio::{Pio0, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2}; +use embassy_rp::pio::{ + Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, + Sm1, Sm2, +}; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use {defmt_rtt as _, panic_probe as _}; -#[embassy_executor::task] -async fn pio_task_sm0(mut sm: PioStateMachineInstance, pin: AnyPin) { +fn setup_pio_task_sm0(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance, pin: AnyPin) { // Setup sm0 // Send data serially to pin @@ -23,11 +25,11 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance, pin: AnyPin) { ); let relocated = RelocatedProgram::new(&prg.program); - let out_pin = sm.make_pio_pin(pin); + let out_pin = pio.make_pio_pin(pin); let pio_pins = [&out_pin]; sm.set_out_pins(&pio_pins); sm.write_instr(relocated.origin() as usize, relocated.code()); - pio_instr_util::exec_jmp(&mut sm, relocated.origin()); + pio_instr_util::exec_jmp(sm, relocated.origin()); sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); sm.set_set_range(0, 1); let pio::Wrap { source, target } = relocated.wrap(); @@ -35,7 +37,10 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance, pin: AnyPin) { sm.set_autopull(true); sm.set_out_shift_dir(ShiftDirection::Left); +} +#[embassy_executor::task] +async fn pio_task_sm0(mut sm: PioStateMachineInstance) { sm.set_enable(true); let mut v = 0x0f0caffa; @@ -104,9 +109,10 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); let pio = p.PIO0; - let (_, sm0, sm1, sm2, ..) = pio.split(); + let (mut pio0, mut sm0, sm1, sm2, ..) = pio.split(); - spawner.spawn(pio_task_sm0(sm0, p.PIN_0.degrade())).unwrap(); + setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade()); + spawner.spawn(pio_task_sm0(sm0)).unwrap(); spawner.spawn(pio_task_sm1(sm1)).unwrap(); spawner.spawn(pio_task_sm2(sm2)).unwrap(); } diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 5f8a3baee..211c60c49 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -6,7 +6,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{self, Pin}; use embassy_rp::pio::{ - FifoJoin, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstance, + FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, + ShiftDirection, SmInstance, }; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; @@ -18,7 +19,7 @@ pub struct Ws2812 { } impl Ws2812 { - pub fn new(mut sm: PioStateMachineInstance, pin: gpio::AnyPin) -> Self { + pub fn new(pio: PioCommonInstance

, mut sm: PioStateMachineInstance, pin: gpio::AnyPin) -> Self { // Setup sm0 // prepare the PIO program @@ -53,7 +54,7 @@ impl Ws2812 { pio_instr_util::exec_jmp(&mut sm, relocated.origin()); // Pin config - let out_pin = sm.make_pio_pin(pin); + let out_pin = pio.make_pio_pin(pin); sm.set_set_pins(&[&out_pin]); sm.set_sideset_base_pin(&out_pin); sm.set_sideset_count(1); @@ -115,7 +116,7 @@ async fn main(_spawner: Spawner) { info!("Start"); let p = embassy_rp::init(Default::default()); - let (_pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split(); + let (pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split(); // 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. @@ -124,7 +125,7 @@ async fn main(_spawner: Spawner) { // For the thing plus, use pin 8 // For the feather, use pin 16 - let mut ws2812 = Ws2812::new(sm0, p.PIN_8.degrade()); + let mut ws2812 = Ws2812::new(pio0, sm0, p.PIN_8.degrade()); // Loop forever making RGB values and pushing them out to the WS2812. loop { From fa1ec29ae61df78a74be4bffb47f400fa35e49f1 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 20:18:22 +0200 Subject: [PATCH 8/9] rp/pio: remove a bunch of unnecessary let _ = self --- embassy-rp/src/pio.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index b43244da2..8492ca31d 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -328,7 +328,6 @@ impl PioStateMachine for PioStateMachineInstan pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn pio_no(&self) -> u8 { - let _ = self; Self::Pio::PIO_NO } @@ -337,7 +336,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn restart(&mut self) { - let _ = self; unsafe { Self::Pio::PIO .ctrl() @@ -345,7 +343,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } fn set_enable(&mut self, enable: bool) { - let _ = self; let mask = 1u8 << Self::Sm::SM_NO; unsafe { Self::Pio::PIO @@ -355,25 +352,20 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn is_enabled(&self) -> bool { - let _ = self; unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_tx_empty(&self) -> bool { - let _ = self; unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_tx_full(&self) -> bool { - let _ = self; unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_rx_empty(&self) -> bool { - let _ = self; unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::Sm::SM_NO) != 0 } } fn is_rx_full(&self) -> bool { - let _ = self; unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::Sm::SM_NO) != 0 } } @@ -430,7 +422,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn clkdiv_restart(&mut self) { - let _ = self; unsafe { Self::Pio::PIO .ctrl() @@ -785,7 +776,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { where I: Iterator, { - let _ = self; write_instr( Self::Pio::PIO, Self::Pio::PIO_NO, @@ -953,7 +943,6 @@ pub trait PioCommon: sealed::PioCommon + Sized { where I: Iterator, { - let _ = self; write_instr(Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); } @@ -1024,7 +1013,6 @@ impl SmInstance for SmInstanceBase {} pub trait PioPeripheral: sealed::PioPeripheral + Sized { fn pio(&self) -> u8 { - let _ = self; Self::Pio::PIO_NO } @@ -1037,7 +1025,6 @@ pub trait PioPeripheral: sealed::PioPeripheral + Sized { PioStateMachineInstance>, PioStateMachineInstance>, ) { - let _ = self; ( PioCommonInstance { pio: PhantomData::default(), From f4ade6af8bb2571ce2de0531d9c9715a7b8b941c Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 20:40:18 +0200 Subject: [PATCH 9/9] rp/pio: write instr memory only from common instruction memory is a shared resource. writing it only from PioCommon clarifies this, and perhaps makes it more obvious that multiple state machines can share the same instructions. this also allows *freeing* of instruction memory to reprogram the system, although this interface is not entirely safe yet. it's safe in the sense rusts understands things, but state machines may misbehave if their instruction memory is freed and rewritten while they are running. fixing this is out of scope for now since it requires some larger changes to how state machines are handled. the interface provided currently is already unsafe in that it lets people execute instruction memory that has never been written, so this isn't much of a drawback for now. --- embassy-rp/src/pio.rs | 106 ++++++++++++------------------ examples/rp/src/bin/pio_async.rs | 28 +++++--- examples/rp/src/bin/pio_dma.rs | 6 +- examples/rp/src/bin/ws2812-pio.rs | 4 +- 4 files changed, 64 insertions(+), 80 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 8492ca31d..7faec10b5 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -772,19 +772,6 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - fn write_instr(&mut self, start: usize, instrs: I) - where - I: Iterator, - { - write_instr( - Self::Pio::PIO, - Self::Pio::PIO_NO, - start, - instrs, - MEM_USED_BY_STATEMACHINE | Self::Sm::SM_NO as u32, - ); - } - fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> { FifoOutFuture::new(self, value) } @@ -880,71 +867,59 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } -/* -This is a bit array containing 4 bits for every word in the PIO instruction memory. -*/ -// Bit 3-2 -//const MEM_USE_MASK: u32 = 0b1100; -const MEM_NOT_USED: u32 = 0b0000; -const MEM_USED_BY_STATEMACHINE: u32 = 0b0100; -const MEM_USED_BY_COMMON: u32 = 0b1000; - -// Bit 1-0 is the number of the state machine -//const MEM_STATE_MASK: u32 = 0b0011; - -// Should use mutex if running on multiple cores -static mut INSTR_MEM_STATUS: &'static mut [[u32; 4]; 2] = &mut [[0; 4]; 2]; - -fn instr_mem_get_status(pio_no: u8, addr: u8) -> u32 { - ((unsafe { INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] }) >> ((addr & 0x07) * 4)) & 0xf -} - -fn instr_mem_set_status(pio_no: u8, addr: u8, status: u32) { - let w = unsafe { &mut INSTR_MEM_STATUS[pio_no as usize][(addr >> 3) as usize] }; - let shift = (addr & 0x07) * 4; - *w = (*w & !(0xf << shift)) | (status << shift); -} - -fn instr_mem_is_free(pio_no: u8, addr: u8) -> bool { - instr_mem_get_status(pio_no, addr) == MEM_NOT_USED -} - pub struct PioCommonInstance { + instructions_used: u32, + pio: PhantomData, +} + +pub struct PioInstanceMemory { + used_mask: u32, pio: PhantomData, } impl sealed::PioCommon for PioCommonInstance { type Pio = PIO; } -impl PioCommon for PioCommonInstance {} - -fn write_instr(pio: &pac::pio::Pio, pio_no: u8, start: usize, instrs: I, mem_user: u32) -where - I: Iterator, -{ - for (i, instr) in instrs.enumerate() { - let addr = (i + start) as u8; - assert!( - instr_mem_is_free(pio_no, addr), - "Trying to write already used PIO instruction memory at {}", - addr - ); - unsafe { - pio.instr_mem(addr as usize).write(|w| { - w.set_instr_mem(instr); - }); - instr_mem_set_status(pio_no, addr, mem_user); +impl PioCommon for PioCommonInstance { + fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory + where + I: Iterator, + { + let mut used_mask = 0; + for (i, instr) in instrs.enumerate() { + let addr = (i + start) as u8; + let mask = 1 << (addr as usize); + assert!( + self.instructions_used & mask == 0, + "Trying to write already used PIO instruction memory at {}", + addr + ); + unsafe { + PIO::PIO.instr_mem(addr as usize).write(|w| { + w.set_instr_mem(instr); + }); + } + used_mask |= mask; } + self.instructions_used |= used_mask; + PioInstanceMemory { + used_mask, + pio: PhantomData, + } + } + + fn free_instr(&mut self, instrs: PioInstanceMemory) { + self.instructions_used &= !instrs.used_mask; } } pub trait PioCommon: sealed::PioCommon + Sized { - fn write_instr(&mut self, start: usize, instrs: I) + fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory where - I: Iterator, - { - write_instr(Self::Pio::PIO, Self::Pio::PIO_NO, start, instrs, MEM_USED_BY_COMMON); - } + I: Iterator; + + // TODO make instruction memory that is currently in use unfreeable + fn free_instr(&mut self, instrs: PioInstanceMemory); fn is_irq_set(&self, irq_no: u8) -> bool { assert!(irq_no < 8); @@ -1027,6 +1002,7 @@ pub trait PioPeripheral: sealed::PioPeripheral + Sized { ) { ( PioCommonInstance { + instructions_used: 0, pio: PhantomData::default(), }, PioStateMachineInstance { diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 3cfeec71f..1b075b8fd 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -28,7 +28,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance, sm: &mut PioStateMachin let out_pin = pio.make_pio_pin(pin); let pio_pins = [&out_pin]; sm.set_out_pins(&pio_pins); - sm.write_instr(relocated.origin() as usize, relocated.code()); + pio.write_instr(relocated.origin() as usize, relocated.code()); pio_instr_util::exec_jmp(sm, relocated.origin()); sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); sm.set_set_range(0, 1); @@ -51,16 +51,15 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance) { } } -#[embassy_executor::task] -async fn pio_task_sm1(mut sm: PioStateMachineInstance) { +fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); let relocated = RelocatedProgram::new(&prg.program); - sm.write_instr(relocated.origin() as usize, relocated.code()); - pio_instr_util::exec_jmp(&mut sm, relocated.origin()); + pio.write_instr(relocated.origin() as usize, relocated.code()); + pio_instr_util::exec_jmp(sm, relocated.origin()); sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); sm.set_set_range(0, 0); let pio::Wrap { source, target } = relocated.wrap(); @@ -68,6 +67,10 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance) { sm.set_autopush(true); sm.set_in_shift_dir(ShiftDirection::Right); +} + +#[embassy_executor::task] +async fn pio_task_sm1(mut sm: PioStateMachineInstance) { sm.set_enable(true); loop { let rx = sm.wait_pull().await; @@ -75,8 +78,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance) { } } -#[embassy_executor::task] -async fn pio_task_sm2(mut sm: PioStateMachineInstance) { +fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { // Setup sm2 // Repeatedly trigger IRQ 3 @@ -90,13 +92,17 @@ async fn pio_task_sm2(mut sm: PioStateMachineInstance) { ".wrap", ); let relocated = RelocatedProgram::new(&prg.program); - sm.write_instr(relocated.origin() as usize, relocated.code()); + pio.write_instr(relocated.origin() as usize, relocated.code()); let pio::Wrap { source, target } = relocated.wrap(); sm.set_wrap(source, target); - pio_instr_util::exec_jmp(&mut sm, relocated.origin()); + pio_instr_util::exec_jmp(sm, relocated.origin()); sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); +} + +#[embassy_executor::task] +async fn pio_task_sm2(mut sm: PioStateMachineInstance) { sm.set_enable(true); loop { sm.wait_irq(3).await; @@ -109,9 +115,11 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); let pio = p.PIO0; - let (mut pio0, mut sm0, sm1, sm2, ..) = pio.split(); + let (mut pio0, mut sm0, mut sm1, mut sm2, ..) = pio.split(); setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade()); + setup_pio_task_sm1(&mut pio0, &mut sm1); + setup_pio_task_sm2(&mut pio0, &mut sm2); spawner.spawn(pio_task_sm0(sm0)).unwrap(); spawner.spawn(pio_task_sm1(sm1)).unwrap(); spawner.spawn(pio_task_sm2(sm2)).unwrap(); diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 145e4a656..7d4919f75 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_rp::pio::{PioPeripheral, PioStateMachine, ShiftDirection}; +use embassy_rp::pio::{PioCommon, PioPeripheral, PioStateMachine, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; @@ -19,7 +19,7 @@ fn swap_nibbles(v: u32) -> u32 { async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let pio = p.PIO0; - let (_, mut sm, ..) = pio.split(); + let (mut pio0, mut sm, ..) = pio.split(); let prg = pio_proc::pio_asm!( ".origin 0", @@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) { ); let relocated = RelocatedProgram::new(&prg.program); - sm.write_instr(relocated.origin() as usize, relocated.code()); + pio0.write_instr(relocated.origin() as usize, relocated.code()); pio_instr_util::exec_jmp(&mut sm, relocated.origin()); sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); let pio::Wrap { source, target } = relocated.wrap(); diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 211c60c49..041e8ae11 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -19,7 +19,7 @@ pub struct Ws2812 { } impl Ws2812 { - pub fn new(pio: PioCommonInstance

, mut sm: PioStateMachineInstance, pin: gpio::AnyPin) -> Self { + pub fn new(mut pio: PioCommonInstance

, mut sm: PioStateMachineInstance, pin: gpio::AnyPin) -> Self { // Setup sm0 // prepare the PIO program @@ -50,7 +50,7 @@ impl Ws2812 { let prg = a.assemble_with_wrap(wrap_source, wrap_target); let relocated = RelocatedProgram::new(&prg); - sm.write_instr(relocated.origin() as usize, relocated.code()); + pio.write_instr(relocated.origin() as usize, relocated.code()); pio_instr_util::exec_jmp(&mut sm, relocated.origin()); // Pin config