diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 29a8a3c53a..c1fb533ead 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -139,7 +139,7 @@ embedded-hal-async = { version = "1.0" } embedded-hal-nb = { version = "1.0" } pio-proc = {version= "0.2" } -pio = {version= "0.2.1" } +pio = { version= "0.2.1" } rp2040-boot2 = "0.3" document-features = "0.2.7" sha2-const-stable = "0.1" @@ -148,3 +148,8 @@ rp-binary-info = { version = "0.1.0", optional = true } [dev-dependencies] embassy-executor = { version = "0.6.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] } static_cell = { version = "2" } + +[patch.crates-io] +pio = { git="https://github.com/CBJamo/pio-rs.git", rev="72a5a7daa859b9d8a416564a2fbf849f58e51639" } +pio-parser = { git="https://github.com/CBJamo/pio-rs.git", rev="72a5a7daa859b9d8a416564a2fbf849f58e51639" } +pio-proc = { git="https://github.com/CBJamo/pio-rs.git", rev="72a5a7daa859b9d8a416564a2fbf849f58e51639" } \ No newline at end of file diff --git a/embassy-rp/src/pio/mod.rs b/embassy-rp/src/pio/mod.rs index 72aa8f1049..cdac87a215 100644 --- a/embassy-rp/src/pio/mod.rs +++ b/embassy-rp/src/pio/mod.rs @@ -50,6 +50,18 @@ pub enum FifoJoin { RxOnly, /// Tx fifo twice as deep. RX fifo disabled TxOnly, + /// Enable random writes (`FJOIN_RX_PUT`) from the state machine (through ISR), + /// and random reads from the system (using [`StateMachine::get_rxf_entry`]). + #[cfg(feature = "_rp235x")] + RxAsStatus, + /// Enable random reads (`FJOIN_RX_GET`) from the state machine (through OSR), + /// and random writes from the system (using [`StateMachine::set_rxf_entry`]). + #[cfg(feature = "_rp235x")] + RxAsControl, + /// FJOIN_RX_PUT | FJOIN_RX_GET: RX can be used as a scratch register, + /// not accesible from the CPU + #[cfg(feature = "_rp235x")] + PioScratch, } /// Shift direction. @@ -730,6 +742,17 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { w.set_in_shiftdir(config.shift_in.direction == ShiftDirection::Right); w.set_autopull(config.shift_out.auto_fill); w.set_autopush(config.shift_in.auto_fill); + + #[cfg(feature = "_rp235x")] + { + w.set_fjoin_rx_get( + config.fifo_join == FifoJoin::RxAsControl || config.fifo_join == FifoJoin::PioScratch, + ); + w.set_fjoin_rx_put( + config.fifo_join == FifoJoin::RxAsStatus || config.fifo_join == FifoJoin::PioScratch, + ); + w.set_in_count(config.in_count); + } }); #[cfg(feature = "rp2040")] @@ -907,6 +930,20 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { pub fn rx_tx(&mut self) -> (&mut StateMachineRx<'d, PIO, SM>, &mut StateMachineTx<'d, PIO, SM>) { (&mut self.rx, &mut self.tx) } + + /// Return the contents of the nth entry of the RX FIFO + /// (should be used only when the FIFO config is set to [`FifoJoin::RxAsStatus`]) + #[cfg(feature = "_rp235x")] + pub fn get_rxf_entry(&self, n: usize) -> u32 { + PIO::PIO.rxf_putget(SM).putget(n).read() + } + + /// Set the contents of the nth entry of the RX FIFO + /// (should be used only when the FIFO config is set to [`FifoJoin::RxAsControl`]) + #[cfg(feature = "_rp235x")] + pub fn set_rxf_entry(&self, n: usize, val: u32) { + PIO::PIO.rxf_putget(SM).putget(n).write_value(val) + } } /// PIO handle. @@ -1053,6 +1090,12 @@ impl<'d, PIO: Instance> Common<'d, PIO> { /// of [`Pio`] do not keep pin registrations alive.** pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); + + // enable the outputs + pin.pad_ctrl().write(|w| w.set_od(false)); + // especially important on the 235x, where IE defaults to 0 + pin.pad_ctrl().write(|w| w.set_ie(true)); + pin.gpio().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); #[cfg(feature = "_rp235x")] pin.pad_ctrl().modify(|w| { diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml index 087f6fd698..0addc74374 100644 --- a/examples/rp23/Cargo.toml +++ b/examples/rp23/Cargo.toml @@ -54,8 +54,8 @@ embedded-storage = { version = "0.3" } static_cell = "2.1" portable-atomic = { version = "1.5", features = ["critical-section"] } log = "0.4" -pio-proc = "0.2" -pio = "0.2.1" +pio-proc = { version = "0.2", feature = ["rp2350"] } +pio = { version = "0.2.1", feature = ["rp2350"] } rand = { version = "0.8.5", default-features = false } embedded-sdmmc = "0.7.0" @@ -77,3 +77,7 @@ embassy-futures = { path = "../../embassy-futures" } embassy-time = { path = "../../embassy-time" } embassy-time-driver = { path = "../../embassy-time-driver" } embassy-embedded-hal = { path = "../../embassy-embedded-hal" } + +pio = { git="https://github.com/CBJamo/pio-rs.git", rev="72a5a7daa859b9d8a416564a2fbf849f58e51639" } +pio-parser = { git="https://github.com/CBJamo/pio-rs.git", rev="72a5a7daa859b9d8a416564a2fbf849f58e51639" } +pio-proc = { git="https://github.com/CBJamo/pio-rs.git", rev="72a5a7daa859b9d8a416564a2fbf849f58e51639" } \ No newline at end of file diff --git a/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs new file mode 100644 index 0000000000..7a1046610a --- /dev/null +++ b/examples/rp23/src/bin/pio_rotary_encoder_rxf.rs @@ -0,0 +1,116 @@ +//! This example shows how to use the PIO module in the RP235x to read a quadrature rotary encoder. +//! It differs from the other example in that it uses the RX FIFO as a status register + +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_rp::block::ImageDef; +use embassy_rp::gpio::Pull; +use embassy_rp::peripherals::PIO0; +use embassy_rp::{bind_interrupts, pio}; +use embassy_time::Timer; +use fixed::traits::ToFixed; +use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use {defmt_rtt as _, panic_probe as _}; + +#[link_section = ".start_block"] +#[used] +pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe(); + +// Program metadata for `picotool info` +#[link_section = ".bi_entries"] +#[used] +pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ + embassy_rp::binary_info::rp_program_name!(c"example_pio_rotary_encoder_rxf"), + embassy_rp::binary_info::rp_cargo_version!(), + embassy_rp::binary_info::rp_program_description!(c"Rotary encoder (RXF)"), + embassy_rp::binary_info::rp_program_build_attribute!(), +]; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +pub struct PioEncoder<'d, T: Instance, const SM: usize> { + sm: StateMachine<'d, T, SM>, +} + +impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { + pub fn new( + pio: &mut Common<'d, T>, + mut sm: StateMachine<'d, T, SM>, + pin_a: impl PioPin, + pin_b: impl PioPin, + ) -> Self { + let mut pin_a = pio.make_pio_pin(pin_a); + let mut pin_b = pio.make_pio_pin(pin_b); + pin_a.set_pull(Pull::Up); + pin_b.set_pull(Pull::Up); + + sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); + + let prg = pio_proc::pio_asm!( + "start:" + // encoder count is stored in X + "mov isr, x" + // and then moved to the RX FIFO register + "mov rxfifo[0], isr" + + // wait for encoder transition + "wait 1 pin 1" + "wait 0 pin 1" + + "set y, 0" + "mov y, pins[1]" + + // update X depending on pin 1 + "jmp !y decr" + + // this is just a clever way of doing x++ + "mov x, ~x" + "jmp x--, incr" + "incr:" + "mov x, ~x" + "jmp start" + + // and this is x-- + "decr:" + "jmp x--, start" + ); + + let mut cfg = Config::default(); + cfg.set_in_pins(&[&pin_a, &pin_b]); + cfg.fifo_join = FifoJoin::RxAsStatus; + cfg.shift_in.direction = ShiftDirection::Left; + cfg.clock_divider = 10_000.to_fixed(); + cfg.use_program(&pio.load_program(&prg.program), &[]); + sm.set_config(&cfg); + + sm.set_enable(true); + Self { sm } + } + + pub async fn read(&mut self) -> u32 { + self.sm.get_rxf_entry(0) + } +} + +pub enum Direction { + Clockwise, + CounterClockwise, +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); + + let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); + + loop { + info!("Count: {}", encoder.read().await); + Timer::after_millis(1000).await; + } +}