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; } } }