From 54e695b1b2105c1b2484584d100564afc0679596 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 2 May 2023 10:50:06 +0200 Subject: [PATCH 01/10] rp/pio: fix dma fixing the dma word size to 32 makes it impossible to implement any peripheral that takes its data in smaller chunks, eg uart, spi, i2c, ws2812, the list goes on. compiler barriers were also not set correctly; we need a SeqCst barrier before starting a transfer as well to avoid reordering of accesses into a buffer after dma has started. --- embassy-rp/src/pio.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 7faec10b..cab57f76 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -8,10 +8,10 @@ use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; use embassy_hal_common::PeripheralRef; use embassy_sync::waitqueue::AtomicWaker; -use crate::dma::{Channel, Transfer}; +use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::{Drive, Pin, Pull, SlewRate}; -use crate::pac::dma::vals::{DataSize, TreqSel}; +use crate::pac::dma::vals::TreqSel; use crate::pio::sealed::{PioInstance as _, SmInstance as _}; use crate::{interrupt, pac, peripherals, RegExt}; @@ -820,7 +820,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } - fn dma_push<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a [u32]) -> Transfer<'a, C> { + 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::SM_NO; @@ -829,10 +829,11 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { p.write_addr() .write_value(Self::Pio::PIO.txf(sm_no as usize).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)); - w.set_data_size(DataSize::SIZE_WORD); + w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(true); w.set_incr_write(false); @@ -843,7 +844,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { Transfer::new(ch) } - fn dma_pull<'a, C: Channel>(&'a self, ch: PeripheralRef<'a, C>, data: &'a mut [u32]) -> Transfer<'a, C> { + 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::SM_NO; @@ -852,10 +853,11 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { p.read_addr() .write_value(Self::Pio::PIO.rxf(sm_no as usize).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 + // Set RX DREQ for this statemachine w.set_treq_sel(TreqSel(pio_no * 8 + sm_no + 4)); - w.set_data_size(DataSize::SIZE_WORD); + w.set_data_size(W::size()); w.set_chain_to(ch.number()); w.set_incr_read(false); w.set_incr_write(true); From 8e22d574478d7480bc0473ed0ad9dac7d02602a8 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 2 May 2023 10:44:00 +0200 Subject: [PATCH 02/10] rp/pio: add hd44780 example add an hd44780 example for pio. hd44780 with busy polling is a pretty complicated protocol if the busy polling is to be done by the peripheral, and this example exercises many pio features that we don't have good examples for yet. --- examples/rp/src/bin/pio_hd44780.rs | 244 +++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 examples/rp/src/bin/pio_hd44780.rs diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs new file mode 100644 index 00000000..6bcd0652 --- /dev/null +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -0,0 +1,244 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +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, PioCommon, PioInstanceBase, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, + SmInstanceBase, +}; +use embassy_rp::pwm::{Config, Pwm}; +use embassy_rp::relocate::RelocatedProgram; +use embassy_rp::{into_ref, Peripheral, PeripheralRef}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + // this test assumes a 2x16 HD44780 display attached as follow: + // rs = PIN0 + // rw = PIN1 + // e = PIN2 + // db4 = PIN3 + // db5 = PIN4 + // db6 = PIN5 + // db7 = PIN6 + // additionally a pwm signal for a bias voltage charge pump is provided on pin 15, + // allowing direct connection of the display to the RP2040 without level shifters. + let p = embassy_rp::init(Default::default()); + + let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { + let mut c = Config::default(); + c.divider = 125.into(); + c.top = 100; + c.compare_b = 50; + c + }); + + let mut hd = HD44780::new( + p.PIO0, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, + ) + .await; + + loop { + struct Buf([u8; N], usize); + impl Write for Buf { + fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> { + for b in s.as_bytes() { + if self.1 >= N { + return Err(core::fmt::Error); + } + self.0[self.1] = *b; + self.1 += 1; + } + Ok(()) + } + } + let mut buf = Buf([0; 16], 0); + write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap(); + hd.add_line(&buf.0[0..buf.1]).await; + Timer::after(Duration::from_secs(1)).await; + } +} + +pub struct HD44780<'l> { + dma: PeripheralRef<'l, AnyChannel>, + sm: PioStateMachineInstance, SmInstanceBase<0>>, + + buf: [u8; 40], +} + +impl<'l> HD44780<'l> { + pub async fn new( + pio: PIO0, + 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, + ) -> HD44780<'l> { + into_ref!(dma); + + let db7pin = db7.pin(); + let (mut common, mut sm0, ..) = pio.split(); + + // takes command words ( <0:4>) + let prg = pio_proc::pio_asm!( + r#" + .side_set 1 opt + + loop: + out x, 24 + delay: + jmp x--, delay + out pins, 4 side 1 + out null, 4 side 0 + jmp !osre, loop + irq 0 + "#, + ); + + let rs = common.make_pio_pin(rs); + let rw = common.make_pio_pin(rw); + let e = common.make_pio_pin(e); + let db4 = common.make_pio_pin(db4); + let db5 = common.make_pio_pin(db5); + let db6 = common.make_pio_pin(db6); + let db7 = common.make_pio_pin(db7); + + sm0.set_set_pins(&[&rs, &rw]); + embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11); + sm0.set_set_pins(&[&e]); + embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b1); + sm0.set_set_pins(&[&db4, &db5, &db6, &db7]); + embassy_rp::pio_instr_util::set_pindir(&mut sm0, 0b11111); + + let relocated = RelocatedProgram::new(&prg.program); + common.write_instr(relocated.origin() as usize, relocated.code()); + embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); + sm0.set_clkdiv(125 * 256); + let pio::Wrap { source, target } = relocated.wrap(); + sm0.set_wrap(source, target); + sm0.set_side_enable(true); + sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); + sm0.set_sideset_base_pin(&e); + sm0.set_sideset_count(2); + sm0.set_out_shift_dir(ShiftDirection::Left); + sm0.set_fifo_join(FifoJoin::TxOnly); + sm0.set_autopull(true); + sm0.set_pull_threshold(32); + + 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); + // init 4 bit + sm0.push_tx((200 << 8) | 0x20); + // set font and lines + sm0.push_tx((50 << 8) | 0x20); + sm0.push_tx(0b1100_0000); + + sm0.wait_irq(0).await; + sm0.set_enable(false); + + // takes command sequences ( , data...) + // many side sets are only there to free up a delay bit! + let prg = pio_proc::pio_asm!( + r#" + .origin 7 + .side_set 1 + + .wrap_target + pull side 0 + out x 1 side 0 ; !rs + out y 7 side 0 ; #data - 1 + + ; rs/rw to e: >= 60ns + ; e high time: >= 500ns + ; e low time: >= 500ns + ; read data valid after e falling: ~5ns + ; write data hold after e falling: ~10ns + + loop: + pull side 0 + jmp !x data side 0 + command: + set pins 0b00 side 0 + jmp shift side 0 + data: + set pins 0b01 side 0 + shift: + out pins 4 side 1 [9] + nop side 0 [9] + out pins 4 side 1 [9] + mov osr null side 0 [7] + out pindirs 4 side 0 + set pins 0b10 side 0 + busy: + nop side 1 [9] + jmp pin more side 0 [9] + mov osr ~osr side 1 [9] + nop side 0 [4] + out pindirs 4 side 0 + jmp y-- loop side 0 + .wrap + more: + nop side 1 [9] + jmp busy side 0 [9] + "# + ); + + let relocated = RelocatedProgram::new(&prg.program); + common.write_instr(relocated.origin() as usize, relocated.code()); + embassy_rp::pio_instr_util::exec_jmp(&mut sm0, relocated.origin()); + let pio::Wrap { source, target } = relocated.wrap(); + sm0.set_clkdiv(8 * 256); // ~64ns/insn + sm0.set_side_enable(false); + sm0.set_jmp_pin(db7pin); + sm0.set_wrap(source, target); + sm0.set_set_pins(&[&rs, &rw]); + sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); + sm0.set_sideset_base_pin(&e); + sm0.set_sideset_count(1); + sm0.set_out_shift_dir(ShiftDirection::Left); + sm0.set_fifo_join(FifoJoin::TxOnly); + + sm0.set_enable(true); + + // display on and cursor on and blinking, reset display + sm0.dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; + + Self { + dma: dma.map_into(), + sm: sm0, + buf: [0x20; 40], + } + } + + pub async fn add_line(&mut self, s: &[u8]) { + // move cursor to 0:0, prepare 16 characters + self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); + // move line 2 up + self.buf.copy_within(22..38, 3); + // move cursor to 1:0, prepare 16 characters + self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); + // file line 2 with spaces + self.buf[22..38].fill(0x20); + // copy input line + let len = s.len().min(16); + self.buf[22..22 + len].copy_from_slice(&s[0..len]); + // set cursor to 1:15 + self.buf[38..].copy_from_slice(&[0x80, 0xcf]); + + self.sm.dma_push(self.dma.reborrow(), &self.buf).await; + } +} From 47ae9b79815af97e7e5d8b2f3c94af2326d7fd79 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 21:55:33 +0200 Subject: [PATCH 03/10] rp/pio: add funcsel values to PioInstance makes code setting funcsels easier to read and should make it easier to hook up more pio blocks, should they ever appear --- embassy-rp/src/pio.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index cab57f76..ecf7c922 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -959,17 +959,7 @@ pub trait PioCommon: sealed::PioCommon + Sized { fn make_pio_pin(&self, pin: impl Pin) -> PioPin { unsafe { - pin.io().ctrl().write(|w| { - w.set_funcsel( - if Self::Pio::PIO_NO == 1 { - pac::io::vals::Gpio0ctrlFuncsel::PIO1_0 - } else { - // PIO == 0 - pac::io::vals::Gpio0ctrlFuncsel::PIO0_0 - } - .0, - ); - }); + pin.io().ctrl().write(|w| w.set_funcsel(Self::Pio::FUNCSEL.0)); } PioPin { pin_bank: pin.pin_bank(), @@ -1031,6 +1021,7 @@ mod sealed { pub trait PioInstance { const PIO_NO: u8; const PIO: &'static crate::pac::pio::Pio; + const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; } pub trait PioCommon { @@ -1059,12 +1050,14 @@ pub trait PioInstance: sealed::PioInstance + Unpin {} impl sealed::PioInstance for PioInstanceBase<0> { const PIO_NO: u8 = 0; const PIO: &'static pac::pio::Pio = &pac::PIO0; + const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::PIO0_0; } impl PioInstance for PioInstanceBase<0> {} impl sealed::PioInstance for PioInstanceBase<1> { const PIO_NO: u8 = 1; const PIO: &'static pac::pio::Pio = &pac::PIO1; + const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::PIO1_0; } impl PioInstance for PioInstanceBase<1> {} From 0d224a00e1023082f03610b74c37933506561c26 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 22:19:13 +0200 Subject: [PATCH 04/10] rp/pio: avoid sm(SM_NO) indexing accessing the current state machine is an extremely common operation that shouldn't have its specifics repeated myriad times. --- embassy-rp/src/pio.rs | 159 ++++++++++++------------------------------ 1 file changed, 43 insertions(+), 116 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index ecf7c922..b20ebbc7 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -410,15 +410,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_clkdiv(&mut self, div_x_256: u32) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .clkdiv() - .write(|w| w.0 = div_x_256 << 8); + Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8); } } fn get_clkdiv(&self) -> u32 { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).clkdiv().read().0 >> 8 } + unsafe { Self::this_sm().clkdiv().read().0 >> 8 } } fn clkdiv_restart(&mut self) { @@ -431,52 +428,37 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_side_enable(&self, enable: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .modify(|w| w.set_side_en(enable)); + Self::this_sm().execctrl().modify(|w| w.set_side_en(enable)); } } fn is_side_enabled(&self) -> bool { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().side_en() } + unsafe { Self::this_sm().execctrl().read().side_en() } } fn set_side_pindir(&mut self, pindir: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .modify(|w| w.set_side_pindir(pindir)); + Self::this_sm().execctrl().modify(|w| w.set_side_pindir(pindir)); } } fn is_side_pindir(&self) -> bool { - unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .read() - .side_pindir() - } + unsafe { Self::this_sm().execctrl().read().side_pindir() } } fn set_jmp_pin(&mut self, pin: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .execctrl() - .modify(|w| w.set_jmp_pin(pin)); + Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin)); } } fn get_jmp_pin(&mut self) -> u8 { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read().jmp_pin() } + unsafe { Self::this_sm().execctrl().read().jmp_pin() } } fn set_wrap(&self, source: u8, target: u8) { unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().modify(|w| { + Self::this_sm().execctrl().modify(|w| { w.set_wrap_top(source); w.set_wrap_bottom(target) }); @@ -486,7 +468,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { /// Get wrapping addresses. Returns (source, target). fn get_wrap(&self) -> (u8, u8) { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).execctrl().read(); + let r = Self::this_sm().execctrl().read(); (r.wrap_top(), r.wrap_bottom()) } } @@ -498,7 +480,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { FifoJoin::TxOnly => (false, true), }; unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().modify(|w| { + Self::this_sm().shiftctrl().modify(|w| { w.set_fjoin_rx(rx); w.set_fjoin_tx(tx) }); @@ -506,7 +488,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_fifo_join(&self) -> FifoJoin { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); + let r = Self::this_sm().shiftctrl().read(); // Ignores the invalid state when both bits are set if r.fjoin_rx() { FifoJoin::RxOnly @@ -521,7 +503,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn clear_fifos(&mut self) { // Toggle FJOIN_RX to flush FIFOs unsafe { - let shiftctrl = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl(); + let shiftctrl = Self::this_sm().shiftctrl(); shiftctrl.modify(|w| { w.set_fjoin_rx(!w.fjoin_rx()); }); @@ -533,51 +515,33 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_pull_threshold(&mut self, threshold: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_pull_thresh(threshold)); + Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold)); } } fn get_pull_threshold(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); - r.pull_thresh() - } + unsafe { Self::this_sm().shiftctrl().read().pull_thresh() } } fn set_push_threshold(&mut self, threshold: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_push_thresh(threshold)); + Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold)); } } fn get_push_threshold(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).shiftctrl().read(); - r.push_thresh() - } + unsafe { Self::this_sm().shiftctrl().read().push_thresh() } } fn set_out_shift_dir(&mut self, dir: ShiftDirection) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) + Self::this_sm() .shiftctrl() .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); } } fn get_out_shiftdir(&self) -> ShiftDirection { unsafe { - if Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .out_shiftdir() - { + if Self::this_sm().shiftctrl().read().out_shiftdir() { ShiftDirection::Right } else { ShiftDirection::Left @@ -587,20 +551,14 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_in_shift_dir(&mut self, dir: ShiftDirection) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) + Self::this_sm() .shiftctrl() .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); } } fn get_in_shiftdir(&self) -> ShiftDirection { unsafe { - if Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .in_shiftdir() - { + if Self::this_sm().shiftctrl().read().in_shiftdir() { ShiftDirection::Right } else { ShiftDirection::Left @@ -610,76 +568,46 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_autopull(&mut self, auto: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_autopull(auto)); + Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto)); } } fn is_autopull(&self) -> bool { - unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .autopull() - } + unsafe { Self::this_sm().shiftctrl().read().autopull() } } fn set_autopush(&mut self, auto: bool) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .modify(|w| w.set_autopush(auto)); + Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto)); } } fn is_autopush(&self) -> bool { - unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .shiftctrl() - .read() - .autopush() - } + unsafe { Self::this_sm().shiftctrl().read().autopush() } } fn get_addr(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).addr().read(); - r.addr() - } + unsafe { Self::this_sm().addr().read().addr() } } fn set_sideset_count(&mut self, count: u8) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| w.set_sideset_count(count)); + Self::this_sm().pinctrl().modify(|w| w.set_sideset_count(count)); } } fn get_sideset_count(&self) -> u8 { - unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); - r.sideset_count() - } + unsafe { Self::this_sm().pinctrl().read().sideset_count() } } fn set_sideset_base_pin(&mut self, base_pin: &PioPin) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| w.set_sideset_base(base_pin.pin())); + Self::this_sm().pinctrl().modify(|w| w.set_sideset_base(base_pin.pin())); } } fn get_sideset_base(&self) -> u8 { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); r.sideset_base() } } @@ -688,7 +616,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_set_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { + Self::this_sm().pinctrl().modify(|w| { w.set_set_base(base); w.set_set_count(count) }); @@ -698,23 +626,20 @@ 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) { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); (r.set_base(), r.set_count()) } } fn set_in_base_pin(&mut self, base: &PioPin) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .pinctrl() - .modify(|w| w.set_in_base(base.pin())); + Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin())); } } fn get_in_base(&self) -> u8 { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); r.in_base() } } @@ -722,7 +647,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn set_out_range(&mut self, base: u8, count: u8) { assert!(base + count < 32); unsafe { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().modify(|w| { + Self::this_sm().pinctrl().modify(|w| { w.set_out_base(base); w.set_out_count(count) }); @@ -732,7 +657,7 @@ 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) { unsafe { - let r = Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).pinctrl().read(); + let r = Self::this_sm().pinctrl().read(); (r.out_base(), r.out_count()) } } @@ -760,15 +685,12 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn get_current_instr() -> u32 { - unsafe { Self::Pio::PIO.sm(Self::Sm::SM_NO as usize).instr().read().0 } + unsafe { Self::this_sm().instr().read().0 } } fn exec_instr(&mut self, instr: u16) { unsafe { - Self::Pio::PIO - .sm(Self::Sm::SM_NO as usize) - .instr() - .write(|w| w.set_instr(instr)); + Self::this_sm().instr().write(|w| w.set_instr(instr)); } } @@ -1031,6 +953,11 @@ mod sealed { pub trait PioStateMachine { type Pio: super::PioInstance; type Sm: super::SmInstance; + + #[inline(always)] + fn this_sm() -> crate::pac::pio::StateMachine { + Self::Pio::PIO.sm(Self::Sm::SM_NO as usize) + } } pub trait SmInstance { From 6cec6fa09b3bcc01ada4d5d5decd02cc2a3a8e4f Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 25 Apr 2023 23:17:57 +0200 Subject: [PATCH 05/10] rp/pio: don't use modify on shared registers pio control registers are notionally shared between state machines as well. state machine operations that change these registers must use atomic accesses (or critical sections, which would be overkill). notably PioPin::set_input_sync_bypass was even wrong, enabling the bypass on a pin requires the corresponding bit to be set (not cleared). the PioCommon function got it right. --- embassy-rp/src/pio.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index b20ebbc7..e9a67fd4 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -298,9 +298,11 @@ impl PioPin { pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) { let mask = 1 << self.pin(); unsafe { - PIO::PIO - .input_sync_bypass() - .modify(|w| *w = if bypass { *w & !mask } else { *w | mask }); + if bypass { + PIO::PIO.input_sync_bypass().write_set(|w| *w = mask); + } else { + PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask); + } } } @@ -336,18 +338,19 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn restart(&mut self) { + let mask = 1u8 << Self::Sm::SM_NO; unsafe { - Self::Pio::PIO - .ctrl() - .modify(|w| w.set_sm_restart(1u8 << Self::Sm::SM_NO)); + Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); } } fn set_enable(&mut self, enable: bool) { let mask = 1u8 << Self::Sm::SM_NO; unsafe { - Self::Pio::PIO - .ctrl() - .modify(|w| w.set_sm_enable((w.sm_enable() & !mask) | (if enable { mask } else { 0 }))); + if enable { + Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); + } else { + Self::Pio::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask)); + } } } @@ -419,10 +422,9 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn clkdiv_restart(&mut self) { + let mask = 1u8 << Self::Sm::SM_NO; unsafe { - Self::Pio::PIO - .ctrl() - .modify(|w| w.set_clkdiv_restart(1u8 << Self::Sm::SM_NO)); + Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); } } @@ -869,9 +871,11 @@ pub trait PioCommon: sealed::PioCommon + Sized { fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { unsafe { - Self::Pio::PIO - .input_sync_bypass() - .modify(|w| *w = (*w & !mask) | (bypass & mask)); + // this can interfere with per-pin bypass functions. splitting the + // modification is going to be fine since nothing that relies on + // it can reasonably run before we finish. + Self::Pio::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); + Self::Pio::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); } } From 3229b5e809688d99a592bbfd1f803e1fb9d62050 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 26 Apr 2023 00:23:18 +0200 Subject: [PATCH 06/10] rp/pio: remove PioPeripheral merge into PioInstance instead. PioPeripheral was mostly a wrapper around PioInstance anyway, and the way the wrapping was done required PioInstanceBase types where PIO{N} could've been used instead. --- embassy-rp/src/pio.rs | 64 ++++++++++-------------------- examples/rp/src/bin/pio_async.rs | 16 ++++---- examples/rp/src/bin/pio_dma.rs | 2 +- examples/rp/src/bin/pio_hd44780.rs | 5 +-- examples/rp/src/bin/ws2812-pio.rs | 4 +- 5 files changed, 33 insertions(+), 58 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index e9a67fd4..459b7806 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -904,19 +904,19 @@ impl sealed::SmInstance for SmInstanceBase { } impl SmInstance for SmInstanceBase {} -pub trait PioPeripheral: sealed::PioPeripheral + Sized { +pub trait PioInstance: sealed::PioInstance + Sized + Unpin { fn pio(&self) -> u8 { - Self::Pio::PIO_NO + Self::PIO_NO } fn split( self, ) -> ( - PioCommonInstance, - PioStateMachineInstance>, - PioStateMachineInstance>, - PioStateMachineInstance>, - PioStateMachineInstance>, + PioCommonInstance, + PioStateMachineInstance>, + PioStateMachineInstance>, + PioStateMachineInstance>, + PioStateMachineInstance>, ) { ( PioCommonInstance { @@ -944,12 +944,6 @@ pub trait PioPeripheral: sealed::PioPeripheral + Sized { } mod sealed { - pub trait PioInstance { - const PIO_NO: u8; - const PIO: &'static crate::pac::pio::Pio; - const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; - } - pub trait PioCommon { type Pio: super::PioInstance; } @@ -968,46 +962,28 @@ mod sealed { const SM_NO: u8; } - pub trait PioPeripheral { - type Pio: super::PioInstance; + pub trait PioInstance { + const PIO_NO: u8; + const PIO: &'static crate::pac::pio::Pio; + const FUNCSEL: crate::pac::io::vals::Gpio0ctrlFuncsel; } } -// Identifies a specific PIO device -pub struct PioInstanceBase {} - -pub trait PioInstance: sealed::PioInstance + Unpin {} - -impl sealed::PioInstance for PioInstanceBase<0> { - const PIO_NO: u8 = 0; - const PIO: &'static pac::pio::Pio = &pac::PIO0; - const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::PIO0_0; -} -impl PioInstance for PioInstanceBase<0> {} - -impl sealed::PioInstance for PioInstanceBase<1> { - const PIO_NO: u8 = 1; - const PIO: &'static pac::pio::Pio = &pac::PIO1; - const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::PIO1_0; -} -impl PioInstance for PioInstanceBase<1> {} - -pub type Pio0 = PioInstanceBase<0>; -pub type Pio1 = PioInstanceBase<1>; - pub type Sm0 = SmInstanceBase<0>; pub type Sm1 = SmInstanceBase<1>; pub type Sm2 = SmInstanceBase<2>; pub type Sm3 = SmInstanceBase<3>; -macro_rules! impl_pio_sm { - ($name:ident, $pio:expr) => { - impl sealed::PioPeripheral for peripherals::$name { - type Pio = PioInstanceBase<$pio>; +macro_rules! impl_pio { + ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { + impl sealed::PioInstance for peripherals::$name { + const PIO_NO: u8 = $pio; + const PIO: &'static pac::pio::Pio = &pac::$pac; + const FUNCSEL: pac::io::vals::Gpio0ctrlFuncsel = pac::io::vals::Gpio0ctrlFuncsel::$funcsel; } - impl PioPeripheral for peripherals::$name {} + impl PioInstance for peripherals::$name {} }; } -impl_pio_sm!(PIO0, 0); -impl_pio_sm!(PIO1, 1); +impl_pio!(PIO0, 0, PIO0, PIO0_0); +impl_pio!(PIO1, 1, PIO1, PIO1_0); diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 1b075b8f..16a09327 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -4,15 +4,15 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{AnyPin, Pin}; +use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{ - Pio0, PioCommon, PioCommonInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, - Sm1, Sm2, + PioCommon, PioCommonInstance, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2, }; 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 PioCommonInstance, sm: &mut PioStateMachineInstance, pin: AnyPin) { +fn setup_pio_task_sm0(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance, pin: AnyPin) { // Setup sm0 // Send data serially to pin @@ -40,7 +40,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm0(mut sm: PioStateMachineInstance) { +async fn pio_task_sm0(mut sm: PioStateMachineInstance) { sm.set_enable(true); let mut v = 0x0f0caffa; @@ -51,7 +51,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance) { } } -fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full @@ -70,7 +70,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm1(mut sm: PioStateMachineInstance) { +async fn pio_task_sm1(mut sm: PioStateMachineInstance) { sm.set_enable(true); loop { let rx = sm.wait_pull().await; @@ -78,7 +78,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance) { } } -fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { // Setup sm2 // Repeatedly trigger IRQ 3 @@ -102,7 +102,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm2(mut sm: PioStateMachineInstance) { +async fn pio_task_sm2(mut sm: PioStateMachineInstance) { sm.set_enable(true); loop { sm.wait_irq(3).await; diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 7d4919f7..ccbc70fe 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::{PioCommon, PioPeripheral, PioStateMachine, ShiftDirection}; +use embassy_rp::pio::{PioCommon, PioInstance, PioStateMachine, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 6bcd0652..1b24897b 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -9,8 +9,7 @@ use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::gpio::Pin; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{ - FifoJoin, PioCommon, PioInstanceBase, PioPeripheral, PioStateMachine, PioStateMachineInstance, ShiftDirection, - SmInstanceBase, + FifoJoin, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstanceBase, }; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; @@ -68,7 +67,7 @@ async fn main(_spawner: Spawner) { pub struct HD44780<'l> { dma: PeripheralRef<'l, AnyChannel>, - sm: PioStateMachineInstance, SmInstanceBase<0>>, + sm: PioStateMachineInstance>, buf: [u8; 40], } diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 041e8ae1..592caf24 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -6,8 +6,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{self, Pin}; use embassy_rp::pio::{ - FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioPeripheral, PioStateMachine, PioStateMachineInstance, - ShiftDirection, SmInstance, + FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, + SmInstance, }; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; From ac111f40d894dec12106638e47317d13728c52a1 Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 2 May 2023 13:46:51 +0200 Subject: [PATCH 07/10] rp/pio: fix PioPin::set_pull, set_schmitt comment --- embassy-rp/src/pio.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 459b7806..27a6068f 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -277,15 +277,14 @@ impl PioPin { #[inline] pub fn set_pull(&mut self, pull: Pull) { unsafe { - self.pad_ctrl().modify(|w| match pull { - Pull::Up => w.set_pue(true), - Pull::Down => w.set_pde(true), - Pull::None => {} + self.pad_ctrl().modify(|w| { + w.set_pue(pull == Pull::Up); + w.set_pde(pull == Pull::Down); }); } } - /// Set the pin's pull. + /// Set the pin's schmitt trigger. #[inline] pub fn set_schmitt(&mut self, enable: bool) { unsafe { From 8839f3f62ab85a1abd066fcbfa15693965e6fae8 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 26 Apr 2023 19:43:57 +0200 Subject: [PATCH 08/10] rp/pio: PioInstance::split -> Pio::new not requiring a PioInstance for splitting lets us split from a PeripheralRef or borrowed PIO as well, mirroring every other peripheral in embassy_rp. pio pins still have to be constructed from owned pin instances for now. --- embassy-rp/src/pio.rs | 92 +++++++++++++++--------------- examples/rp/src/bin/pio_async.rs | 22 ++++--- examples/rp/src/bin/pio_dma.rs | 10 +++- examples/rp/src/bin/pio_hd44780.rs | 10 ++-- examples/rp/src/bin/ws2812-pio.rs | 18 +++--- 5 files changed, 85 insertions(+), 67 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 27a6068f..97e97b74 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -5,7 +5,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use core::task::{Context, Poll}; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; -use embassy_hal_common::PeripheralRef; +use embassy_hal_common::{Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use crate::dma::{Channel, Transfer, Word}; @@ -316,16 +316,16 @@ impl SealedPin for PioPin { } } -pub struct PioStateMachineInstance { - pio: PhantomData, +pub struct PioStateMachineInstance<'d, PIO: PioInstance, SM: SmInstance> { + pio: PhantomData<&'d PIO>, sm: PhantomData, } -impl sealed::PioStateMachine for PioStateMachineInstance { +impl<'d, PIO: PioInstance, SM: SmInstance> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { type Pio = PIO; type Sm = SM; } -impl PioStateMachine for PioStateMachineInstance {} +impl<'d, PIO: PioInstance, SM: SmInstance> PioStateMachine for PioStateMachineInstance<'d, PIO, SM> {} pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn pio_no(&self) -> u8 { @@ -792,21 +792,21 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } -pub struct PioCommonInstance { +pub struct PioCommonInstance<'d, PIO: PioInstance> { instructions_used: u32, - pio: PhantomData, + pio: PhantomData<&'d PIO>, } -pub struct PioInstanceMemory { +pub struct PioInstanceMemory<'d, PIO: PioInstance> { used_mask: u32, - pio: PhantomData, + pio: PhantomData<&'d PIO>, } -impl sealed::PioCommon for PioCommonInstance { +impl<'d, PIO: PioInstance> sealed::PioCommon for PioCommonInstance<'d, PIO> { type Pio = PIO; } -impl PioCommon for PioCommonInstance { - fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory +impl<'d, PIO: PioInstance> PioCommon for PioCommonInstance<'d, PIO> { + fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, Self::Pio> where I: Iterator, { @@ -903,43 +903,45 @@ impl sealed::SmInstance for SmInstanceBase { } impl SmInstance for SmInstanceBase {} +pub struct Pio<'d, PIO: PioInstance> { + pub common: PioCommonInstance<'d, PIO>, + pub sm0: PioStateMachineInstance<'d, PIO, SmInstanceBase<0>>, + pub sm1: PioStateMachineInstance<'d, PIO, SmInstanceBase<1>>, + pub sm2: PioStateMachineInstance<'d, PIO, SmInstanceBase<2>>, + pub sm3: PioStateMachineInstance<'d, PIO, SmInstanceBase<3>>, +} + +impl<'d, PIO: PioInstance> Pio<'d, PIO> { + pub fn new(_pio: impl Peripheral

+ 'd) -> Self { + Self { + common: PioCommonInstance { + instructions_used: 0, + pio: PhantomData, + }, + sm0: PioStateMachineInstance { + sm: PhantomData, + pio: PhantomData, + }, + sm1: PioStateMachineInstance { + sm: PhantomData, + pio: PhantomData, + }, + sm2: PioStateMachineInstance { + sm: PhantomData, + pio: PhantomData, + }, + sm3: PioStateMachineInstance { + sm: PhantomData, + pio: PhantomData, + }, + } + } +} + pub trait PioInstance: sealed::PioInstance + Sized + Unpin { fn pio(&self) -> u8 { Self::PIO_NO } - - fn split( - self, - ) -> ( - PioCommonInstance, - PioStateMachineInstance>, - PioStateMachineInstance>, - PioStateMachineInstance>, - PioStateMachineInstance>, - ) { - ( - PioCommonInstance { - instructions_used: 0, - pio: PhantomData::default(), - }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - PioStateMachineInstance { - sm: PhantomData::default(), - pio: PhantomData::default(), - }, - ) - } } mod sealed { diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 16a09327..69a22f23 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_rp::gpio::{AnyPin, Pin}; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{ - PioCommon, PioCommonInstance, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2, + Pio, PioCommon, PioCommonInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2, }; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; @@ -40,7 +40,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm0(mut sm: PioStateMachineInstance) { +async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, Sm0>) { sm.set_enable(true); let mut v = 0x0f0caffa; @@ -70,7 +70,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm1(mut sm: PioStateMachineInstance) { +async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, Sm1>) { sm.set_enable(true); loop { let rx = sm.wait_pull().await; @@ -102,7 +102,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachin } #[embassy_executor::task] -async fn pio_task_sm2(mut sm: PioStateMachineInstance) { +async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, Sm2>) { sm.set_enable(true); loop { sm.wait_irq(3).await; @@ -115,11 +115,17 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); let pio = p.PIO0; - let (mut pio0, mut sm0, mut sm1, mut sm2, ..) = pio.split(); + let Pio { + mut common, + mut sm0, + mut sm1, + mut sm2, + .. + } = Pio::new(pio); - setup_pio_task_sm0(&mut pio0, &mut sm0, p.PIN_0.degrade()); - setup_pio_task_sm1(&mut pio0, &mut sm1); - setup_pio_task_sm2(&mut pio0, &mut sm2); + setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0.degrade()); + 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(); diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index ccbc70fe..33c320b8 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::{PioCommon, PioInstance, PioStateMachine, ShiftDirection}; +use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; @@ -19,7 +19,11 @@ fn swap_nibbles(v: u32) -> u32 { async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let pio = p.PIO0; - let (mut pio0, mut sm, ..) = pio.split(); + let Pio { + mut common, + sm0: mut sm, + .. + } = Pio::new(pio); let prg = pio_proc::pio_asm!( ".origin 0", @@ -34,7 +38,7 @@ async fn main(_spawner: Spawner) { ); let relocated = RelocatedProgram::new(&prg.program); - pio0.write_instr(relocated.origin() as usize, relocated.code()); + common.write_instr(relocated.origin() as usize, relocated.code()); pio_instr_util::exec_jmp(&mut sm, relocated.origin()); sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); let pio::Wrap { source, target } = relocated.wrap(); diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 1b24897b..994d4600 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -9,7 +9,7 @@ use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::gpio::Pin; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{ - FifoJoin, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstanceBase, + FifoJoin, Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstanceBase, }; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; @@ -67,14 +67,14 @@ async fn main(_spawner: Spawner) { pub struct HD44780<'l> { dma: PeripheralRef<'l, AnyChannel>, - sm: PioStateMachineInstance>, + sm: PioStateMachineInstance<'l, PIO0, SmInstanceBase<0>>, buf: [u8; 40], } impl<'l> HD44780<'l> { pub async fn new( - pio: PIO0, + pio: impl Peripheral

+ 'l, dma: impl Peripheral

+ 'l, rs: impl Pin, rw: impl Pin, @@ -87,7 +87,9 @@ impl<'l> HD44780<'l> { into_ref!(dma); let db7pin = db7.pin(); - let (mut common, mut sm0, ..) = pio.split(); + let Pio { + mut common, mut sm0, .. + } = Pio::new(pio); // takes command words ( <0:4>) let prg = pio_proc::pio_asm!( diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 592caf24..42c731bd 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -6,7 +6,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{self, Pin}; use embassy_rp::pio::{ - FifoJoin, PioCommon, PioCommonInstance, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, + FifoJoin, Pio, PioCommon, PioCommonInstance, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstance, }; use embassy_rp::pio_instr_util; @@ -14,12 +14,16 @@ use embassy_rp::relocate::RelocatedProgram; use embassy_time::{Duration, Timer}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; -pub struct Ws2812 { - sm: PioStateMachineInstance, +pub struct Ws2812<'d, P: PioInstance, S: SmInstance> { + sm: PioStateMachineInstance<'d, P, S>, } -impl Ws2812 { - pub fn new(mut pio: PioCommonInstance

, mut sm: PioStateMachineInstance, pin: gpio::AnyPin) -> Self { +impl<'d, P: PioInstance, S: SmInstance> Ws2812<'d, P, S> { + pub fn new( + mut pio: PioCommonInstance<'d, P>, + mut sm: PioStateMachineInstance<'d, P, S>, + pin: gpio::AnyPin, + ) -> Self { // Setup sm0 // prepare the PIO program @@ -116,7 +120,7 @@ async fn main(_spawner: Spawner) { info!("Start"); let p = embassy_rp::init(Default::default()); - let (pio0, sm0, _sm1, _sm2, _sm3) = p.PIO0.split(); + let Pio { common, sm0, .. } = Pio::new(p.PIO0); // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit // feather boards for the 2040 both have one built in. @@ -125,7 +129,7 @@ async fn main(_spawner: Spawner) { // For the thing plus, use pin 8 // For the feather, use pin 16 - let mut ws2812 = Ws2812::new(pio0, sm0, p.PIN_8.degrade()); + let mut ws2812 = Ws2812::new(common, sm0, p.PIN_8.degrade()); // Loop forever making RGB values and pushing them out to the WS2812. loop { From a167c77d3928e1304ccccec6ddf7572d1e3c4cd9 Mon Sep 17 00:00:00 2001 From: pennae Date: Wed, 26 Apr 2023 20:27:31 +0200 Subject: [PATCH 09/10] rp/pio: make PioCommon a struct the PioCommon trait does not serve much of a purpose; there can be only two implementations and they only differ in a few associated constants. --- embassy-rp/src/pio.rs | 59 +++++++++++------------------- examples/rp/src/bin/pio_async.rs | 10 ++--- examples/rp/src/bin/pio_dma.rs | 2 +- examples/rp/src/bin/pio_hd44780.rs | 4 +- examples/rp/src/bin/ws2812-pio.rs | 9 +---- 5 files changed, 30 insertions(+), 54 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 97e97b74..6827e511 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -792,7 +792,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } } -pub struct PioCommonInstance<'d, PIO: PioInstance> { +pub struct PioCommon<'d, PIO: PioInstance> { instructions_used: u32, pio: PhantomData<&'d PIO>, } @@ -802,11 +802,8 @@ pub struct PioInstanceMemory<'d, PIO: PioInstance> { pio: PhantomData<&'d PIO>, } -impl<'d, PIO: PioInstance> sealed::PioCommon for PioCommonInstance<'d, PIO> { - type Pio = PIO; -} -impl<'d, PIO: PioInstance> PioCommon for PioCommonInstance<'d, PIO> { - fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, Self::Pio> +impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { + pub fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory<'d, PIO> where I: Iterator, { @@ -833,58 +830,50 @@ impl<'d, PIO: PioInstance> PioCommon for PioCommonInstance<'d, PIO> { } } - fn free_instr(&mut self, instrs: PioInstanceMemory) { + // TODO make instruction memory that is currently in use unfreeable + pub fn free_instr(&mut self, instrs: PioInstanceMemory) { self.instructions_used &= !instrs.used_mask; } -} -pub trait PioCommon: sealed::PioCommon + Sized { - fn write_instr(&mut self, start: usize, instrs: I) -> PioInstanceMemory - where - I: Iterator; - - // TODO make instruction memory that is currently in use unfreeable - fn free_instr(&mut self, instrs: PioInstanceMemory); - - fn is_irq_set(&self, irq_no: u8) -> bool { + pub fn is_irq_set(&self, irq_no: u8) -> bool { assert!(irq_no < 8); unsafe { - let irq_flags = Self::Pio::PIO.irq(); + let irq_flags = PIO::PIO.irq(); irq_flags.read().0 & (1 << irq_no) != 0 } } - fn clear_irq(&mut self, irq_no: usize) { + pub fn clear_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); - unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } + unsafe { PIO::PIO.irq().write(|w| w.set_irq(1 << irq_no)) } } - fn clear_irqs(&mut self, mask: u8) { - unsafe { Self::Pio::PIO.irq().write(|w| w.set_irq(mask)) } + pub fn clear_irqs(&mut self, mask: u8) { + unsafe { PIO::PIO.irq().write(|w| w.set_irq(mask)) } } - fn force_irq(&mut self, irq_no: usize) { + pub fn force_irq(&mut self, irq_no: usize) { assert!(irq_no < 8); - unsafe { Self::Pio::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } + unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(1 << irq_no)) } } - fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) { + 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 // modification is going to be fine since nothing that relies on // it can reasonably run before we finish. - Self::Pio::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); - Self::Pio::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); + PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass); + PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass); } } - fn get_input_sync_bypass(&self) -> u32 { - unsafe { Self::Pio::PIO.input_sync_bypass().read() } + pub fn get_input_sync_bypass(&self) -> u32 { + unsafe { PIO::PIO.input_sync_bypass().read() } } - fn make_pio_pin(&self, pin: impl Pin) -> PioPin { + pub fn make_pio_pin(&self, pin: impl Pin) -> PioPin { unsafe { - pin.io().ctrl().write(|w| w.set_funcsel(Self::Pio::FUNCSEL.0)); + pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); } PioPin { pin_bank: pin.pin_bank(), @@ -904,7 +893,7 @@ impl sealed::SmInstance for SmInstanceBase { impl SmInstance for SmInstanceBase {} pub struct Pio<'d, PIO: PioInstance> { - pub common: PioCommonInstance<'d, PIO>, + pub common: PioCommon<'d, PIO>, pub sm0: PioStateMachineInstance<'d, PIO, SmInstanceBase<0>>, pub sm1: PioStateMachineInstance<'d, PIO, SmInstanceBase<1>>, pub sm2: PioStateMachineInstance<'d, PIO, SmInstanceBase<2>>, @@ -914,7 +903,7 @@ pub struct Pio<'d, PIO: PioInstance> { impl<'d, PIO: PioInstance> Pio<'d, PIO> { pub fn new(_pio: impl Peripheral

+ 'd) -> Self { Self { - common: PioCommonInstance { + common: PioCommon { instructions_used: 0, pio: PhantomData, }, @@ -945,10 +934,6 @@ pub trait PioInstance: sealed::PioInstance + Sized + Unpin { } mod sealed { - pub trait PioCommon { - type Pio: super::PioInstance; - } - pub trait PioStateMachine { type Pio: super::PioInstance; type Sm: super::SmInstance; diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 69a22f23..50b001b6 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -5,14 +5,12 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::gpio::{AnyPin, Pin}; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Pio, PioCommon, PioCommonInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2, -}; +use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection, Sm0, Sm1, Sm2}; 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 PioCommonInstance, sm: &mut PioStateMachineInstance, pin: AnyPin) { +fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachineInstance, pin: AnyPin) { // Setup sm0 // Send data serially to pin @@ -51,7 +49,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, Sm0>) { } } -fn setup_pio_task_sm1(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full @@ -78,7 +76,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, Sm1>) { } } -fn setup_pio_task_sm2(pio: &mut PioCommonInstance, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { // Setup sm2 // Repeatedly trigger IRQ 3 diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 33c320b8..0f1f6df1 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, PioCommon, PioStateMachine, ShiftDirection}; +use embassy_rp::pio::{Pio, PioStateMachine, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 994d4600..20c6a056 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -8,9 +8,7 @@ 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, PioCommon, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstanceBase, -}; +use embassy_rp::pio::{FifoJoin, Pio, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstanceBase}; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{into_ref, Peripheral, PeripheralRef}; diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 42c731bd..a2121df4 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -6,8 +6,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{self, Pin}; use embassy_rp::pio::{ - FifoJoin, Pio, PioCommon, PioCommonInstance, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, - SmInstance, + FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstance, }; use embassy_rp::pio_instr_util; use embassy_rp::relocate::RelocatedProgram; @@ -19,11 +18,7 @@ pub struct Ws2812<'d, P: PioInstance, S: SmInstance> { } impl<'d, P: PioInstance, S: SmInstance> Ws2812<'d, P, S> { - pub fn new( - mut pio: PioCommonInstance<'d, P>, - mut sm: PioStateMachineInstance<'d, P, S>, - pin: gpio::AnyPin, - ) -> Self { + pub fn new(mut pio: PioCommon<'d, P>, mut sm: PioStateMachineInstance<'d, P, S>, pin: gpio::AnyPin) -> Self { // Setup sm0 // prepare the PIO program From 7a36072a15b2164a903ae3f36ee251eaf311216d Mon Sep 17 00:00:00 2001 From: pennae Date: Tue, 2 May 2023 17:55:40 +0200 Subject: [PATCH 10/10] rp/pio: drop SmInstance{,Base} these are just overly convoluted ways of writing down numbers. --- embassy-rp/src/pio.rs | 130 +++++++++++------------------ examples/rp/src/bin/pio_async.rs | 14 ++-- examples/rp/src/bin/pio_hd44780.rs | 4 +- examples/rp/src/bin/ws2812-pio.rs | 6 +- 4 files changed, 60 insertions(+), 94 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 6827e511..5433d3f2 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -12,7 +12,7 @@ use crate::dma::{Channel, Transfer, Word}; use crate::gpio::sealed::Pin as SealedPin; use crate::gpio::{Drive, Pin, Pull, SlewRate}; use crate::pac::dma::vals::TreqSel; -use crate::pio::sealed::{PioInstance as _, SmInstance as _}; +use crate::pio::sealed::PioInstance as _; use crate::{interrupt, pac, peripherals, RegExt}; struct Wakers([AtomicWaker; 12]); @@ -119,10 +119,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Future for FifoOutFuture if self.get_mut().sm.try_push_tx(value) { Poll::Ready(()) } else { - WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::Sm::SM_NO as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_out()[SM::SM as usize].register(cx.waker()); unsafe { PIO::PIO.irqs(0).inte().write_set(|m| { - m.0 = TXNFULL_MASK << SM::Sm::SM_NO; + m.0 = TXNFULL_MASK << SM::SM; }); } // debug!("Pending"); @@ -135,7 +135,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine + Unpin> Drop for FifoOutFuture<' fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { - m.0 = TXNFULL_MASK << SM::Sm::SM_NO; + m.0 = TXNFULL_MASK << SM::SM; }); } } @@ -164,10 +164,10 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Future for FifoInFuture<'d, PIO, if let Some(v) = self.sm.try_pull_rx() { Poll::Ready(v) } else { - WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::Sm::SM_NO as usize].register(cx.waker()); + WAKERS[PIO::PIO_NO as usize].fifo_in()[SM::SM].register(cx.waker()); unsafe { PIO::PIO.irqs(0).inte().write_set(|m| { - m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; + m.0 = RXNEMPTY_MASK << SM::SM; }); } //debug!("Pending"); @@ -180,7 +180,7 @@ impl<'d, PIO: PioInstance, SM: PioStateMachine> Drop for FifoInFuture<'d, PIO, S fn drop(&mut self) { unsafe { PIO::PIO.irqs(0).inte().write_clear(|m| { - m.0 = RXNEMPTY_MASK << SM::Sm::SM_NO; + m.0 = RXNEMPTY_MASK << SM::SM; }); } } @@ -316,16 +316,15 @@ impl SealedPin for PioPin { } } -pub struct PioStateMachineInstance<'d, PIO: PioInstance, SM: SmInstance> { +pub struct PioStateMachineInstance<'d, PIO: PioInstance, const SM: usize> { pio: PhantomData<&'d PIO>, - sm: PhantomData, } -impl<'d, PIO: PioInstance, SM: SmInstance> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { +impl<'d, PIO: PioInstance, const SM: usize> sealed::PioStateMachine for PioStateMachineInstance<'d, PIO, SM> { type Pio = PIO; - type Sm = SM; + const SM: usize = SM; } -impl<'d, PIO: PioInstance, SM: SmInstance> PioStateMachine for PioStateMachineInstance<'d, PIO, 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 { @@ -333,17 +332,17 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn sm_no(&self) -> u8 { - Self::Sm::SM_NO + Self::SM as u8 } fn restart(&mut self) { - let mask = 1u8 << Self::Sm::SM_NO; + let mask = 1u8 << Self::SM; unsafe { Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_restart(mask)); } } fn set_enable(&mut self, enable: bool) { - let mask = 1u8 << Self::Sm::SM_NO; + let mask = 1u8 << Self::SM; unsafe { if enable { Self::Pio::PIO.ctrl().write_set(|w| w.set_sm_enable(mask)); @@ -354,40 +353,40 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn is_enabled(&self) -> bool { - unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::Sm::SM_NO) != 0 } + unsafe { Self::Pio::PIO.ctrl().read().sm_enable() & (1u8 << Self::SM) != 0 } } fn is_tx_empty(&self) -> bool { - unsafe { Self::Pio::PIO.fstat().read().txempty() & (1u8 << Self::Sm::SM_NO) != 0 } + 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::SM_NO) != 0 } + 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::SM_NO) != 0 } + 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::SM_NO) != 0 } + 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::SM_NO * 8)) as u8 & 0x0f + (flevel >> (Self::SM * 8)) as u8 & 0x0f } } fn rx_level(&self) -> u8 { unsafe { let flevel = Self::Pio::PIO.flevel().read().0; - (flevel >> (Self::Sm::SM_NO * 8 + 4)) as u8 & 0x0f + (flevel >> (Self::SM * 8 + 4)) as u8 & 0x0f } } fn push_tx(&mut self, v: u32) { unsafe { - Self::Pio::PIO.txf(Self::Sm::SM_NO as usize).write_value(v); + Self::Pio::PIO.txf(Self::SM).write_value(v); } } @@ -400,7 +399,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn pull_rx(&mut self) -> u32 { - unsafe { Self::Pio::PIO.rxf(Self::Sm::SM_NO as usize).read() } + unsafe { Self::Pio::PIO.rxf(Self::SM).read() } } fn try_pull_rx(&mut self) -> Option { @@ -421,7 +420,7 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { } fn clkdiv_restart(&mut self) { - let mask = 1u8 << Self::Sm::SM_NO; + let mask = 1u8 << Self::SM; unsafe { Self::Pio::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask)); } @@ -710,8 +709,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_tx_stalled(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().txstall() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_txstall(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().txstall() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_txstall(1 << Self::SM)); ret } } @@ -719,8 +718,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_tx_overflowed(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().txover() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_txover(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().txover() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_txover(1 << Self::SM)); ret } } @@ -728,8 +727,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_rx_stalled(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().rxstall() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_rxstall(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().rxstall() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_rxstall(1 << Self::SM)); ret } } @@ -737,8 +736,8 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { fn has_rx_underflowed(&self) -> bool { unsafe { let fdebug = Self::Pio::PIO.fdebug(); - let ret = fdebug.read().rxunder() & (1 << Self::Sm::SM_NO) != 0; - fdebug.write(|w| w.set_rxunder(1 << Self::Sm::SM_NO)); + let ret = fdebug.read().rxunder() & (1 << Self::SM) != 0; + fdebug.write(|w| w.set_rxunder(1 << Self::SM)); ret } } @@ -746,16 +745,15 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { 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::SM_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 as usize).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)); + 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); @@ -770,16 +768,15 @@ pub trait PioStateMachine: sealed::PioStateMachine + Sized + Unpin { 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::SM_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 as usize).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 + 4)); + 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); @@ -882,22 +879,12 @@ impl<'d, PIO: PioInstance> PioCommon<'d, PIO> { } } -// Identifies a specific state machine inside a PIO device -pub struct SmInstanceBase {} - -pub trait SmInstance: sealed::SmInstance + Unpin {} - -impl sealed::SmInstance for SmInstanceBase { - const SM_NO: u8 = SM_NO; -} -impl SmInstance for SmInstanceBase {} - pub struct Pio<'d, PIO: PioInstance> { pub common: PioCommon<'d, PIO>, - pub sm0: PioStateMachineInstance<'d, PIO, SmInstanceBase<0>>, - pub sm1: PioStateMachineInstance<'d, PIO, SmInstanceBase<1>>, - pub sm2: PioStateMachineInstance<'d, PIO, SmInstanceBase<2>>, - pub sm3: PioStateMachineInstance<'d, PIO, SmInstanceBase<3>>, + pub sm0: PioStateMachineInstance<'d, PIO, 0>, + pub sm1: PioStateMachineInstance<'d, PIO, 1>, + pub sm2: PioStateMachineInstance<'d, PIO, 2>, + pub sm3: PioStateMachineInstance<'d, PIO, 3>, } impl<'d, PIO: PioInstance> Pio<'d, PIO> { @@ -907,22 +894,10 @@ impl<'d, PIO: PioInstance> Pio<'d, PIO> { instructions_used: 0, pio: PhantomData, }, - sm0: PioStateMachineInstance { - sm: PhantomData, - pio: PhantomData, - }, - sm1: PioStateMachineInstance { - sm: PhantomData, - pio: PhantomData, - }, - sm2: PioStateMachineInstance { - sm: PhantomData, - pio: PhantomData, - }, - sm3: PioStateMachineInstance { - sm: PhantomData, - pio: PhantomData, - }, + sm0: PioStateMachineInstance { pio: PhantomData }, + sm1: PioStateMachineInstance { pio: PhantomData }, + sm2: PioStateMachineInstance { pio: PhantomData }, + sm3: PioStateMachineInstance { pio: PhantomData }, } } } @@ -936,18 +911,14 @@ pub trait PioInstance: sealed::PioInstance + Sized + Unpin { mod sealed { pub trait PioStateMachine { type Pio: super::PioInstance; - type Sm: super::SmInstance; + const SM: usize; #[inline(always)] fn this_sm() -> crate::pac::pio::StateMachine { - Self::Pio::PIO.sm(Self::Sm::SM_NO as usize) + Self::Pio::PIO.sm(Self::SM as usize) } } - pub trait SmInstance { - const SM_NO: u8; - } - pub trait PioInstance { const PIO_NO: u8; const PIO: &'static crate::pac::pio::Pio; @@ -955,11 +926,6 @@ mod sealed { } } -pub type Sm0 = SmInstanceBase<0>; -pub type Sm1 = SmInstanceBase<1>; -pub type Sm2 = SmInstanceBase<2>; -pub type Sm3 = SmInstanceBase<3>; - macro_rules! impl_pio { ($name:ident, $pio:expr, $pac:ident, $funcsel:ident) => { impl sealed::PioInstance for peripherals::$name { diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 50b001b6..5fea7034 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -5,12 +5,12 @@ 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, Sm0, Sm1, Sm2}; +use embassy_rp::pio::{Pio, PioCommon, PioStateMachine, PioStateMachineInstance, 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 PioStateMachineInstance, pin: AnyPin) { // Setup sm0 // Send data serially to pin @@ -38,7 +38,7 @@ fn setup_pio_task_sm0(pio: &mut PioCommon, sm: &mut PioStateMachineInstanc } #[embassy_executor::task] -async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, Sm0>) { +async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, 0>) { sm.set_enable(true); let mut v = 0x0f0caffa; @@ -49,7 +49,7 @@ async fn pio_task_sm0(mut sm: PioStateMachineInstance<'static, PIO0, Sm0>) { } } -fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full @@ -68,7 +68,7 @@ fn setup_pio_task_sm1(pio: &mut PioCommon, sm: &mut PioStateMachineInstanc } #[embassy_executor::task] -async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, Sm1>) { +async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, 1>) { sm.set_enable(true); loop { let rx = sm.wait_pull().await; @@ -76,7 +76,7 @@ async fn pio_task_sm1(mut sm: PioStateMachineInstance<'static, PIO0, Sm1>) { } } -fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { +fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachineInstance) { // Setup sm2 // Repeatedly trigger IRQ 3 @@ -100,7 +100,7 @@ fn setup_pio_task_sm2(pio: &mut PioCommon, sm: &mut PioStateMachineInstanc } #[embassy_executor::task] -async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, Sm2>) { +async fn pio_task_sm2(mut sm: PioStateMachineInstance<'static, PIO0, 2>) { sm.set_enable(true); loop { sm.wait_irq(3).await; diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 20c6a056..59b4c1f5 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -8,7 +8,7 @@ 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, SmInstanceBase}; +use embassy_rp::pio::{FifoJoin, Pio, PioStateMachine, PioStateMachineInstance, ShiftDirection}; use embassy_rp::pwm::{Config, Pwm}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{into_ref, Peripheral, PeripheralRef}; @@ -65,7 +65,7 @@ async fn main(_spawner: Spawner) { pub struct HD44780<'l> { dma: PeripheralRef<'l, AnyChannel>, - sm: PioStateMachineInstance<'l, PIO0, SmInstanceBase<0>>, + sm: PioStateMachineInstance<'l, PIO0, 0>, buf: [u8; 40], } diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index a2121df4..0975559d 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -6,18 +6,18 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{self, Pin}; use embassy_rp::pio::{ - FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, ShiftDirection, SmInstance, + FifoJoin, Pio, PioCommon, PioInstance, PioStateMachine, PioStateMachineInstance, 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, S: SmInstance> { +pub struct Ws2812<'d, P: PioInstance, const S: usize> { sm: PioStateMachineInstance<'d, P, S>, } -impl<'d, P: PioInstance, S: SmInstance> Ws2812<'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 { // Setup sm0