diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 5433d3f2..2cf4761a 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -4,15 +4,16 @@ 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_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::{Drive, Pin, 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}; struct Wakers([AtomicWaker; 12]); @@ -95,34 +96,29 @@ 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> { - sm: &'a mut SM, - pio: PhantomData, +pub struct FifoOutFuture<'a, 'd, PIO: PioInstance, const SM: usize> { + sm_tx: &'a mut PioStateMachineTx<'d, PIO, SM>, value: u32, } -impl<'a, PIO: PioInstance, SM: PioStateMachine + 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 PioStateMachineTx<'d, PIO, SM>, value: u32) -> Self { + FifoOutFuture { sm_tx: sm, value } } } -impl<'d, PIO: PioInstance, SM: PioStateMachine + 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); 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::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"); @@ -131,11 +127,11 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture } } -impl<'d, PIO: PioInstance, SM: PioStateMachine + 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; }); } } @@ -143,31 +139,27 @@ 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> { - sm: &'a mut SM, - pio: PhantomData, +pub struct FifoInFuture<'a, 'd, PIO: PioInstance, const SM: usize> { + sm_rx: &'a mut PioStateMachineRx<'d, PIO, SM>, } -impl<'a, PIO: PioInstance, SM: PioStateMachine> 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 PioStateMachineRx<'d, PIO, SM>) -> Self { + FifoInFuture { sm_rx: sm } } } -impl<'d, PIO: PioInstance, SM: PioStateMachine> 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() { + if let Some(v) = self.sm_rx.try_pull() { 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"); @@ -176,11 +168,11 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, } } -impl<'d, PIO: PioInstance, SM: PioStateMachine> 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; }); } } @@ -188,21 +180,12 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S /// 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); @@ -232,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| { @@ -242,17 +225,17 @@ impl<'d, PIO: PioInstance> Drop for IrqFuture { } } -pub struct PioPin { - pin_bank: u8, +pub struct Pin<'l, PIO: PioInstance> { + pin: PeripheralRef<'l, AnyPin>, pio: PhantomData, } -impl PioPin { +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, @@ -267,7 +250,7 @@ impl PioPin { #[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); }); } @@ -277,7 +260,7 @@ impl PioPin { #[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); }); @@ -288,7 +271,7 @@ impl PioPin { #[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); }); } @@ -306,157 +289,251 @@ impl PioPin { } pub fn pin(&self) -> u8 { - self._pin() + self.pin._pin() } } -impl SealedPin for PioPin { - fn pin_bank(&self) -> u8 { - self.pin_bank - } -} - -pub struct PioStateMachineInstance<'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> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { - type Pio = PIO; - const SM: usize = SM; -} -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 +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 } } - fn sm_no(&self) -> u8 { - Self::SM as u8 + pub fn full(&self) -> bool { + unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 } } - fn restart(&mut self) { - let mask = 1u8 << Self::SM; + pub fn level(&self) -> u8 { + unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f } + } + + pub fn stalled(&self) -> bool { unsafe { - Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); + let fdebug = PIO::PIO.fdebug(); + let ret = fdebug.read().rxstall() & (1 << SM) != 0; + fdebug.write(|w| w.set_rxstall(1 << SM)); + ret } } - fn set_enable(&mut self, enable: bool) { - let mask = 1u8 << Self::SM; + + 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 { + PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM)); + } + on_pio_drop::(); + } +} + +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 fn restart(&mut self) { + let mask = 1u8 << SM; + unsafe { + PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); + } + } + 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 } - } - fn is_tx_full(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().txfull() & (1u8 << Self::SM) != 0 } - } - - fn is_rx_empty(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().rxempty() & (1u8 << Self::SM) != 0 } - } - fn is_rx_full(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().rxfull() & (1u8 << Self::SM) != 0 } - } - - fn tx_level(&self) -> u8 { - unsafe { - let flevel = Self::Pio::PIO.flevel().read().0; - (flevel >> (Self::SM * 8)) as u8 & 0x0f - } - } - - fn rx_level(&self) -> u8 { - unsafe { - let flevel = Self::Pio::PIO.flevel().read().0; - (flevel >> (Self::SM * 8 + 4)) as u8 & 0x0f - } - } - - fn push_tx(&mut self, v: u32) { - unsafe { - Self::Pio::PIO.txf(Self::SM).write_value(v); - } - } - - fn try_push_tx(&mut self, v: u32) -> bool { - if self.is_tx_full() { - return false; - } - self.push_tx(v); - true - } - - fn pull_rx(&mut self) -> u32 { - unsafe { Self::Pio::PIO.rxf(Self::SM).read() } - } - - 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); @@ -466,14 +543,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } /// 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), @@ -486,7 +563,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { }); } } - 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 @@ -500,7 +577,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - fn clear_fifos(&mut self) { + pub fn clear_fifos(&mut self) { // Toggle FJOIN_RX to flush FIFOs unsafe { let shiftctrl = Self::this_sm().shiftctrl(); @@ -513,33 +590,33 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - 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 @@ -549,14 +626,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - 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 @@ -566,46 +643,46 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - 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: &PioPin) { + 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() @@ -613,7 +690,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } /// 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| { @@ -624,27 +701,27 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } /// 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: &PioPin) { + 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| { @@ -655,14 +732,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } /// 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 [&PioPin]) { + 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; @@ -673,7 +750,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]) { + 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; @@ -684,108 +761,24 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { 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> { - FifoOutFuture::new(self, value) + pub fn rx(&mut self) -> &mut PioStateMachineRx<'d, PIO, SM> { + &mut self.rx } - - fn wait_pull<'a>(&'a mut self) -> FifoInFuture<'a, Self::Pio, Self> { - FifoInFuture::new(self) + pub fn tx(&mut self) -> &mut PioStateMachineTx<'d, PIO, SM> { + &mut self.tx } - - fn wait_irq(&self, irq_no: u8) -> IrqFuture { - IrqFuture::new(irq_no) - } - - 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)); - ret - } - } - - 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)); - ret - } - } - - 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)); - ret - } - } - - 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)); - ret - } - } - - 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 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.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_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) - } - - 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 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.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_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) } } @@ -794,6 +787,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>, @@ -827,33 +826,13 @@ 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; } - 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 @@ -868,64 +847,172 @@ 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. **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 { pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); } - PioPin { - pin_bank: pin.pin_bank(), + // 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: pin.into_ref().map_into(), pio: PhantomData::default(), } } } +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, + } + } +} + +#[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 sm0: PioStateMachineInstance<'d, PIO, 0>, - pub sm1: PioStateMachineInstance<'d, PIO, 1>, - pub sm2: PioStateMachineInstance<'d, PIO, 2>, - pub sm3: PioStateMachineInstance<'d, PIO, 3>, + pub irq_flags: PioIrqFlags<'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>, + pub sm3: PioStateMachine<'d, PIO, 3>, } 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, pio: PhantomData, }, - sm0: PioStateMachineInstance { pio: PhantomData }, - sm1: PioStateMachineInstance { pio: PhantomData }, - sm2: PioStateMachineInstance { pio: PhantomData }, - sm3: PioStateMachineInstance { pio: PhantomData }, + irq_flags: PioIrqFlags { pio: PhantomData }, + irq0: PioIrq { pio: PhantomData }, + irq1: PioIrq { pio: PhantomData }, + irq2: PioIrq { pio: PhantomData }, + irq3: PioIrq { 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 }, + }, } } } -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 { - pub trait PioStateMachine { - type Pio: super::PioInstance; - const SM: usize; + use super::*; - #[inline(always)] - fn this_sm() -> crate::pac::pio::StateMachine { - Self::Pio::PIO.sm(Self::SM as usize) - } - } + pub trait PioPin {} pub trait PioInstance { 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 {} + macro_rules! impl_pio { ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { impl sealed::PioInstance for peripherals::$name { @@ -939,3 +1026,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/embassy-rp/src/pio_instr_util.rs b/embassy-rp/src/pio_instr_util.rs index ae26ff1d..81abdb66 100644 --- a/embassy-rp/src/pio_instr_util.rs +++ b/embassy-rp/src/pio_instr_util.rs @@ -1,38 +1,38 @@ use pio::{InSource, InstructionOperands, JmpCondition, OutDestination, SetDestination}; -use crate::pio::PioStateMachine; +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, } .encode(); - sm.push_tx(value); + sm.tx().push(value); 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, } .encode(); sm.exec_instr(IN); - sm.pull_rx() + sm.rx().pull() } -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, } .encode(); - sm.push_tx(value); + sm.tx().push(value); 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, @@ -40,10 +40,10 @@ pub fn get_y(sm: &mut SM) -> u32 { .encode(); sm.exec_instr(IN); - sm.pull_rx() + sm.rx().pull() } -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,26 +61,26 @@ 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, } .encode(); - sm.push_tx(data); + sm.tx().push(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, } .encode(); - sm.push_tx(data); + sm.tx().push(data); 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 5fea7034..4e0ab5e3 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, PioIrq, PioPin, PioStateMachine, 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 PioStateMachine, pin: impl PioPin) { // Setup sm0 // Send data serially to pin @@ -38,18 +37,18 @@ 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; loop { - sm.wait_push(v).await; + sm.tx().wait_push(v).await; v ^= 0xffff; info!("Pushed {:032b} to FIFO", v); } } -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 @@ -68,15 +67,15 @@ 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; + let rx = sm.rx().wait_pull().await; info!("Pulled {:032b} from FIFO", rx); } } -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 @@ -100,10 +99,10 @@ 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 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"); } } @@ -115,16 +114,17 @@ async fn main(spawner: Spawner) { let Pio { mut common, + irq3, mut sm0, mut sm1, mut sm2, .. } = 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(); 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_dma.rs b/examples/rp/src/bin/pio_dma.rs index 0f1f6df1..c664482e 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, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; @@ -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 59b4c1f5..f76d334e 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, ShiftDirection}; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{into_ref, Peripheral, PeripheralRef}; @@ -65,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], } @@ -74,19 +73,22 @@ 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); let db7pin = db7.pin(); let Pio { - mut common, mut sm0, .. + mut common, + mut irq0, + mut sm0, + .. } = Pio::new(pio); // takes command words ( <0:4>) @@ -137,16 +139,16 @@ 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); - sm0.wait_irq(0).await; + irq0.wait().await; sm0.set_enable(false); // takes command sequences ( , data...) @@ -214,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(), @@ -238,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 0975559d..c9c701a7 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -4,21 +4,18 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::gpio::{self, Pin}; -use embassy_rp::pio::{ - FifoJoin, Pio, PioCommon, PioInstance, 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}; 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: gpio::AnyPin) -> 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 @@ -90,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; } } } @@ -124,7 +121,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 {