From 1e8da91defc2b5b328d733dedffc25893c786c1f Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 2 May 2023 20:39:19 +0200 Subject: [PATCH 01/11] rp/pio: make free_instr unsafe we can't prove that some instruction memory is not used as long as state machines are alive, and we can pass instance memory handles between instances as well. mark free_instr unsafe, with documentation for this caveat. --- embassy-rp/src/pio.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 5433d3f2..0616f6fc 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -827,8 +827,10 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { } } - // TODO make instruction memory that is currently in use unfreeable - pub fn free_instr(&mut self, instrs: PioInstanceMemory) { + /// Free instruction memory previously allocated with [`PioCommon::write_instr`]. + /// This is always possible but unsafe if any state machine is still using this + /// bit of memory. + pub unsafe fn free_instr(&mut self, instrs: PioInstanceMemory) { self.instructions_used &= !instrs.used_mask; } From 62841dd5b958fa2458aceb638a17d243e72d987f Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 2 May 2023 12:52:29 +0200 Subject: [PATCH 02/11] rp/pio: revert pio pin funcsel to null on pio+sms drop once all sharing owners of pio pins have been dropped we should reset the pin for use by other hal objects. unfortunately this needs an atomic state per pio block because PioCommon and all of the state machines really do share ownership of any wrapped pins. only PioCommon can create them, but all state machines can keep them alive. since state machines can be moved to core1 we can't do reference counting in relaxed mode, but we *can* do relaxed pin accounting (since only common and the final drop can modify this). --- embassy-rp/src/pio.rs | 67 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 0616f6fc..32e9be74 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -4,9 +4,11 @@ use core::pin::Pin as FuturePin; use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; +use atomic_polyfill::{AtomicU32, AtomicU8}; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_hal_common::{Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use pac::io::vals::Gpio0ctrlFuncsel; use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; @@ -320,6 +322,12 @@ pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> { pio: PhantomData<&'d PIO>, } +impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachineInstance<'d, PIO, SM> { + fn drop(&mut self) { + on_pio_drop::(); + } +} + impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { type Pio = PIO; const SM: usize = SM; @@ -794,6 +802,12 @@ pub struct PioCommon<'d, PIO: PioInstance> { pio: PhantomData<&'d PIO>, } +impl<'d, PIO: PioInstance> Drop for PioCommon<'d, PIO> { + fn drop(&mut self) { + on_pio_drop::(); + } +} + pub struct PioInstanceMemory<'d, PIO: PioInstance> { used_mask: u32, pio: PhantomData<&'d PIO>, @@ -870,10 +884,15 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { unsafe { PIO::PIO.input_sync_bypass().read() } } - pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin { + /// Register a pin for PIO usage. Pins will be released from the PIO block + /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`PioCommon`] *and* + /// all [`PioStateMachine`]s for this block have been dropped. + pub fn make_pio_pin(&mut self, pin: impl Pin) -> PioPin { unsafe { pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); } + // we can be relaxed about this because we're &mut here and nothing is cached + PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); PioPin { pin_bank: pin.pin_bank(), pio: PhantomData::default(), @@ -891,6 +910,8 @@ pub struct Pio<'d, PIO: PioInstance> { impl<'d, PIO: PioInstance> Pio<'d, PIO> { pub fn new(_pio: impl Peripheral

+ 'd) -> Self { + PIO::state().users.store(5, Ordering::Release); + PIO::state().used_pins.store(0, Ordering::Release); Self { common: PioCommon { instructions_used: 0, @@ -904,13 +925,35 @@ impl<'d, PIO: PioInstance> Pio<'d, PIO> { } } -pub trait PioInstance: sealed::PioInstance + Sized + Unpin { - fn pio(&self) -> u8 { - Self::PIO_NO +// we need to keep a record of which pins are assigned to each PIO. make_pio_pin +// notionally takes ownership of the pin it is given, but the wrapped pin cannot +// be treated as an owned resource since dropping it would have to deconfigure +// the pin, breaking running state machines in the process. pins are also shared +// between all state machines, which makes ownership even messier to track any +// other way. +pub struct State { + users: AtomicU8, + used_pins: AtomicU32, +} + +fn on_pio_drop() { + let state = PIO::state(); + if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { + let used_pins = state.used_pins.load(Ordering::Relaxed); + let null = Gpio0ctrlFuncsel::NULL.0; + for i in 0..32 { + if used_pins & (1 << i) != 0 { + unsafe { + pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null)); + } + } + } } } mod sealed { + use super::*; + pub trait PioStateMachine { type Pio: super::PioInstance; const SM: usize; @@ -925,6 +968,22 @@ mod sealed { const PIO_NO: u8; const PIO: &'static crate::pac::pio::Pio; const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; + + #[inline] + fn state() -> &'static State { + static STATE: State = State { + users: AtomicU8::new(0), + used_pins: AtomicU32::new(0), + }; + + &STATE + } + } +} + +pub trait PioInstance: sealed::PioInstance + Sized + Unpin { + fn pio(&self) -> u8 { + Self::PIO_NO } } From 17e78175a69dc96ea8f71c41949cbc705d82b51a Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 11:21:58 +0200 Subject: [PATCH 03/11] rp/pio: disable state machines on drop --- embassy-rp/src/pio.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 32e9be74..d05eef04 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -324,6 +324,9 @@ pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> { impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachineInstance<'d, PIO, SM> { fn drop(&mut self) { + unsafe { + PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); + } on_pio_drop::(); } } From 4ccb2bc95aab6202d6f53882a59265427cdd5655 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 08:15:46 +0200 Subject: [PATCH 04/11] rp/pio: add PioPin trait pio can only access pins in bank 0, so it doesn't make sense to even allow wrapping of other banks' pins. --- embassy-rp/src/pio.rs | 41 ++++++++++++++++++++++-------- examples/rp/src/bin/pio_async.rs | 7 +++-- examples/rp/src/bin/pio_hd44780.rs | 17 ++++++------- examples/rp/src/bin/ws2812-pio.rs | 7 +++-- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index d05eef04..21223eaf 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -12,7 +12,7 @@ use pac::io::vals::Gpio0ctrlFuncsel; use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; -use crate::gpio::{Drive, Pin, Pull, SlewRate}; +use crate::gpio::{self, Drive, Pull, SlewRate}; use crate::pac::dma::vals::TreqSel; use crate::pio::sealed::PioInstance as _; use crate::{interrupt, pac, peripherals, RegExt}; @@ -244,12 +244,12 @@ impl<'d, PIO: PioInstance> Drop for IrqFuture { } } -pub struct PioPin { +pub struct Pin { pin_bank: u8, pio: PhantomData, } -impl PioPin { +impl Pin { /// Set the pin's drive strength. #[inline] pub fn set_drive_strength(&mut self, strength: Drive) { @@ -312,7 +312,7 @@ impl PioPin { } } -impl SealedPin for PioPin { +impl SealedPin for Pin { fn pin_bank(&self) -> u8 { self.pin_bank } @@ -610,7 +610,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { unsafe { Self::this_sm().pinctrl().read().sideset_count() } } - fn set_sideset_base_pin(&mut self, base_pin: &PioPin) { + fn set_sideset_base_pin(&mut self, base_pin: &Pin) { unsafe { Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin())); } @@ -642,7 +642,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - fn set_in_base_pin(&mut self, base: &PioPin) { + fn set_in_base_pin(&mut self, base: &Pin) { unsafe { Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin())); } @@ -673,7 +673,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&PioPin]) { + fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { let count = pins.len(); assert!(count >= 1); let start = pins[0].pin() as usize; @@ -684,7 +684,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { self.set_out_range(start as u8, count as u8); } - fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&PioPin]) { + fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { let count = pins.len(); assert!(count >= 1); let start = pins[0].pin() as usize; @@ -890,13 +890,13 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { /// Register a pin for PIO usage. Pins will be released from the PIO block /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`PioCommon`] *and* /// all [`PioStateMachine`]s for this block have been dropped. - pub fn make_pio_pin(&mut self, pin: impl Pin) -> PioPin { + pub fn make_pio_pin(&mut self, pin: impl PioPin) -> Pin { unsafe { pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); } // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); - PioPin { + Pin { pin_bank: pin.pin_bank(), pio: PhantomData::default(), } @@ -967,6 +967,8 @@ mod sealed { } } + pub trait PioPin {} + pub trait PioInstance { const PIO_NO: u8; const PIO: &'static crate::pac::pio::Pio; @@ -1003,3 +1005,22 @@ macro_rules! impl_pio { impl_pio!(PIO0, 0, PIO0, PIO0_0); impl_pio!(PIO1, 1, PIO1, PIO1_0); + +pub trait PioPin: sealed::PioPin + gpio::Pin {} + +macro_rules! impl_pio_pin { + ($( $num:tt )*) => { + $( + paste::paste!{ + impl sealed::PioPin for peripherals::[< PIN_ $num >] {} + impl PioPin for peripherals::[< PIN_ $num >] {} + } + )* + }; +} + +impl_pio_pin! { + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 +} diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 5fea7034..154cc6b6 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -3,14 +3,13 @@ #![feature(type_alias_impl_trait)] use defmt::info; use embassy_executor::Spawner; -use embassy_rp::gpio::{AnyPin, Pin}; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection}; +use embassy_rp::pio::{Pio, PioCommon, PioPin, PioStateMachine, PioStateMachineInstance, ShiftDirection}; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use {defmt_rtt as _, panic_probe as _}; -fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachineInstance, pin: AnyPin) { +fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachineInstance, pin: impl PioPin) { // Setup sm0 // Send data serially to pin @@ -121,7 +120,7 @@ async fn main(spawner: Spawner) { .. } = Pio::new(pio); - setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0.degrade()); + setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0); setup_pio_task_sm1(&mut common, &mut sm1); setup_pio_task_sm2(&mut common, &mut sm2); spawner.spawn(pio_task_sm0(sm0)).unwrap(); diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 59b4c1f5..6d56bc23 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -6,9 +6,8 @@ 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::pio::{FifoJoin, Pio, PioPin, PioStateMachine, PioStateMachineInstance, ShiftDirection}; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{into_ref, Peripheral, PeripheralRef}; @@ -74,13 +73,13 @@ impl<'l> HD44780<'l> { pub async fn new( pio: impl Peripheral

+ 'l, dma: impl Peripheral

+ 'l, - rs: impl Pin, - rw: impl Pin, - e: impl Pin, - db4: impl Pin, - db5: impl Pin, - db6: impl Pin, - db7: impl Pin, + rs: impl PioPin, + rw: impl PioPin, + e: impl PioPin, + db4: impl PioPin, + db5: impl PioPin, + db6: impl PioPin, + db7: impl PioPin, ) -> HD44780<'l> { into_ref!(dma); diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 0975559d..8276fad6 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -4,9 +4,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::gpio::{self, Pin}; use embassy_rp::pio::{ - FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, + FifoJoin, Pio, PioCommon, PioInstance, PioPin, PioStateMachine, PioStateMachineInstance, ShiftDirection, }; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; @@ -18,7 +17,7 @@ pub struct Ws2812<'d, P: PioInstance, const S: usize> { } impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> { - pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self { + pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: impl PioPin) -> Self { // Setup sm0 // prepare the PIO program @@ -124,7 +123,7 @@ async fn main(_spawner: Spawner) { // For the thing plus, use pin 8 // For the feather, use pin 16 - let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8.degrade()); + let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8); // Loop forever making RGB values and pushing them out to the WS2812. loop { From 6ad58f428a42fd73377b6b8ec81315da06357049 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 08:46:08 +0200 Subject: [PATCH 05/11] rp/pio: wrap PioPins from ref, like everything else also store peripheral refs instead of a raw pin/bank number, like everything else. --- embassy-rp/src/pio.rs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 21223eaf..bb9bdb8a 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -6,13 +6,13 @@ use core::task::{Context, Poll}; use atomic_polyfill::{AtomicU32, AtomicU8}; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; -use embassy_hal_common::{Peripheral, PeripheralRef}; +use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use pac::io::vals::Gpio0ctrlFuncsel; use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; -use crate::gpio::{self, Drive, Pull, SlewRate}; +use crate::gpio::{self, AnyPin, Drive, Pull, SlewRate}; use crate::pac::dma::vals::TreqSel; use crate::pio::sealed::PioInstance as _; use crate::{interrupt, pac, peripherals, RegExt}; @@ -244,17 +244,17 @@ impl<'d, PIO: PioInstance> Drop for IrqFuture { } } -pub struct Pin { - pin_bank: u8, +pub struct Pin<'l, PIO: PioInstance> { + pin: PeripheralRef<'l, AnyPin>, pio: PhantomData, } -impl Pin { +impl<'l, PIO: PioInstance> Pin<'l, PIO> { /// Set the pin's drive strength. #[inline] pub fn set_drive_strength(&mut self, strength: Drive) { unsafe { - self.pad_ctrl().modify(|w| { + self.pin.pad_ctrl().modify(|w| { w.set_drive(match strength { Drive::_2mA => pac::pads::vals::Drive::_2MA, Drive::_4mA => pac::pads::vals::Drive::_4MA, @@ -269,7 +269,7 @@ impl Pin { #[inline] pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { unsafe { - self.pad_ctrl().modify(|w| { + self.pin.pad_ctrl().modify(|w| { w.set_slewfast(slew_rate == SlewRate::Fast); }); } @@ -279,7 +279,7 @@ impl Pin { #[inline] pub fn set_pull(&mut self, pull: Pull) { unsafe { - self.pad_ctrl().modify(|w| { + self.pin.pad_ctrl().modify(|w| { w.set_pue(pull == Pull::Up); w.set_pde(pull == Pull::Down); }); @@ -290,7 +290,7 @@ impl Pin { #[inline] pub fn set_schmitt(&mut self, enable: bool) { unsafe { - self.pad_ctrl().modify(|w| { + self.pin.pad_ctrl().modify(|w| { w.set_schmitt(enable); }); } @@ -308,13 +308,7 @@ impl Pin { } pub fn pin(&self) -> u8 { - self._pin() - } -} - -impl SealedPin for Pin { - fn pin_bank(&self) -> u8 { - self.pin_bank + self.pin._pin() } } @@ -890,14 +884,15 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { /// Register a pin for PIO usage. Pins will be released from the PIO block /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`PioCommon`] *and* /// all [`PioStateMachine`]s for this block have been dropped. - pub fn make_pio_pin(&mut self, pin: impl PioPin) -> Pin { + pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { + into_ref!(pin); unsafe { pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); } // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); Pin { - pin_bank: pin.pin_bank(), + pin: pin.into_ref().map_into(), pio: PhantomData::default(), } } From 79985f003646d379f2aea2738dc0291770e701c5 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 09:11:19 +0200 Subject: [PATCH 06/11] rp/pio: hide pio/sm numbers nothing should care which number pio it is running on, and the state machine index could always be extracted from type information. --- embassy-rp/src/pio.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index bb9bdb8a..ffd8d53d 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -332,14 +332,6 @@ impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioState impl<'d, PIO: PioInstance, const SM: usize> PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {} pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { - fn pio_no(&self) -> u8 { - Self::Pio::PIO_NO - } - - fn sm_no(&self) -> u8 { - Self::SM as u8 - } - fn restart(&mut self) { let mask = 1u8 << Self::SM; unsafe { @@ -981,11 +973,7 @@ mod sealed { } } -pub trait PioInstance: sealed::PioInstance + Sized + Unpin { - fn pio(&self) -> u8 { - Self::PIO_NO - } -} +pub trait PioInstance: sealed::PioInstance + Sized + Unpin {} macro_rules! impl_pio { ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { From 906d2b2db78d287ad818ab2a7abb1fec572ac6f6 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 09:42:42 +0200 Subject: [PATCH 07/11] rp/pio: PioStateMachine{Instance, => ,Instance} next step: get rid of the insance trait entirely --- embassy-rp/src/pio.rs | 44 +++++++++++++++--------------- embassy-rp/src/pio_instr_util.rs | 20 +++++++------- examples/rp/src/bin/pio_async.rs | 12 ++++---- examples/rp/src/bin/pio_dma.rs | 2 +- examples/rp/src/bin/pio_hd44780.rs | 2 +- examples/rp/src/bin/ws2812-pio.rs | 4 +-- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index ffd8d53d..a2e3d3a9 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -97,13 +97,13 @@ pub(crate) unsafe fn init() { /// 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> { +pub struct FifoOutFuture<'a, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> { sm: &'a mut SM, pio: PhantomData, value: u32, } -impl<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> FifoOutFuture<'a, PIO, SM> { +impl<'a, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> FifoOutFuture<'a, PIO, SM> { pub fn new(sm: &'a mut SM, value: u32) -> Self { FifoOutFuture { sm, @@ -113,7 +113,7 @@ impl<'a, PIO: PioInstance, SM: PioStateMachine + Unpin> FifoOutFuture<'a, PIO, S } } -impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture<'d, PIO, SM> { +impl<'d, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> Future for FifoOutFuture<'d, PIO, SM> { type Output = (); fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { //debug!("Poll {},{}", PIO::PIO_NO, SM); @@ -133,7 +133,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture } } -impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<'d, PIO, SM> { +impl<'d, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> Drop for FifoOutFuture<'d, PIO, SM> { fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { @@ -145,12 +145,12 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<' /// Future that waits for RX-FIFO to become readable #[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachine> { +pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachineInstance> { sm: &'a mut SM, pio: PhantomData, } -impl<'a, PIO: PioInstance, SM: PioStateMachine> FifoInFuture<'a, PIO, SM> { +impl<'a, PIO: PioInstance, SM: PioStateMachineInstance> FifoInFuture<'a, PIO, SM> { pub fn new(sm: &'a mut SM) -> Self { FifoInFuture { sm, @@ -159,7 +159,7 @@ impl<'a, PIO: PioInstance, SM: PioStateMachine> FifoInFuture<'a, PIO, SM> { } } -impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, SM> { +impl<'d, PIO: PioInstance, SM: PioStateMachineInstance> Future for FifoInFuture<'d, PIO, SM> { type Output = u32; fn poll(mut self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { //debug!("Poll {},{}", PIO::PIO_NO, SM); @@ -178,7 +178,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, } } -impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, SM> { +impl<'d, PIO: PioInstance, SM: PioStateMachineInstance> Drop for FifoInFuture<'d, PIO, SM> { fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { @@ -312,11 +312,11 @@ impl<'l, PIO: PioInstance> Pin<'l, PIO> { } } -pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> { +pub struct PioStateMachine<'d, PIO: PioInstance, const SM: usize> { pio: PhantomData<&'d PIO>, } -impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachineInstance<'d, PIO, SM> { +impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachine<'d, PIO, SM> { fn drop(&mut self) { unsafe { PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); @@ -325,13 +325,13 @@ impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachineInstance<'d, } } -impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { +impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachineInstance for PioStateMachine<'d, PIO, SM> { type Pio = PIO; const SM: usize = SM; } -impl<'d, PIO: PioInstance, const SM: usize> PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {} +impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineInstance for PioStateMachine<'d, PIO, SM> {} -pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { +pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unpin { fn restart(&mut self) { let mask = 1u8 << Self::SM; unsafe { @@ -892,10 +892,10 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { pub struct Pio<'d, PIO: PioInstance> { pub common: PioCommon<'d, PIO>, - pub sm0: PioStateMachineInstance<'d, PIO, 0>, - pub sm1: PioStateMachineInstance<'d, PIO, 1>, - pub sm2: PioStateMachineInstance<'d, PIO, 2>, - pub sm3: PioStateMachineInstance<'d, PIO, 3>, + pub sm0: PioStateMachine<'d, PIO, 0>, + pub sm1: PioStateMachine<'d, PIO, 1>, + pub sm2: PioStateMachine<'d, PIO, 2>, + pub sm3: PioStateMachine<'d, PIO, 3>, } impl<'d, PIO: PioInstance> Pio<'d, PIO> { @@ -907,10 +907,10 @@ impl<'d, PIO: PioInstance> Pio<'d, PIO> { instructions_used: 0, pio: PhantomData, }, - sm0: PioStateMachineInstance { pio: PhantomData }, - sm1: PioStateMachineInstance { pio: PhantomData }, - sm2: PioStateMachineInstance { pio: PhantomData }, - sm3: PioStateMachineInstance { pio: PhantomData }, + sm0: PioStateMachine { pio: PhantomData }, + sm1: PioStateMachine { pio: PhantomData }, + sm2: PioStateMachine { pio: PhantomData }, + sm3: PioStateMachine { pio: PhantomData }, } } } @@ -944,7 +944,7 @@ fn on_pio_drop() { mod sealed { use super::*; - pub trait PioStateMachine { + pub trait PioStateMachineInstance { type Pio: super::PioInstance; const SM: usize; diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio_instr_util.rs index ae26ff1d..f5e7d7ab 100644 --- a/embassy-rp/src/pio_instr_util.rs +++ b/embassy-rp/src/pio_instr_util.rs @@ -1,8 +1,8 @@ use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; -use crate::pio::PioStateMachine; +use crate::pio::PioStateMachineInstance; -pub fn set_x(sm: &mut SM, value: u32) { +pub fn set_x(sm: &mut SM, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::X, bit_count: 32, @@ -12,7 +12,7 @@ pub fn set_x(sm: &mut SM, value: u32) { sm.exec_instr(OUT); } -pub fn get_x(sm: &mut SM) -> u32 { +pub fn get_x(sm: &mut SM) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::X, bit_count: 32, @@ -22,7 +22,7 @@ pub fn get_x(sm: &mut SM) -> u32 { sm.pull_rx() } -pub fn set_y(sm: &mut SM, value: u32) { +pub fn set_y(sm: &mut SM, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::Y, bit_count: 32, @@ -32,7 +32,7 @@ pub fn set_y(sm: &mut SM, value: u32) { sm.exec_instr(OUT); } -pub fn get_y(sm: &mut SM) -> u32 { +pub fn get_y(sm: &mut SM) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::Y, bit_count: 32, @@ -43,7 +43,7 @@ pub fn get_y(sm: &mut SM) -> u32 { sm.pull_rx() } -pub fn set_pindir(sm: &mut SM, data: u8) { +pub fn set_pindir(sm: &mut SM, data: u8) { let set: u16 = InstructionOperands::SET { destination: SetDestination::PINDIRS, data, @@ -52,7 +52,7 @@ pub fn set_pindir(sm: &mut SM, data: u8) { sm.exec_instr(set); } -pub fn set_pin(sm: &mut SM, data: u8) { +pub fn set_pin(sm: &mut SM, data: u8) { let set: u16 = InstructionOperands::SET { destination: SetDestination::PINS, data, @@ -61,7 +61,7 @@ pub fn set_pin(sm: &mut SM, data: u8) { sm.exec_instr(set); } -pub fn set_out_pin(sm: &mut SM, data: u32) { +pub fn set_out_pin(sm: &mut SM, data: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::PINS, bit_count: 32, @@ -70,7 +70,7 @@ pub fn set_out_pin(sm: &mut SM, data: u32) { sm.push_tx(data); sm.exec_instr(OUT); } -pub fn set_out_pindir(sm: &mut SM, data: u32) { +pub fn set_out_pindir(sm: &mut SM, data: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::PINDIRS, bit_count: 32, @@ -80,7 +80,7 @@ pub fn set_out_pindir(sm: &mut SM, data: u32) { sm.exec_instr(OUT); } -pub fn exec_jmp(sm: &mut SM, to_addr: u8) { +pub fn exec_jmp(sm: &mut SM, to_addr: u8) { let jmp: u16 = InstructionOperands::JMP { address: to_addr, condition: JmpCondition::Always, diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 154cc6b6..8c02f9f1 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -9,7 +9,7 @@ use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use {defmt_rtt as _, panic_probe as _}; -fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachineInstance, pin: impl PioPin) { +fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachine, pin: impl PioPin) { // Setup sm0 // Send data serially to pin @@ -37,7 +37,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachineInstanc } #[embassy_executor::task] -async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) { +async fn pio_task_sm0(mut sm: PioStateMachine<'static, PIO0, 0>) { sm.set_enable(true); let mut v = 0x0f0caffa; @@ -48,7 +48,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) { } } -fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachine) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full @@ -67,7 +67,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachineInstanc } #[embassy_executor::task] -async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) { +async fn pio_task_sm1(mut sm: PioStateMachine<'static, PIO0, 1>) { sm.set_enable(true); loop { let rx = sm.wait_pull().await; @@ -75,7 +75,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) { } } -fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachine) { // Setup sm2 // Repeatedly trigger IRQ 3 @@ -99,7 +99,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachineInstanc } #[embassy_executor::task] -async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, 2>) { +async fn pio_task_sm2(mut sm: PioStateMachine<'static, PIO0, 2>) { sm.set_enable(true); loop { sm.wait_irq(3).await; diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 0f1f6df1..a351e2c7 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::{Pio, PioStateMachine, ShiftDirection}; +use embassy_rp::pio::{Pio, PioStateMachineInstance, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 6d56bc23..249711a3 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -64,7 +64,7 @@ async fn main(_spawner: Spawner) { pub struct HD44780<'l> { dma: PeripheralRef<'l, AnyChannel>, - sm: PioStateMachineInstance<'l, PIO0, 0>, + sm: PioStateMachine<'l, PIO0, 0>, buf: [u8; 40], } diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 8276fad6..c141560e 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -13,11 +13,11 @@ use embassy_time::{Duration, Timer}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; pub struct Ws2812<'d, P: PioInstance, const S: usize> { - sm: PioStateMachineInstance<'d, P, S>, + sm: PioStateMachine<'d, P, S>, } impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> { - pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: impl PioPin) -> Self { + pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachine<'d, P, S>, pin: impl PioPin) -> Self { // Setup sm0 // prepare the PIO program From 486fe9e59da7474c5162f56d89d5b6c279d02753 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 10:18:24 +0200 Subject: [PATCH 08/11] rp/pio: remove PioStateMachineInstance move all methods into PioStateMachine instead. the huge trait wasn't object-safe and thus didn't have any benefits whatsoever except for making it *slightly* easier to write bounds for passing around state machines. that would be much better solved with generics-less instances. --- embassy-rp/src/pio.rs | 271 +++++++++++++---------------- embassy-rp/src/pio_instr_util.rs | 20 +-- examples/rp/src/bin/pio_async.rs | 2 +- examples/rp/src/bin/pio_dma.rs | 2 +- examples/rp/src/bin/pio_hd44780.rs | 2 +- examples/rp/src/bin/ws2812-pio.rs | 4 +- 6 files changed, 138 insertions(+), 163 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index a2e3d3a9..52ef89a1 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -14,7 +14,6 @@ use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::{self, AnyPin, Drive, Pull, SlewRate}; use crate::pac::dma::vals::TreqSel; -use crate::pio::sealed::PioInstance as _; use crate::{interrupt, pac, peripherals, RegExt}; struct Wakers([AtomicWaker; 12]); @@ -97,23 +96,18 @@ pub(crate) unsafe fn init() { /// 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: PioStateMachineInstance + Unpin> { - sm: &'a mut SM, - pio: PhantomData, +pub struct FifoOutFuture<'a, 'd, PIO: PioInstance, const SM: usize> { + sm: &'a mut PioStateMachine<'d, PIO, SM>, value: u32, } -impl<'a, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> FifoOutFuture<'a, PIO, SM> { - pub fn new(sm: &'a mut SM, value: u32) -> Self { - FifoOutFuture { - sm, - pio: PhantomData::default(), - value, - } +impl<'a, 'd, PIO: PioInstance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> { + pub fn new(sm: &'a mut PioStateMachine<'d, PIO, SM>, value: u32) -> Self { + FifoOutFuture { sm, value } } } -impl<'d, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> Future for FifoOutFuture<'d, PIO, SM> { +impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoOutFuture<'a, 'd, PIO, SM> { type Output = (); fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { //debug!("Poll {},{}", PIO::PIO_NO, SM); @@ -121,10 +115,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> Future for FifoO if self.get_mut().sm.try_push_tx(value) { Poll::Ready(()) } else { - WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::SM as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); unsafe { PIO::PIO.irqs(0).inte().write_set(|m| { - m.0 = TXNFULL_MASK << SM::SM; + m.0 = TXNFULL_MASK << SM; }); } // debug!("Pending"); @@ -133,11 +127,11 @@ impl<'d, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> Future for FifoO } } -impl<'d, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> Drop for FifoOutFuture<'d, PIO, SM> { +impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> { fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { - m.0 = TXNFULL_MASK << SM::SM; + m.0 = TXNFULL_MASK << SM; }); } } @@ -145,31 +139,27 @@ impl<'d, PIO: PioInstance, SM: PioStateMachineInstance + Unpin> Drop for FifoOut /// Future that waits for RX-FIFO to become readable #[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct FifoInFuture<'a, PIO: PioInstance, SM: PioStateMachineInstance> { - sm: &'a mut SM, - pio: PhantomData, +pub struct FifoInFuture<'a, 'd, PIO: PioInstance, const SM: usize> { + sm: &'a mut PioStateMachine<'d, PIO, SM>, } -impl<'a, PIO: PioInstance, SM: PioStateMachineInstance> FifoInFuture<'a, PIO, SM> { - pub fn new(sm: &'a mut SM) -> Self { - FifoInFuture { - sm, - pio: PhantomData::default(), - } +impl<'a, 'd, PIO: PioInstance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> { + pub fn new(sm: &'a mut PioStateMachine<'d, PIO, SM>) -> Self { + FifoInFuture { sm } } } -impl<'d, PIO: PioInstance, SM: PioStateMachineInstance> Future for FifoInFuture<'d, PIO, SM> { +impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO, SM> { type Output = u32; fn poll(mut self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { //debug!("Poll {},{}", PIO::PIO_NO, SM); if let Some(v) = self.sm.try_pull_rx() { Poll::Ready(v) } else { - WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::SM].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); unsafe { PIO::PIO.irqs(0).inte().write_set(|m| { - m.0 = RXNEMPTY_MASK << SM::SM; + m.0 = RXNEMPTY_MASK << SM; }); } //debug!("Pending"); @@ -178,11 +168,11 @@ impl<'d, PIO: PioInstance, SM: PioStateMachineInstance> Future for FifoInFuture< } } -impl<'d, PIO: PioInstance, SM: PioStateMachineInstance> Drop for FifoInFuture<'d, PIO, SM> { +impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> { fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { - m.0 = RXNEMPTY_MASK << SM::SM; + m.0 = RXNEMPTY_MASK << SM; }); } } @@ -325,69 +315,68 @@ impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachine<'d, PIO, SM } } -impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachineInstance for PioStateMachine<'d, PIO, SM> { - type Pio = PIO; - const SM: usize = SM; -} -impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineInstance for PioStateMachine<'d, PIO, SM> {} +impl<'d, PIO: PioInstance + 'd, const SM: usize> PioStateMachine<'d, PIO, SM> { + #[inline(always)] + fn this_sm() -> crate::pac::pio::StateMachine { + PIO::PIO.sm(SM) + } -pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unpin { - fn restart(&mut self) { - let mask = 1u8 << Self::SM; + pub fn restart(&mut self) { + let mask = 1u8 << SM; unsafe { - Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); + PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); } } - fn set_enable(&mut self, enable: bool) { - let mask = 1u8 << Self::SM; + pub fn set_enable(&mut self, enable: bool) { + let mask = 1u8 << SM; unsafe { if enable { - Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); + PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); } else { - Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); + PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); } } } - fn is_enabled(&self) -> bool { - unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::SM) != 0 } + pub fn is_enabled(&self) -> bool { + unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } } - fn is_tx_empty(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::SM) != 0 } + pub fn is_tx_empty(&self) -> bool { + unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } } - fn is_tx_full(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::SM) != 0 } + pub fn is_tx_full(&self) -> bool { + unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } } - fn is_rx_empty(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::SM) != 0 } + pub fn is_rx_empty(&self) -> bool { + unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } } - fn is_rx_full(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::SM) != 0 } + pub fn is_rx_full(&self) -> bool { + unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } } - fn tx_level(&self) -> u8 { + pub fn tx_level(&self) -> u8 { unsafe { - let flevel = Self::Pio::PIO.flevel().read().0; - (flevel >> (Self::SM * 8)) as u8 & 0x0f + let flevel = PIO::PIO.flevel().read().0; + (flevel >> (SM * 8)) as u8 & 0x0f } } - fn rx_level(&self) -> u8 { + pub fn rx_level(&self) -> u8 { unsafe { - let flevel = Self::Pio::PIO.flevel().read().0; - (flevel >> (Self::SM * 8 + 4)) as u8 & 0x0f + let flevel = PIO::PIO.flevel().read().0; + (flevel >> (SM * 8 + 4)) as u8 & 0x0f } } - fn push_tx(&mut self, v: u32) { + pub fn push_tx(&mut self, v: u32) { unsafe { - Self::Pio::PIO.txf(Self::SM).write_value(v); + PIO::PIO.txf(SM).write_value(v); } } - fn try_push_tx(&mut self, v: u32) -> bool { + pub fn try_push_tx(&mut self, v: u32) -> bool { if self.is_tx_full() { return false; } @@ -395,65 +384,65 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp true } - fn pull_rx(&mut self) -> u32 { - unsafe { Self::Pio::PIO.rxf(Self::SM).read() } + pub fn pull_rx(&mut self) -> u32 { + unsafe { PIO::PIO.rxf(SM).read() } } - fn try_pull_rx(&mut self) -> Option { + pub fn try_pull_rx(&mut self) -> Option { if self.is_rx_empty() { return None; } Some(self.pull_rx()) } - fn set_clkdiv(&mut self, div_x_256: u32) { + pub fn set_clkdiv(&mut self, div_x_256: u32) { unsafe { Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8); } } - fn get_clkdiv(&self) -> u32 { + pub fn get_clkdiv(&self) -> u32 { unsafe { Self::this_sm().clkdiv().read().0 >> 8 } } - fn clkdiv_restart(&mut self) { - let mask = 1u8 << Self::SM; + pub fn clkdiv_restart(&mut self) { + let mask = 1u8 << SM; unsafe { - Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); + PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); } } - fn set_side_enable(&self, enable: bool) { + pub fn set_side_enable(&self, enable: bool) { unsafe { Self::this_sm().execctrl().modify(|w| w.set_side_en(enable)); } } - fn is_side_enabled(&self) -> bool { + pub fn is_side_enabled(&self) -> bool { unsafe { Self::this_sm().execctrl().read().side_en() } } - fn set_side_pindir(&mut self, pindir: bool) { + pub fn set_side_pindir(&mut self, pindir: bool) { unsafe { Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir)); } } - fn is_side_pindir(&self) -> bool { + pub fn is_side_pindir(&self) -> bool { unsafe { Self::this_sm().execctrl().read().side_pindir() } } - fn set_jmp_pin(&mut self, pin: u8) { + pub fn set_jmp_pin(&mut self, pin: u8) { unsafe { Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin)); } } - fn get_jmp_pin(&mut self) -> u8 { + pub fn get_jmp_pin(&mut self) -> u8 { unsafe { Self::this_sm().execctrl().read().jmp_pin() } } - fn set_wrap(&self, source: u8, target: u8) { + pub fn set_wrap(&self, source: u8, target: u8) { unsafe { Self::this_sm().execctrl().modify(|w| { w.set_wrap_top(source); @@ -463,14 +452,14 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } /// Get wrapping addresses. Returns (source, target). - fn get_wrap(&self) -> (u8, u8) { + pub fn get_wrap(&self) -> (u8, u8) { unsafe { let r = Self::this_sm().execctrl().read(); (r.wrap_top(), r.wrap_bottom()) } } - fn set_fifo_join(&mut self, join: FifoJoin) { + pub fn set_fifo_join(&mut self, join: FifoJoin) { let (rx, tx) = match join { FifoJoin::Duplex => (false, false), FifoJoin::RxOnly => (true, false), @@ -483,7 +472,7 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp }); } } - fn get_fifo_join(&self) -> FifoJoin { + pub fn get_fifo_join(&self) -> FifoJoin { unsafe { let r = Self::this_sm().shiftctrl().read(); // Ignores the invalid state when both bits are set @@ -497,7 +486,7 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } } - fn clear_fifos(&mut self) { + pub fn clear_fifos(&mut self) { // Toggle FJOIN_RX to flush FIFOs unsafe { let shiftctrl = Self::this_sm().shiftctrl(); @@ -510,33 +499,33 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } } - fn set_pull_threshold(&mut self, threshold: u8) { + pub fn set_pull_threshold(&mut self, threshold: u8) { unsafe { Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold)); } } - fn get_pull_threshold(&self) -> u8 { + pub fn get_pull_threshold(&self) -> u8 { unsafe { Self::this_sm().shiftctrl().read().pull_thresh() } } - fn set_push_threshold(&mut self, threshold: u8) { + pub fn set_push_threshold(&mut self, threshold: u8) { unsafe { Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold)); } } - fn get_push_threshold(&self) -> u8 { + pub fn get_push_threshold(&self) -> u8 { unsafe { Self::this_sm().shiftctrl().read().push_thresh() } } - fn set_out_shift_dir(&mut self, dir: ShiftDirection) { + pub fn set_out_shift_dir(&mut self, dir: ShiftDirection) { unsafe { Self::this_sm() .shiftctrl() .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); } } - fn get_out_shiftdir(&self) -> ShiftDirection { + pub fn get_out_shiftdir(&self) -> ShiftDirection { unsafe { if Self::this_sm().shiftctrl().read().out_shiftdir() { ShiftDirection::Right @@ -546,14 +535,14 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } } - fn set_in_shift_dir(&mut self, dir: ShiftDirection) { + pub fn set_in_shift_dir(&mut self, dir: ShiftDirection) { unsafe { Self::this_sm() .shiftctrl() .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); } } - fn get_in_shiftdir(&self) -> ShiftDirection { + pub fn get_in_shiftdir(&self) -> ShiftDirection { unsafe { if Self::this_sm().shiftctrl().read().in_shiftdir() { ShiftDirection::Right @@ -563,46 +552,46 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } } - fn set_autopull(&mut self, auto: bool) { + pub fn set_autopull(&mut self, auto: bool) { unsafe { Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto)); } } - fn is_autopull(&self) -> bool { + pub fn is_autopull(&self) -> bool { unsafe { Self::this_sm().shiftctrl().read().autopull() } } - fn set_autopush(&mut self, auto: bool) { + pub fn set_autopush(&mut self, auto: bool) { unsafe { Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto)); } } - fn is_autopush(&self) -> bool { + pub fn is_autopush(&self) -> bool { unsafe { Self::this_sm().shiftctrl().read().autopush() } } - fn get_addr(&self) -> u8 { + pub fn get_addr(&self) -> u8 { unsafe { Self::this_sm().addr().read().addr() } } - fn set_sideset_count(&mut self, count: u8) { + pub fn set_sideset_count(&mut self, count: u8) { unsafe { Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count)); } } - fn get_sideset_count(&self) -> u8 { + pub fn get_sideset_count(&self) -> u8 { unsafe { Self::this_sm().pinctrl().read().sideset_count() } } - fn set_sideset_base_pin(&mut self, base_pin: &Pin) { + pub fn set_sideset_base_pin(&mut self, base_pin: &Pin) { unsafe { Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin())); } } - fn get_sideset_base(&self) -> u8 { + pub fn get_sideset_base(&self) -> u8 { unsafe { let r = Self::this_sm().pinctrl().read(); r.sideset_base() @@ -610,7 +599,7 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } /// Set the range of out pins affected by a set instruction. - fn set_set_range(&mut self, base: u8, count: u8) { + pub fn set_set_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { Self::this_sm().pinctrl().modify(|w| { @@ -621,27 +610,27 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } /// Get the range of out pins affected by a set instruction. Returns (base, count). - fn get_set_range(&self) -> (u8, u8) { + pub fn get_set_range(&self) -> (u8, u8) { unsafe { let r = Self::this_sm().pinctrl().read(); (r.set_base(), r.set_count()) } } - fn set_in_base_pin(&mut self, base: &Pin) { + pub fn set_in_base_pin(&mut self, base: &Pin) { unsafe { Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin())); } } - fn get_in_base(&self) -> u8 { + pub fn get_in_base(&self) -> u8 { unsafe { let r = Self::this_sm().pinctrl().read(); r.in_base() } } - fn set_out_range(&mut self, base: u8, count: u8) { + pub fn set_out_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { Self::this_sm().pinctrl().modify(|w| { @@ -652,14 +641,14 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp } /// Get the range of out pins affected by a set instruction. Returns (base, count). - fn get_out_range(&self) -> (u8, u8) { + pub fn get_out_range(&self) -> (u8, u8) { unsafe { let r = Self::this_sm().pinctrl().read(); (r.out_base(), r.out_count()) } } - fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { + pub fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { let count = pins.len(); assert!(count >= 1); let start = pins[0].pin() as usize; @@ -670,7 +659,7 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp self.set_out_range(start as u8, count as u8); } - fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { + pub fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { let count = pins.len(); assert!(count >= 1); let start = pins[0].pin() as usize; @@ -681,76 +670,75 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp self.set_set_range(start as u8, count as u8); } - fn get_current_instr() -> u32 { + pub fn get_current_instr() -> u32 { unsafe { Self::this_sm().instr().read().0 } } - fn exec_instr(&mut self, instr: u16) { + pub fn exec_instr(&mut self, instr: u16) { unsafe { Self::this_sm().instr().write(|w| w.set_instr(instr)); } } - fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, Self::Pio, Self> { + pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> { FifoOutFuture::new(self, value) } - fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, Self::Pio, Self> { + pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> { FifoInFuture::new(self) } - fn wait_irq(&self, irq_no: u8) -> IrqFuture { + pub fn wait_irq(&self, irq_no: u8) -> IrqFuture { IrqFuture::new(irq_no) } - fn has_tx_stalled(&self) -> bool { + pub fn has_tx_stalled(&self) -> bool { unsafe { - let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().txstall() & (1 << Self::SM) != 0; - fdebug.write(|w| w.set_txstall(1 << Self::SM)); + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().txstall() & (1 << SM) != 0; + fdebug.write(|w| w.set_txstall(1 << SM)); ret } } - fn has_tx_overflowed(&self) -> bool { + pub fn has_tx_overflowed(&self) -> bool { unsafe { - let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().txover() & (1 << Self::SM) != 0; - fdebug.write(|w| w.set_txover(1 << Self::SM)); + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().txover() & (1 << SM) != 0; + fdebug.write(|w| w.set_txover(1 << SM)); ret } } - fn has_rx_stalled(&self) -> bool { + pub fn has_rx_stalled(&self) -> bool { unsafe { - let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().rxstall() & (1 << Self::SM) != 0; - fdebug.write(|w| w.set_rxstall(1 << Self::SM)); + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().rxstall() & (1 << SM) != 0; + fdebug.write(|w| w.set_rxstall(1 << SM)); ret } } - fn has_rx_underflowed(&self) -> bool { + pub fn has_rx_underflowed(&self) -> bool { unsafe { - let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().rxunder() & (1 << Self::SM) != 0; - fdebug.write(|w| w.set_rxunder(1 << Self::SM)); + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().rxunder() & (1 << SM) != 0; + fdebug.write(|w| w.set_rxunder(1 << SM)); ret } } - fn dma_push<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { + pub fn dma_push<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { unsafe { - let pio_no = Self::Pio::PIO_NO; - let sm_no = Self::SM; + let pio_no = PIO::PIO_NO; let p = ch.regs(); p.read_addr().write_value(data.as_ptr() as u32); - p.write_addr().write_value(Self::Pio::PIO.txf(sm_no).ptr() as u32); + p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); p.trans_count().write_value(data.len() as u32); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { // Set TX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8)); + w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(true); @@ -762,18 +750,17 @@ pub trait PioStateMachineInstance: sealed::PioStateMachineInstance + Sized + Unp Transfer::new(ch) } - fn dma_pull<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [W]) -> Transfer<'a, C> { + pub fn dma_pull<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [W]) -> Transfer<'a, C> { unsafe { - let pio_no = Self::Pio::PIO_NO; - let sm_no = Self::SM; + let pio_no = PIO::PIO_NO; let p = ch.regs(); p.write_addr().write_value(data.as_ptr() as u32); - p.read_addr().write_value(Self::Pio::PIO.rxf(sm_no).ptr() as u32); + p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); p.trans_count().write_value(data.len() as u32); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { // Set RX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + sm_no as u8 + 4)); + w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(false); @@ -944,16 +931,6 @@ fn on_pio_drop() { mod sealed { use super::*; - pub trait PioStateMachineInstance { - 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 PioPin {} pub trait PioInstance { diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio_instr_util.rs index f5e7d7ab..ffe16024 100644 --- a/embassy-rp/src/pio_instr_util.rs +++ b/embassy-rp/src/pio_instr_util.rs @@ -1,8 +1,8 @@ use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; -use crate::pio::PioStateMachineInstance; +use crate::pio::{PioInstance, PioStateMachine}; -pub fn set_x(sm: &mut SM, value: u32) { +pub fn set_x(sm: &mut PioStateMachine, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::X, bit_count: 32, @@ -12,7 +12,7 @@ pub fn set_x(sm: &mut SM, value: u32) { sm.exec_instr(OUT); } -pub fn get_x(sm: &mut SM) -> u32 { +pub fn get_x(sm: &mut PioStateMachine) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::X, bit_count: 32, @@ -22,7 +22,7 @@ pub fn get_x(sm: &mut SM) -> u32 { sm.pull_rx() } -pub fn set_y(sm: &mut SM, value: u32) { +pub fn set_y(sm: &mut PioStateMachine, value: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::Y, bit_count: 32, @@ -32,7 +32,7 @@ pub fn set_y(sm: &mut SM, value: u32) { sm.exec_instr(OUT); } -pub fn get_y(sm: &mut SM) -> u32 { +pub fn get_y(sm: &mut PioStateMachine) -> u32 { const IN: u16 = InstructionOperands::IN { source: InSource::Y, bit_count: 32, @@ -43,7 +43,7 @@ pub fn get_y(sm: &mut SM) -> u32 { sm.pull_rx() } -pub fn set_pindir(sm: &mut SM, data: u8) { +pub fn set_pindir(sm: &mut PioStateMachine, data: u8) { let set: u16 = InstructionOperands::SET { destination: SetDestination::PINDIRS, data, @@ -52,7 +52,7 @@ pub fn set_pindir(sm: &mut SM, data: u8) { sm.exec_instr(set); } -pub fn set_pin(sm: &mut SM, data: u8) { +pub fn set_pin(sm: &mut PioStateMachine, data: u8) { let set: u16 = InstructionOperands::SET { destination: SetDestination::PINS, data, @@ -61,7 +61,7 @@ pub fn set_pin(sm: &mut SM, data: u8) { sm.exec_instr(set); } -pub fn set_out_pin(sm: &mut SM, data: u32) { +pub fn set_out_pin(sm: &mut PioStateMachine, data: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::PINS, bit_count: 32, @@ -70,7 +70,7 @@ pub fn set_out_pin(sm: &mut SM, data: u32) { sm.push_tx(data); sm.exec_instr(OUT); } -pub fn set_out_pindir(sm: &mut SM, data: u32) { +pub fn set_out_pindir(sm: &mut PioStateMachine, data: u32) { const OUT: u16 = InstructionOperands::OUT { destination: OutDestination::PINDIRS, bit_count: 32, @@ -80,7 +80,7 @@ pub fn set_out_pindir(sm: &mut SM, data: u32) { sm.exec_instr(OUT); } -pub fn exec_jmp(sm: &mut SM, to_addr: u8) { +pub fn exec_jmp(sm: &mut PioStateMachine, to_addr: u8) { let jmp: u16 = InstructionOperands::JMP { address: to_addr, condition: JmpCondition::Always, diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 8c02f9f1..11b29086 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Pio, PioCommon, PioPin, PioStateMachine, PioStateMachineInstance, ShiftDirection}; +use embassy_rp::pio::{Pio, PioCommon, PioPin, PioStateMachine, ShiftDirection}; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index a351e2c7..a2a2ee39 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::{Pio, PioStateMachineInstance, ShiftDirection}; +use embassy_rp::pio::{Pio, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 249711a3..bc51d43c 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -7,7 +7,7 @@ use core::fmt::Write; use embassy_executor::Spawner; use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{FifoJoin, Pio, PioPin, PioStateMachine, PioStateMachineInstance, ShiftDirection}; +use embassy_rp::pio::{FifoJoin, Pio, PioPin, PioStateMachine, ShiftDirection}; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{into_ref, Peripheral, PeripheralRef}; diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index c141560e..713e01b4 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -4,9 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::pio::{ - FifoJoin, Pio, PioCommon, PioInstance, PioPin, PioStateMachine, PioStateMachineInstance, ShiftDirection, -}; +use embassy_rp::pio::{FifoJoin, Pio, PioCommon, PioInstance, PioPin, PioStateMachine, ShiftDirection}; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use embassy_time::{Duration, Timer}; From 909a5fe2e513ef91129a29ccdd8772824879383c Mon Sep 17 00:00:00 2001 From: pennae Date: Thu, 27 Apr 2023 02:12:49 +0200 Subject: [PATCH 09/11] rp/pio: split irqs from state machines we can only have one active waiter for any given irq at any given time. allowing waits for irqs on state machines bypasses this limitation and causes lost events for all but the latest waiter for a given irq. splitting this out also allows us to signal from state machines to other parts of the application without monopolizing state machine access for the irq wait, as would be necessary to make irq waiting sound. --- embassy-rp/src/pio.rs | 45 ++++++++++++++++++------------ examples/rp/src/bin/pio_async.rs | 9 +++--- examples/rp/src/bin/pio_hd44780.rs | 7 +++-- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 52ef89a1..769641ac 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -180,21 +180,12 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoInFuture<'a, 'd, PI /// Future that waits for IRQ #[must_use = "futures do nothing unless you `.await` or poll them"] -pub struct IrqFuture { - pio: PhantomData, +pub struct IrqFuture<'a, 'd, PIO: PioInstance> { + pio: PhantomData<&'a PioIrq<'d, PIO, 0>>, irq_no: u8, } -impl<'a, PIO: PioInstance> IrqFuture { - pub fn new(irq_no: u8) -> Self { - IrqFuture { - pio: PhantomData::default(), - irq_no, - } - } -} - -impl<'d, PIO: PioInstance> Future for IrqFuture { +impl<'a, 'd, PIO: PioInstance> Future for IrqFuture<'a, 'd, PIO> { type Output = (); fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { //debug!("Poll {},{}", PIO::PIO_NO, SM); @@ -224,7 +215,7 @@ impl<'d, PIO: PioInstance> Future for IrqFuture { } } -impl<'d, PIO: PioInstance> Drop for IrqFuture { +impl<'a, 'd, PIO: PioInstance> Drop for IrqFuture<'a, 'd, PIO> { fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { @@ -688,10 +679,6 @@ impl<'d, PIO: PioInstance + 'd, const SM: usize> PioStateMachine<'d, PIO, SM> { FifoInFuture::new(self) } - pub fn wait_irq(&self, irq_no: u8) -> IrqFuture { - IrqFuture::new(irq_no) - } - pub fn has_tx_stalled(&self) -> bool { unsafe { let fdebug = PIO::PIO.fdebug(); @@ -862,7 +849,8 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { /// Register a pin for PIO usage. Pins will be released from the PIO block /// (i.e., have their `FUNCSEL` reset to `NULL`) when the [`PioCommon`] *and* - /// all [`PioStateMachine`]s for this block have been dropped. + /// all [`PioStateMachine`]s for this block have been dropped. **Other members + /// of [`Pio`] do not keep pin registrations alive.** pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); unsafe { @@ -877,8 +865,25 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { } } +pub struct PioIrq<'d, PIO: PioInstance, const N: usize> { + pio: PhantomData<&'d PIO>, +} + +impl<'d, PIO: PioInstance, const N: usize> PioIrq<'d, PIO, N> { + pub fn wait<'a>(&'a mut self) -> IrqFuture<'a, 'd, PIO> { + IrqFuture { + pio: PhantomData, + irq_no: N as u8, + } + } +} + pub struct Pio<'d, PIO: PioInstance> { pub common: PioCommon<'d, PIO>, + pub irq0: PioIrq<'d, PIO, 0>, + pub irq1: PioIrq<'d, PIO, 1>, + pub irq2: PioIrq<'d, PIO, 2>, + pub irq3: PioIrq<'d, PIO, 3>, pub sm0: PioStateMachine<'d, PIO, 0>, pub sm1: PioStateMachine<'d, PIO, 1>, pub sm2: PioStateMachine<'d, PIO, 2>, @@ -894,6 +899,10 @@ impl<'d, PIO: PioInstance> Pio<'d, PIO> { instructions_used: 0, pio: PhantomData, }, + irq0: PioIrq { pio: PhantomData }, + irq1: PioIrq { pio: PhantomData }, + irq2: PioIrq { pio: PhantomData }, + irq3: PioIrq { pio: PhantomData }, sm0: PioStateMachine { pio: PhantomData }, sm1: PioStateMachine { pio: PhantomData }, sm2: PioStateMachine { pio: PhantomData }, diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 11b29086..3d76a7d7 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -4,7 +4,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Pio, PioCommon, PioPin, PioStateMachine, ShiftDirection}; +use embassy_rp::pio::{Pio, PioCommon, PioIrq, PioPin, PioStateMachine, ShiftDirection}; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; use {defmt_rtt as _, panic_probe as _}; @@ -99,10 +99,10 @@ fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachine) { +async fn pio_task_sm2(mut irq: PioIrq<'static, PIO0, 3>, mut sm: PioStateMachine<'static, PIO0, 2>) { sm.set_enable(true); loop { - sm.wait_irq(3).await; + irq.wait().await; info!("IRQ trigged"); } } @@ -114,6 +114,7 @@ async fn main(spawner: Spawner) { let Pio { mut common, + irq3, mut sm0, mut sm1, mut sm2, @@ -125,5 +126,5 @@ async fn main(spawner: Spawner) { setup_pio_task_sm2(&mut common, &mut sm2); spawner.spawn(pio_task_sm0(sm0)).unwrap(); spawner.spawn(pio_task_sm1(sm1)).unwrap(); - spawner.spawn(pio_task_sm2(sm2)).unwrap(); + spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap(); } diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index bc51d43c..7c1d7acf 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -85,7 +85,10 @@ impl<'l> HD44780<'l> { let db7pin = db7.pin(); let Pio { - mut common, mut sm0, .. + mut common, + mut irq0, + mut sm0, + .. } = Pio::new(pio); // takes command words ( <0:4>) @@ -145,7 +148,7 @@ impl<'l> HD44780<'l> { sm0.push_tx((50 << 8) | 0x20); sm0.push_tx(0b1100_0000); - sm0.wait_irq(0).await; + irq0.wait().await; sm0.set_enable(false); // takes command sequences ( , data...) From 77f7830da396b8666600a39e860c46ddde395f04 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 10:51:50 +0200 Subject: [PATCH 10/11] rp/pio: move irq flag handling to own struct this way we can share irq handling between state machines and common without having to duplicate the methods. it also lets us give irq flag access to places without having to dedicate a state machine or the common instance to those places, which can be very useful to eg trigger an event and wait for a confirmation using an irq wait object. --- embassy-rp/src/pio.rs | 62 ++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 769641ac..3c5969db 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -811,28 +811,6 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { self.instructions_used &= !instrs.used_mask; } - pub fn is_irq_set(&self, irq_no: u8) -> bool { - assert!(irq_no < 8); - unsafe { - let irq_flags = PIO::PIO.irq(); - irq_flags.read().0 & (1 << irq_no) != 0 - } - } - - pub fn clear_irq(&mut self, irq_no: usize) { - assert!(irq_no < 8); - unsafe { PIO::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } - } - - pub fn clear_irqs(&mut self, mask: u8) { - unsafe { PIO::PIO.irq().write(|w| w.set_irq(mask)) } - } - - pub fn force_irq(&mut self, irq_no: usize) { - assert!(irq_no < 8); - unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } - } - pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { unsafe { // this can interfere with per-pin bypass functions. splitting the @@ -878,8 +856,47 @@ impl<'d, PIO: PioInstance, const N: usize> PioIrq<'d, PIO, N> { } } +#[derive(Clone)] +pub struct PioIrqFlags<'d, PIO: PioInstance> { + pio: PhantomData<&'d PIO>, +} + +impl<'d, PIO: PioInstance> PioIrqFlags<'d, PIO> { + pub fn check(&self, irq_no: u8) -> bool { + assert!(irq_no < 8); + self.check_any(1 << irq_no) + } + + pub fn check_any(&self, irqs: u8) -> bool { + unsafe { PIO::PIO.irq().read().irq() & irqs != 0 } + } + + pub fn check_all(&self, irqs: u8) -> bool { + unsafe { PIO::PIO.irq().read().irq() & irqs == irqs } + } + + pub fn clear(&self, irq_no: usize) { + assert!(irq_no < 8); + self.clear_all(1 << irq_no); + } + + pub fn clear_all(&self, irqs: u8) { + unsafe { PIO::PIO.irq().write(|w| w.set_irq(irqs)) } + } + + pub fn set(&self, irq_no: usize) { + assert!(irq_no < 8); + self.set_all(1 << irq_no); + } + + pub fn set_all(&self, irqs: u8) { + unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) } + } +} + pub struct Pio<'d, PIO: PioInstance> { pub common: PioCommon<'d, PIO>, + pub irq_flags: PioIrqFlags<'d, PIO>, pub irq0: PioIrq<'d, PIO, 0>, pub irq1: PioIrq<'d, PIO, 1>, pub irq2: PioIrq<'d, PIO, 2>, @@ -899,6 +916,7 @@ impl<'d, PIO: PioInstance> Pio<'d, PIO> { instructions_used: 0, pio: PhantomData, }, + irq_flags: PioIrqFlags { pio: PhantomData }, irq0: PioIrq { pio: PhantomData }, irq1: PioIrq { pio: PhantomData }, irq2: PioIrq { pio: PhantomData }, From c44c108db57cbe34e21411054840f61c61efa8a8 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 3 May 2023 12:49:55 +0200 Subject: [PATCH 11/11] rp/pio: wrap sm rx, tx in structs and allow splitting this *finally* allows sound implementions of bidirectional transfers without blocking. the futures previously allowed only a single direction to be active at any given time, and the dma transfers didn't take a mutable reference and were thus unsound. --- embassy-rp/src/pio.rs | 334 ++++++++++++++++------------- embassy-rp/src/pio_instr_util.rs | 12 +- examples/rp/src/bin/pio_async.rs | 4 +- examples/rp/src/bin/pio_dma.rs | 5 +- examples/rp/src/bin/pio_hd44780.rs | 16 +- examples/rp/src/bin/ws2812-pio.rs | 2 +- 6 files changed, 204 insertions(+), 169 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 3c5969db..2cf4761a 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -97,13 +97,13 @@ pub(crate) unsafe fn init() { /// Future that waits for TX-FIFO to become writable #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct FifoOutFuture<'a, 'd, PIO: PioInstance, const SM: usize> { - sm: &'a mut PioStateMachine<'d, PIO, SM>, + sm_tx: &'a mut PioStateMachineTx<'d, PIO, SM>, value: u32, } impl<'a, 'd, PIO: PioInstance, const SM: usize> FifoOutFuture<'a, 'd, PIO, SM> { - pub fn new(sm: &'a mut PioStateMachine<'d, PIO, SM>, value: u32) -> Self { - FifoOutFuture { sm, value } + pub fn new(sm: &'a mut PioStateMachineTx<'d, PIO, SM>, value: u32) -> Self { + FifoOutFuture { sm_tx: sm, value } } } @@ -112,7 +112,7 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoOutFuture<'a, 'd, fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { //debug!("Poll {},{}", PIO::PIO_NO, SM); let value = self.value; - if self.get_mut().sm.try_push_tx(value) { + if self.get_mut().sm_tx.try_push(value) { Poll::Ready(()) } else { WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker()); @@ -140,12 +140,12 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Drop for FifoOutFuture<'a, 'd, P /// Future that waits for RX-FIFO to become readable #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct FifoInFuture<'a, 'd, PIO: PioInstance, const SM: usize> { - sm: &'a mut PioStateMachine<'d, PIO, SM>, + sm_rx: &'a mut PioStateMachineRx<'d, PIO, SM>, } impl<'a, 'd, PIO: PioInstance, const SM: usize> FifoInFuture<'a, 'd, PIO, SM> { - pub fn new(sm: &'a mut PioStateMachine<'d, PIO, SM>) -> Self { - FifoInFuture { sm } + pub fn new(sm: &'a mut PioStateMachineRx<'d, PIO, SM>) -> Self { + FifoInFuture { sm_rx: sm } } } @@ -153,7 +153,7 @@ impl<'a, 'd, PIO: PioInstance, const SM: usize> Future for FifoInFuture<'a, 'd, type Output = u32; fn poll(mut self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll { //debug!("Poll {},{}", PIO::PIO_NO, SM); - if let Some(v) = self.sm.try_pull_rx() { + if let Some(v) = self.sm_rx.try_pull() { Poll::Ready(v) } else { WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker()); @@ -293,10 +293,163 @@ impl<'l, PIO: PioInstance> Pin<'l, PIO> { } } -pub struct PioStateMachine<'d, PIO: PioInstance, const SM: usize> { +pub struct PioStateMachineRx<'d, PIO: PioInstance, const SM: usize> { pio: PhantomData<&'d PIO>, } +impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineRx<'d, PIO, SM> { + pub fn empty(&self) -> bool { + unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } + } + + pub fn full(&self) -> bool { + unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } + } + + pub fn level(&self) -> u8 { + unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } + } + + pub fn stalled(&self) -> bool { + unsafe { + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().rxstall() & (1 << SM) != 0; + fdebug.write(|w| w.set_rxstall(1 << SM)); + ret + } + } + + pub fn underflowed(&self) -> bool { + unsafe { + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().rxunder() & (1 << SM) != 0; + fdebug.write(|w| w.set_rxunder(1 << SM)); + ret + } + } + + pub fn pull(&mut self) -> u32 { + unsafe { PIO::PIO.rxf(SM).read() } + } + + pub fn try_pull(&mut self) -> Option { + if self.empty() { + return None; + } + Some(self.pull()) + } + + pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> { + FifoInFuture::new(self) + } + + pub fn dma_pull<'a, C: Channel, W: Word>( + &'a mut self, + ch: PeripheralRef<'a, C>, + data: &'a mut [W], + ) -> Transfer<'a, C> { + unsafe { + let pio_no = PIO::PIO_NO; + let p = ch.regs(); + p.write_addr().write_value(data.as_ptr() as u32); + p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); + p.trans_count().write_value(data.len() as u32); + compiler_fence(Ordering::SeqCst); + p.ctrl_trig().write(|w| { + // Set RX DREQ for this statemachine + w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); + w.set_data_size(W::size()); + w.set_chain_to(ch.number()); + w.set_incr_read(false); + w.set_incr_write(true); + w.set_en(true); + }); + compiler_fence(Ordering::SeqCst); + } + Transfer::new(ch) + } +} + +pub struct PioStateMachineTx<'d, PIO: PioInstance, const SM: usize> { + pio: PhantomData<&'d PIO>, +} + +impl<'d, PIO: PioInstance, const SM: usize> PioStateMachineTx<'d, PIO, SM> { + pub fn empty(&self) -> bool { + unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } + } + pub fn full(&self) -> bool { + unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } + } + + pub fn level(&self) -> u8 { + unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } + } + + pub fn stalled(&self) -> bool { + unsafe { + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().txstall() & (1 << SM) != 0; + fdebug.write(|w| w.set_txstall(1 << SM)); + ret + } + } + + pub fn overflowed(&self) -> bool { + unsafe { + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().txover() & (1 << SM) != 0; + fdebug.write(|w| w.set_txover(1 << SM)); + ret + } + } + + pub fn push(&mut self, v: u32) { + unsafe { + PIO::PIO.txf(SM).write_value(v); + } + } + + pub fn try_push(&mut self, v: u32) -> bool { + if self.full() { + return false; + } + self.push(v); + true + } + + pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> { + FifoOutFuture::new(self, value) + } + + pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { + unsafe { + let pio_no = PIO::PIO_NO; + let p = ch.regs(); + p.read_addr().write_value(data.as_ptr() as u32); + p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); + p.trans_count().write_value(data.len() as u32); + compiler_fence(Ordering::SeqCst); + p.ctrl_trig().write(|w| { + // Set TX DREQ for this statemachine + w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); + w.set_data_size(W::size()); + w.set_chain_to(ch.number()); + w.set_incr_read(true); + w.set_incr_write(false); + w.set_en(true); + }); + compiler_fence(Ordering::SeqCst); + } + Transfer::new(ch) + } +} + +pub struct PioStateMachine<'d, PIO: PioInstance, const SM: usize> { + rx: PioStateMachineRx<'d, PIO, SM>, + tx: PioStateMachineTx<'d, PIO, SM>, +} + impl<'d, PIO: PioInstance, const SM: usize> Drop for PioStateMachine<'d, PIO, SM> { fn drop(&mut self) { unsafe { @@ -333,59 +486,6 @@ impl<'d, PIO: PioInstance + 'd, const SM: usize> PioStateMachine<'d, PIO, SM> { unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } } - pub fn is_tx_empty(&self) -> bool { - unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 } - } - pub fn is_tx_full(&self) -> bool { - unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 } - } - - pub fn is_rx_empty(&self) -> bool { - unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 } - } - pub fn is_rx_full(&self) -> bool { - unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } - } - - pub fn tx_level(&self) -> u8 { - unsafe { - let flevel = PIO::PIO.flevel().read().0; - (flevel >> (SM * 8)) as u8 & 0x0f - } - } - - pub fn rx_level(&self) -> u8 { - unsafe { - let flevel = PIO::PIO.flevel().read().0; - (flevel >> (SM * 8 + 4)) as u8 & 0x0f - } - } - - pub fn push_tx(&mut self, v: u32) { - unsafe { - PIO::PIO.txf(SM).write_value(v); - } - } - - pub fn try_push_tx(&mut self, v: u32) -> bool { - if self.is_tx_full() { - return false; - } - self.push_tx(v); - true - } - - pub fn pull_rx(&mut self) -> u32 { - unsafe { PIO::PIO.rxf(SM).read() } - } - - pub fn try_pull_rx(&mut self) -> Option { - if self.is_rx_empty() { - return None; - } - Some(self.pull_rx()) - } - pub fn set_clkdiv(&mut self, div_x_256: u32) { unsafe { Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8); @@ -671,92 +771,14 @@ impl<'d, PIO: PioInstance + 'd, const SM: usize> PioStateMachine<'d, PIO, SM> { } } - pub fn wait_push<'a>(&'a mut self, value: u32) -> FifoOutFuture<'a, 'd, PIO, SM> { - FifoOutFuture::new(self, value) + pub fn rx(&mut self) -> &mut PioStateMachineRx<'d, PIO, SM> { + &mut self.rx } - - pub fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, 'd, PIO, SM> { - FifoInFuture::new(self) + pub fn tx(&mut self) -> &mut PioStateMachineTx<'d, PIO, SM> { + &mut self.tx } - - pub fn has_tx_stalled(&self) -> bool { - unsafe { - let fdebug = PIO::PIO.fdebug(); - let ret = fdebug.read().txstall() & (1 << SM) != 0; - fdebug.write(|w| w.set_txstall(1 << SM)); - ret - } - } - - pub fn has_tx_overflowed(&self) -> bool { - unsafe { - let fdebug = PIO::PIO.fdebug(); - let ret = fdebug.read().txover() & (1 << SM) != 0; - fdebug.write(|w| w.set_txover(1 << SM)); - ret - } - } - - pub fn has_rx_stalled(&self) -> bool { - unsafe { - let fdebug = PIO::PIO.fdebug(); - let ret = fdebug.read().rxstall() & (1 << SM) != 0; - fdebug.write(|w| w.set_rxstall(1 << SM)); - ret - } - } - - pub fn has_rx_underflowed(&self) -> bool { - unsafe { - let fdebug = PIO::PIO.fdebug(); - let ret = fdebug.read().rxunder() & (1 << SM) != 0; - fdebug.write(|w| w.set_rxunder(1 << SM)); - ret - } - } - - pub fn dma_push<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> { - unsafe { - let pio_no = PIO::PIO_NO; - let p = ch.regs(); - p.read_addr().write_value(data.as_ptr() as u32); - p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32); - p.trans_count().write_value(data.len() as u32); - compiler_fence(Ordering::SeqCst); - p.ctrl_trig().write(|w| { - // Set TX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8)); - w.set_data_size(W::size()); - w.set_chain_to(ch.number()); - w.set_incr_read(true); - w.set_incr_write(false); - w.set_en(true); - }); - compiler_fence(Ordering::SeqCst); - } - Transfer::new(ch) - } - - pub fn dma_pull<'a, C: Channel, W: Word>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [W]) -> Transfer<'a, C> { - unsafe { - let pio_no = PIO::PIO_NO; - let p = ch.regs(); - p.write_addr().write_value(data.as_ptr() as u32); - p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32); - p.trans_count().write_value(data.len() as u32); - compiler_fence(Ordering::SeqCst); - p.ctrl_trig().write(|w| { - // Set RX DREQ for this statemachine - w.set_treq_sel(TreqSel(pio_no * 8 + SM as u8 + 4)); - w.set_data_size(W::size()); - w.set_chain_to(ch.number()); - w.set_incr_read(false); - w.set_incr_write(true); - w.set_en(true); - }); - compiler_fence(Ordering::SeqCst); - } - Transfer::new(ch) + pub fn rx_tx(&mut self) -> (&mut PioStateMachineRx<'d, PIO, SM>, &mut PioStateMachineTx<'d, PIO, SM>) { + (&mut self.rx, &mut self.tx) } } @@ -921,10 +943,22 @@ impl<'d, PIO: PioInstance> Pio<'d, PIO> { irq1: PioIrq { pio: PhantomData }, irq2: PioIrq { pio: PhantomData }, irq3: PioIrq { pio: PhantomData }, - sm0: PioStateMachine { pio: PhantomData }, - sm1: PioStateMachine { pio: PhantomData }, - sm2: PioStateMachine { pio: PhantomData }, - sm3: PioStateMachine { pio: PhantomData }, + sm0: PioStateMachine { + rx: PioStateMachineRx { pio: PhantomData }, + tx: PioStateMachineTx { pio: PhantomData }, + }, + sm1: PioStateMachine { + rx: PioStateMachineRx { pio: PhantomData }, + tx: PioStateMachineTx { pio: PhantomData }, + }, + sm2: PioStateMachine { + rx: PioStateMachineRx { pio: PhantomData }, + tx: PioStateMachineTx { pio: PhantomData }, + }, + sm3: PioStateMachine { + rx: PioStateMachineRx { pio: PhantomData }, + tx: PioStateMachineTx { pio: PhantomData }, + }, } } } diff --git a/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio_instr_util.rs index ffe16024..81abdb66 100644 --- a/embassy-rp/src/pio_instr_util.rs +++ b/embassy-rp/src/pio_instr_util.rs @@ -8,7 +8,7 @@ pub fn set_x(sm: &mut PioStateMachine(sm: &mut PioStateMachine(sm: &mut PioStateMachine, value: u32) { @@ -28,7 +28,7 @@ pub fn set_y(sm: &mut PioStateMachine(sm: &mut PioStateMachine(sm: &mut PioStateMachine, data: u8) { @@ -67,7 +67,7 @@ pub fn set_out_pin(sm: &mut PioStateMachine

(sm: &mut PioStateMachine, data: u32) { @@ -76,7 +76,7 @@ pub fn set_out_pindir(sm: &mut PioStateMachin bit_count: 32, } .encode(); - sm.push_tx(data); + sm.tx().push(data); sm.exec_instr(OUT); } diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 3d76a7d7..4e0ab5e3 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -42,7 +42,7 @@ async fn pio_task_sm0(mut sm: PioStateMachine<'static, PIO0, 0>) { let mut v = 0x0f0caffa; loop { - sm.wait_push(v).await; + sm.tx().wait_push(v).await; v ^= 0xffff; info!("Pushed {:032b} to FIFO", v); } @@ -70,7 +70,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachine) { sm.set_enable(true); loop { - let rx = sm.wait_pull().await; + let rx = sm.rx().wait_pull().await; info!("Pulled {:032b} from FIFO", rx); } } diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index a2a2ee39..c664482e 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -60,9 +60,10 @@ async fn main(_spawner: Spawner) { } let mut din = [0u32; 29]; loop { + let (rx, tx) = sm.rx_tx(); join( - sm.dma_push(dma_out_ref.reborrow(), &dout), - sm.dma_pull(dma_in_ref.reborrow(), &mut din), + tx.dma_push(dma_out_ref.reborrow(), &dout), + rx.dma_pull(dma_in_ref.reborrow(), &mut din), ) .await; for i in 0..din.len() { diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 7c1d7acf..f76d334e 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -139,14 +139,14 @@ impl<'l> HD44780<'l> { 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); + sm0.tx().push((50000 << 8) | 0x30); + sm0.tx().push((5000 << 8) | 0x30); + sm0.tx().push((200 << 8) | 0x30); // init 4 bit - sm0.push_tx((200 << 8) | 0x20); + sm0.tx().push((200 << 8) | 0x20); // set font and lines - sm0.push_tx((50 << 8) | 0x20); - sm0.push_tx(0b1100_0000); + sm0.tx().push((50 << 8) | 0x20); + sm0.tx().push(0b1100_0000); irq0.wait().await; sm0.set_enable(false); @@ -216,7 +216,7 @@ impl<'l> HD44780<'l> { sm0.set_enable(true); // display on and cursor on and blinking, reset display - sm0.dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; + sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; Self { dma: dma.map_into(), @@ -240,6 +240,6 @@ impl<'l> HD44780<'l> { // set cursor to 1:15 self.buf[38..].copy_from_slice(&[0x80, 0xcf]); - self.sm.dma_push(self.dma.reborrow(), &self.buf).await; + self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; } } diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 713e01b4..c9c701a7 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -87,7 +87,7 @@ impl<'d, P: PioInstance, const S: usize> Ws2812<'d, P, S> { pub async fn write(&mut self, colors: &[RGB8]) { for color in colors { let word = (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); - self.sm.wait_push(word).await; + self.sm.tx().wait_push(word).await; } } }