diff options
| author | Adrian Wowk <[email protected]> | 2025-07-02 20:31:45 -0500 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2025-09-05 20:35:48 +0200 |
| commit | 676f9da58360627699736c79a4e24ef20a2b9f87 (patch) | |
| tree | 2680d97a65271dae5b4eee5613b51e8b2469a4a7 | |
| parent | 0407f7ebe8fabeb81b8a77811ec5dda0fee0b44b (diff) | |
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
| -rw-r--r-- | embassy-rp/src/pio/mod.rs | 67 |
1 files changed, 59 insertions, 8 deletions
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; | |||
| 12 | use fixed::FixedU32; | 12 | use fixed::FixedU32; |
| 13 | use pio::{Program, SideSet, Wrap}; | 13 | use pio::{Program, SideSet, Wrap}; |
| 14 | 14 | ||
| 15 | use crate::dma::{Channel, Transfer, Word}; | 15 | use crate::dma::{self, Channel, Transfer, Word}; |
| 16 | use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; | 16 | use crate::gpio::{self, AnyPin, Drive, Level, Pull, SealedPin, SlewRate}; |
| 17 | use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; | 17 | use crate::interrupt::typelevel::{Binding, Handler, Interrupt}; |
| 18 | use crate::relocate::RelocatedProgram; | 18 | use crate::relocate::RelocatedProgram; |
| @@ -281,6 +281,18 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { | |||
| 281 | }); | 281 | }); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | /// Configure the output logic inversion of this pin. | ||
| 285 | #[inline] | ||
| 286 | pub fn set_output_inversion(&mut self, invert: bool) { | ||
| 287 | self.pin.gpio().ctrl().modify(|w| { | ||
| 288 | w.set_outover(if invert { | ||
| 289 | pac::io::vals::Outover::INVERT | ||
| 290 | } else { | ||
| 291 | pac::io::vals::Outover::NORMAL | ||
| 292 | }) | ||
| 293 | }); | ||
| 294 | } | ||
| 295 | |||
| 284 | /// Set the pin's input sync bypass. | 296 | /// Set the pin's input sync bypass. |
| 285 | pub fn set_input_sync_bypass(&mut self, bypass: bool) { | 297 | pub fn set_input_sync_bypass(&mut self, bypass: bool) { |
| 286 | let mask = 1 << self.pin(); | 298 | let mask = 1 << self.pin(); |
| @@ -360,6 +372,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 360 | FifoInFuture::new(self) | 372 | FifoInFuture::new(self) |
| 361 | } | 373 | } |
| 362 | 374 | ||
| 375 | fn dreq() -> crate::pac::dma::vals::TreqSel { | ||
| 376 | crate::pac::dma::vals::TreqSel::from(PIO::PIO_NO * 8 + SM as u8 + 4) | ||
| 377 | } | ||
| 378 | |||
| 363 | /// Prepare DMA transfer from RX FIFO. | 379 | /// Prepare DMA transfer from RX FIFO. |
| 364 | pub fn dma_pull<'a, C: Channel, W: Word>( | 380 | pub fn dma_pull<'a, C: Channel, W: Word>( |
| 365 | &'a mut self, | 381 | &'a mut self, |
| @@ -367,7 +383,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 367 | data: &'a mut [W], | 383 | data: &'a mut [W], |
| 368 | bswap: bool, | 384 | bswap: bool, |
| 369 | ) -> Transfer<'a, C> { | 385 | ) -> Transfer<'a, C> { |
| 370 | let pio_no = PIO::PIO_NO; | ||
| 371 | let p = ch.regs(); | 386 | let p = ch.regs(); |
| 372 | p.write_addr().write_value(data.as_ptr() as u32); | 387 | p.write_addr().write_value(data.as_ptr() as u32); |
| 373 | p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); | 388 | 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> { | |||
| 377 | p.trans_count().write(|w| w.set_count(data.len() as u32)); | 392 | p.trans_count().write(|w| w.set_count(data.len() as u32)); |
| 378 | compiler_fence(Ordering::SeqCst); | 393 | compiler_fence(Ordering::SeqCst); |
| 379 | p.ctrl_trig().write(|w| { | 394 | p.ctrl_trig().write(|w| { |
| 380 | // Set RX DREQ for this statemachine | 395 | w.set_treq_sel(Self::dreq()); |
| 381 | w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8 + 4)); | ||
| 382 | w.set_data_size(W::size()); | 396 | w.set_data_size(W::size()); |
| 383 | w.set_chain_to(ch.number()); | 397 | w.set_chain_to(ch.number()); |
| 384 | w.set_incr_read(false); | 398 | w.set_incr_read(false); |
| @@ -389,6 +403,36 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 389 | compiler_fence(Ordering::SeqCst); | 403 | compiler_fence(Ordering::SeqCst); |
| 390 | Transfer::new(ch) | 404 | Transfer::new(ch) |
| 391 | } | 405 | } |
| 406 | |||
| 407 | /// Prepare a repeated DMA transfer from RX FIFO. | ||
| 408 | pub fn dma_pull_repeated<'a, C: Channel, W: Word>(&'a mut self, ch: Peri<'a, C>, len: usize) -> Transfer<'a, C> { | ||
| 409 | // This is the read version of dma::write_repeated. This allows us to | ||
| 410 | // discard reads from the RX FIFO through DMA. | ||
| 411 | |||
| 412 | // static mut so it gets allocated in RAM | ||
| 413 | static mut DUMMY: u32 = 0; | ||
| 414 | |||
| 415 | let p = ch.regs(); | ||
| 416 | p.write_addr().write_value(core::ptr::addr_of_mut!(DUMMY) as u32); | ||
| 417 | p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32); | ||
| 418 | |||
| 419 | #[cfg(feature = "rp2040")] | ||
| 420 | p.trans_count().write(|w| *w = len as u32); | ||
| 421 | #[cfg(feature = "_rp235x")] | ||
| 422 | p.trans_count().write(|w| w.set_count(len as u32)); | ||
| 423 | |||
| 424 | compiler_fence(Ordering::SeqCst); | ||
| 425 | p.ctrl_trig().write(|w| { | ||
| 426 | w.set_treq_sel(Self::dreq()); | ||
| 427 | w.set_data_size(W::size()); | ||
| 428 | w.set_chain_to(ch.number()); | ||
| 429 | w.set_incr_read(false); | ||
| 430 | w.set_incr_write(false); | ||
| 431 | w.set_en(true); | ||
| 432 | }); | ||
| 433 | compiler_fence(Ordering::SeqCst); | ||
| 434 | Transfer::new(ch) | ||
| 435 | } | ||
| 392 | } | 436 | } |
| 393 | 437 | ||
| 394 | /// Type representing a state machine TX FIFO. | 438 | /// Type representing a state machine TX FIFO. |
| @@ -412,7 +456,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 412 | (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f | 456 | (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f |
| 413 | } | 457 | } |
| 414 | 458 | ||
| 415 | /// Check state machine has stalled on empty TX FIFO. | 459 | /// Check if state machine has stalled on empty TX FIFO. |
| 416 | pub fn stalled(&self) -> bool { | 460 | pub fn stalled(&self) -> bool { |
| 417 | let fdebug = PIO::PIO.fdebug(); | 461 | let fdebug = PIO::PIO.fdebug(); |
| 418 | let ret = fdebug.read().txstall() & (1 << SM) != 0; | 462 | let ret = fdebug.read().txstall() & (1 << SM) != 0; |
| @@ -451,6 +495,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 451 | FifoOutFuture::new(self, value) | 495 | FifoOutFuture::new(self, value) |
| 452 | } | 496 | } |
| 453 | 497 | ||
| 498 | fn dreq() -> crate::pac::dma::vals::TreqSel { | ||
| 499 | crate::pac::dma::vals::TreqSel::from(PIO::PIO_NO * 8 + SM as u8) | ||
| 500 | } | ||
| 501 | |||
| 454 | /// Prepare a DMA transfer to TX FIFO. | 502 | /// Prepare a DMA transfer to TX FIFO. |
| 455 | pub fn dma_push<'a, C: Channel, W: Word>( | 503 | pub fn dma_push<'a, C: Channel, W: Word>( |
| 456 | &'a mut self, | 504 | &'a mut self, |
| @@ -458,7 +506,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 458 | data: &'a [W], | 506 | data: &'a [W], |
| 459 | bswap: bool, | 507 | bswap: bool, |
| 460 | ) -> Transfer<'a, C> { | 508 | ) -> Transfer<'a, C> { |
| 461 | let pio_no = PIO::PIO_NO; | ||
| 462 | let p = ch.regs(); | 509 | let p = ch.regs(); |
| 463 | p.read_addr().write_value(data.as_ptr() as u32); | 510 | p.read_addr().write_value(data.as_ptr() as u32); |
| 464 | p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32); | 511 | 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> { | |||
| 468 | p.trans_count().write(|w| w.set_count(data.len() as u32)); | 515 | p.trans_count().write(|w| w.set_count(data.len() as u32)); |
| 469 | compiler_fence(Ordering::SeqCst); | 516 | compiler_fence(Ordering::SeqCst); |
| 470 | p.ctrl_trig().write(|w| { | 517 | p.ctrl_trig().write(|w| { |
| 471 | // Set TX DREQ for this statemachine | 518 | w.set_treq_sel(Self::dreq()); |
| 472 | w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8)); | ||
| 473 | w.set_data_size(W::size()); | 519 | w.set_data_size(W::size()); |
| 474 | w.set_chain_to(ch.number()); | 520 | w.set_chain_to(ch.number()); |
| 475 | w.set_incr_read(true); | 521 | w.set_incr_read(true); |
| @@ -480,6 +526,11 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 480 | compiler_fence(Ordering::SeqCst); | 526 | compiler_fence(Ordering::SeqCst); |
| 481 | Transfer::new(ch) | 527 | Transfer::new(ch) |
| 482 | } | 528 | } |
| 529 | |||
| 530 | /// Prepare a repeated DMA transfer to TX FIFO. | ||
| 531 | pub fn dma_push_repeated<'a, C: Channel, W: Word>(&'a mut self, ch: Peri<'a, C>, len: usize) -> Transfer<'a, C> { | ||
| 532 | unsafe { dma::write_repeated(ch, PIO::PIO.txf(SM).as_ptr(), len, Self::dreq()) } | ||
| 533 | } | ||
| 483 | } | 534 | } |
| 484 | 535 | ||
| 485 | /// A type representing a single PIO state machine. | 536 | /// A type representing a single PIO state machine. |
