From 676f9da58360627699736c79a4e24ef20a2b9f87 Mon Sep 17 00:00:00 2001 From: Adrian Wowk Date: Wed, 2 Jul 2025 20:31:45 -0500 Subject: rp: add new pio dma apis This commit adds StateMachineRx::dma_pull_repeated and StateMachineTx::dma_push_repeated which allow you to discard reads or send dummy writes to the state machine using the DMA hardware --- embassy-rp/src/pio/mod.rs | 67 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 8 deletions(-) (limited to 'embassy-rp') diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 0d8a94776..f46e664e4 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -12,7 +12,7 @@ use fixed::types::extra::U8; use fixed::FixedU32; use pio::{Program, SideSet, Wrap}; -use crate::dma::{Channel, Transfer, Word}; +use crate::dma::{self, Channel, Transfer, Word}; use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; use crate::relocate::RelocatedProgram; @@ -281,6 +281,18 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { }); } + /// Configure the output logic inversion of this pin. + #[inline] + pub fn set_output_inversion(&mut self, invert: bool) { + self.pin.gpio().ctrl().modify(|w| { + w.set_outover(if invert { + pac::io::vals::Outover::INVERT + } else { + pac::io::vals::Outover::NORMAL + }) + }); + } + /// Set the pin's input sync bypass. pub fn set_input_sync_bypass(&mut self, bypass: bool) { let mask = 1 << self.pin(); @@ -360,6 +372,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { FifoInFuture::new(self) } + fn dreq() -> crate::pac::dma::vals::TreqSel { + crate::pac::dma::vals::TreqSel::from(PIO::PIO_NO * 8 + SM as u8 + 4) + } + /// Prepare DMA transfer from RX FIFO. pub fn dma_pull<'a, C: Channel, W: Word>( &'a mut self, @@ -367,7 +383,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { data: &'a mut [W], bswap: bool, ) -> Transfer<'a, C> { - 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).as_ptr() as u32); @@ -377,8 +392,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { p.trans_count().write(|w| w.set_count(data.len() as u32)); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { - // Set RX DREQ for this statemachine - w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8 + 4)); + w.set_treq_sel(Self::dreq()); w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(false); @@ -389,6 +403,36 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { compiler_fence(Ordering::SeqCst); Transfer::new(ch) } + + /// Prepare a repeated DMA transfer from RX FIFO. + pub fn dma_pull_repeated<'a, C: Channel, W: Word>(&'a mut self, ch: Peri<'a, C>, len: usize) -> Transfer<'a, C> { + // This is the read version of dma::write_repeated. This allows us to + // discard reads from the RX FIFO through DMA. + + // static mut so it gets allocated in RAM + static mut DUMMY: u32 = 0; + + let p = ch.regs(); + p.write_addr().write_value(core::ptr::addr_of_mut!(DUMMY) as u32); + p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); + + #[cfg(feature = "rp2040")] + p.trans_count().write(|w| *w = len as u32); + #[cfg(feature = "_rp235x")] + p.trans_count().write(|w| w.set_count(len as u32)); + + compiler_fence(Ordering::SeqCst); + p.ctrl_trig().write(|w| { + w.set_treq_sel(Self::dreq()); + w.set_data_size(W::size()); + w.set_chain_to(ch.number()); + w.set_incr_read(false); + w.set_incr_write(false); + w.set_en(true); + }); + compiler_fence(Ordering::SeqCst); + Transfer::new(ch) + } } /// Type representing a state machine TX FIFO. @@ -412,7 +456,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f } - /// Check state machine has stalled on empty TX FIFO. + /// Check if state machine has stalled on empty TX FIFO. pub fn stalled(&self) -> bool { let fdebug = PIO::PIO.fdebug(); let ret = fdebug.read().txstall() & (1 << SM) != 0; @@ -451,6 +495,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { FifoOutFuture::new(self, value) } + fn dreq() -> crate::pac::dma::vals::TreqSel { + crate::pac::dma::vals::TreqSel::from(PIO::PIO_NO * 8 + SM as u8) + } + /// Prepare a DMA transfer to TX FIFO. pub fn dma_push<'a, C: Channel, W: Word>( &'a mut self, @@ -458,7 +506,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { data: &'a [W], bswap: bool, ) -> Transfer<'a, C> { - 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).as_ptr() as u32); @@ -468,8 +515,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { p.trans_count().write(|w| w.set_count(data.len() as u32)); compiler_fence(Ordering::SeqCst); p.ctrl_trig().write(|w| { - // Set TX DREQ for this statemachine - w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8)); + w.set_treq_sel(Self::dreq()); w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(true); @@ -480,6 +526,11 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { compiler_fence(Ordering::SeqCst); Transfer::new(ch) } + + /// Prepare a repeated DMA transfer to TX FIFO. + pub fn dma_push_repeated<'a, C: Channel, W: Word>(&'a mut self, ch: Peri<'a, C>, len: usize) -> Transfer<'a, C> { + unsafe { dma::write_repeated(ch, PIO::PIO.txf(SM).as_ptr(), len, Self::dreq()) } + } } /// A type representing a single PIO state machine. -- cgit