diff options
Diffstat (limited to 'embassy-rp/src/pio/mod.rs')
| -rw-r--r-- | embassy-rp/src/pio/mod.rs | 90 |
1 files changed, 80 insertions, 10 deletions
diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index ec698d99c..5f554dfe3 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; |
| @@ -98,6 +98,9 @@ pub enum StatusSource { | |||
| 98 | TxFifoLevel = 0, | 98 | TxFifoLevel = 0, |
| 99 | /// All-ones if RX FIFO level < N, otherwise all-zeroes. | 99 | /// All-ones if RX FIFO level < N, otherwise all-zeroes. |
| 100 | RxFifoLevel = 1, | 100 | RxFifoLevel = 1, |
| 101 | /// All-ones if the indexed IRQ flag is raised, otherwise all-zeroes | ||
| 102 | #[cfg(feature = "_rp235x")] | ||
| 103 | Irq = 2, | ||
| 101 | } | 104 | } |
| 102 | 105 | ||
| 103 | const RXNEMPTY_MASK: u32 = 1 << 0; | 106 | const RXNEMPTY_MASK: u32 = 1 << 0; |
| @@ -278,6 +281,18 @@ impl<'l, PIO: Instance> Pin<'l, PIO> { | |||
| 278 | }); | 281 | }); |
| 279 | } | 282 | } |
| 280 | 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 | |||
| 281 | /// Set the pin's input sync bypass. | 296 | /// Set the pin's input sync bypass. |
| 282 | pub fn set_input_sync_bypass(&mut self, bypass: bool) { | 297 | pub fn set_input_sync_bypass(&mut self, bypass: bool) { |
| 283 | let mask = 1 << self.pin(); | 298 | let mask = 1 << self.pin(); |
| @@ -357,6 +372,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 357 | FifoInFuture::new(self) | 372 | FifoInFuture::new(self) |
| 358 | } | 373 | } |
| 359 | 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 | |||
| 360 | /// Prepare DMA transfer from RX FIFO. | 379 | /// Prepare DMA transfer from RX FIFO. |
| 361 | pub fn dma_pull<'a, C: Channel, W: Word>( | 380 | pub fn dma_pull<'a, C: Channel, W: Word>( |
| 362 | &'a mut self, | 381 | &'a mut self, |
| @@ -364,7 +383,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 364 | data: &'a mut [W], | 383 | data: &'a mut [W], |
| 365 | bswap: bool, | 384 | bswap: bool, |
| 366 | ) -> Transfer<'a, C> { | 385 | ) -> Transfer<'a, C> { |
| 367 | let pio_no = PIO::PIO_NO; | ||
| 368 | let p = ch.regs(); | 386 | let p = ch.regs(); |
| 369 | p.write_addr().write_value(data.as_ptr() as u32); | 387 | p.write_addr().write_value(data.as_ptr() as u32); |
| 370 | 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); |
| @@ -374,8 +392,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 374 | 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)); |
| 375 | compiler_fence(Ordering::SeqCst); | 393 | compiler_fence(Ordering::SeqCst); |
| 376 | p.ctrl_trig().write(|w| { | 394 | p.ctrl_trig().write(|w| { |
| 377 | // Set RX DREQ for this statemachine | 395 | w.set_treq_sel(Self::dreq()); |
| 378 | w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8 + 4)); | ||
| 379 | w.set_data_size(W::size()); | 396 | w.set_data_size(W::size()); |
| 380 | w.set_chain_to(ch.number()); | 397 | w.set_chain_to(ch.number()); |
| 381 | w.set_incr_read(false); | 398 | w.set_incr_read(false); |
| @@ -386,6 +403,36 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> { | |||
| 386 | compiler_fence(Ordering::SeqCst); | 403 | compiler_fence(Ordering::SeqCst); |
| 387 | Transfer::new(ch) | 404 | Transfer::new(ch) |
| 388 | } | 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 | } | ||
| 389 | } | 436 | } |
| 390 | 437 | ||
| 391 | /// Type representing a state machine TX FIFO. | 438 | /// Type representing a state machine TX FIFO. |
| @@ -409,7 +456,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 409 | (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f | 456 | (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f |
| 410 | } | 457 | } |
| 411 | 458 | ||
| 412 | /// Check state machine has stalled on empty TX FIFO. | 459 | /// Check if state machine has stalled on empty TX FIFO. |
| 413 | pub fn stalled(&self) -> bool { | 460 | pub fn stalled(&self) -> bool { |
| 414 | let fdebug = PIO::PIO.fdebug(); | 461 | let fdebug = PIO::PIO.fdebug(); |
| 415 | let ret = fdebug.read().txstall() & (1 << SM) != 0; | 462 | let ret = fdebug.read().txstall() & (1 << SM) != 0; |
| @@ -448,6 +495,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 448 | FifoOutFuture::new(self, value) | 495 | FifoOutFuture::new(self, value) |
| 449 | } | 496 | } |
| 450 | 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 | |||
| 451 | /// Prepare a DMA transfer to TX FIFO. | 502 | /// Prepare a DMA transfer to TX FIFO. |
| 452 | pub fn dma_push<'a, C: Channel, W: Word>( | 503 | pub fn dma_push<'a, C: Channel, W: Word>( |
| 453 | &'a mut self, | 504 | &'a mut self, |
| @@ -455,7 +506,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 455 | data: &'a [W], | 506 | data: &'a [W], |
| 456 | bswap: bool, | 507 | bswap: bool, |
| 457 | ) -> Transfer<'a, C> { | 508 | ) -> Transfer<'a, C> { |
| 458 | let pio_no = PIO::PIO_NO; | ||
| 459 | let p = ch.regs(); | 509 | let p = ch.regs(); |
| 460 | p.read_addr().write_value(data.as_ptr() as u32); | 510 | p.read_addr().write_value(data.as_ptr() as u32); |
| 461 | 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); |
| @@ -465,8 +515,7 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 465 | 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)); |
| 466 | compiler_fence(Ordering::SeqCst); | 516 | compiler_fence(Ordering::SeqCst); |
| 467 | p.ctrl_trig().write(|w| { | 517 | p.ctrl_trig().write(|w| { |
| 468 | // Set TX DREQ for this statemachine | 518 | w.set_treq_sel(Self::dreq()); |
| 469 | w.set_treq_sel(crate::pac::dma::vals::TreqSel::from(pio_no * 8 + SM as u8)); | ||
| 470 | w.set_data_size(W::size()); | 519 | w.set_data_size(W::size()); |
| 471 | w.set_chain_to(ch.number()); | 520 | w.set_chain_to(ch.number()); |
| 472 | w.set_incr_read(true); | 521 | w.set_incr_read(true); |
| @@ -477,6 +526,11 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> { | |||
| 477 | compiler_fence(Ordering::SeqCst); | 526 | compiler_fence(Ordering::SeqCst); |
| 478 | Transfer::new(ch) | 527 | Transfer::new(ch) |
| 479 | } | 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 | } | ||
| 480 | } | 534 | } |
| 481 | 535 | ||
| 482 | /// A type representing a single PIO state machine. | 536 | /// A type representing a single PIO state machine. |
| @@ -736,6 +790,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 736 | w.set_status_sel(match config.status_sel { | 790 | w.set_status_sel(match config.status_sel { |
| 737 | StatusSource::TxFifoLevel => pac::pio::vals::ExecctrlStatusSel::TXLEVEL, | 791 | StatusSource::TxFifoLevel => pac::pio::vals::ExecctrlStatusSel::TXLEVEL, |
| 738 | StatusSource::RxFifoLevel => pac::pio::vals::ExecctrlStatusSel::RXLEVEL, | 792 | StatusSource::RxFifoLevel => pac::pio::vals::ExecctrlStatusSel::RXLEVEL, |
| 793 | StatusSource::Irq => pac::pio::vals::ExecctrlStatusSel::IRQ, | ||
| 739 | }); | 794 | }); |
| 740 | #[cfg(feature = "rp2040")] | 795 | #[cfg(feature = "rp2040")] |
| 741 | w.set_status_sel(match config.status_sel { | 796 | w.set_status_sel(match config.status_sel { |
| @@ -922,13 +977,27 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 922 | self.set_enable(enabled); | 977 | self.set_enable(enabled); |
| 923 | } | 978 | } |
| 924 | 979 | ||
| 980 | #[cfg(feature = "rp2040")] | ||
| 981 | fn pin_base() -> u8 { | ||
| 982 | 0 | ||
| 983 | } | ||
| 984 | |||
| 985 | #[cfg(feature = "_rp235x")] | ||
| 986 | fn pin_base() -> u8 { | ||
| 987 | if PIO::PIO.gpiobase().read().gpiobase() { | ||
| 988 | 16 | ||
| 989 | } else { | ||
| 990 | 0 | ||
| 991 | } | ||
| 992 | } | ||
| 993 | |||
| 925 | /// Sets pin directions. This pauses the current state machine to run `SET` commands | 994 | /// Sets pin directions. This pauses the current state machine to run `SET` commands |
| 926 | /// and temporarily unsets the `OUT_STICKY` bit. | 995 | /// and temporarily unsets the `OUT_STICKY` bit. |
| 927 | pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { | 996 | pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) { |
| 928 | self.with_paused(|sm| { | 997 | self.with_paused(|sm| { |
| 929 | for pin in pins { | 998 | for pin in pins { |
| 930 | Self::this_sm().pinctrl().write(|w| { | 999 | Self::this_sm().pinctrl().write(|w| { |
| 931 | w.set_set_base(pin.pin()); | 1000 | w.set_set_base(pin.pin() - Self::pin_base()); |
| 932 | w.set_set_count(1); | 1001 | w.set_set_count(1); |
| 933 | }); | 1002 | }); |
| 934 | // SET PINDIRS, (dir) | 1003 | // SET PINDIRS, (dir) |
| @@ -943,7 +1012,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { | |||
| 943 | self.with_paused(|sm| { | 1012 | self.with_paused(|sm| { |
| 944 | for pin in pins { | 1013 | for pin in pins { |
| 945 | Self::this_sm().pinctrl().write(|w| { | 1014 | Self::this_sm().pinctrl().write(|w| { |
| 946 | w.set_set_base(pin.pin()); | 1015 | w.set_set_base(pin.pin() - Self::pin_base()); |
| 947 | w.set_set_count(1); | 1016 | w.set_set_count(1); |
| 948 | }); | 1017 | }); |
| 949 | // SET PINS, (dir) | 1018 | // SET PINS, (dir) |
| @@ -1306,6 +1375,7 @@ impl<'d, PIO: Instance> Pio<'d, PIO> { | |||
| 1306 | PIO::state().users.store(5, Ordering::Release); | 1375 | PIO::state().users.store(5, Ordering::Release); |
| 1307 | PIO::state().used_pins.store(0, Ordering::Release); | 1376 | PIO::state().used_pins.store(0, Ordering::Release); |
| 1308 | PIO::Interrupt::unpend(); | 1377 | PIO::Interrupt::unpend(); |
| 1378 | |||
| 1309 | unsafe { PIO::Interrupt::enable() }; | 1379 | unsafe { PIO::Interrupt::enable() }; |
| 1310 | Self { | 1380 | Self { |
| 1311 | common: Common { | 1381 | common: Common { |
