From 684f4838590bb5ff809ded117f34364d7c65588e Mon Sep 17 00:00:00 2001 From: Mathias Gottschlag Date: Tue, 28 Sep 2021 21:48:05 +0200 Subject: [PATCH] pio: Improve documentation and add an example that uses pio_proc::pio!(). --- Cargo.toml | 1 + rp2040-hal/Cargo.toml | 1 + rp2040-hal/examples/pio_blink.rs | 12 +++--- rp2040-hal/examples/pio_proc_blink.rs | 62 +++++++++++++++++++++++++++ rp2040-hal/src/pio.rs | 46 +++++++++++++++++--- rp2040-hal/src/prelude.rs | 1 + 6 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 rp2040-hal/examples/pio_proc_blink.rs diff --git a/Cargo.toml b/Cargo.toml index f7adced..a60908d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "rp2040-hal", "boards/feather_rp2040", diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index 6598c61..6b24fef 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -18,6 +18,7 @@ nb = "1.0" rp2040-pac = "0.1.5" paste = "1.0" pio = { git = "https://github.com/rp-rs/pio-rs.git", branch = "main" } +pio-proc = { git = "https://github.com/rp-rs/pio-rs.git", branch = "main" } usb-device = "0.2.8" vcell = "0.1" void = { version = "1.0.2", default-features = false } diff --git a/rp2040-hal/examples/pio_blink.rs b/rp2040-hal/examples/pio_blink.rs index 3a4ab6b..7e7d14b 100644 --- a/rp2040-hal/examples/pio_blink.rs +++ b/rp2040-hal/examples/pio_blink.rs @@ -7,6 +7,7 @@ use cortex_m_rt::entry; use hal::gpio::{FunctionPio0, Pin}; use hal::pac; +use hal::pio::PIOExt; use hal::sio::Sio; use panic_halt as _; use rp2040_hal as hal; @@ -53,15 +54,14 @@ fn main() -> ! { let program = a.assemble_with_wrap(wrap_source, wrap_target); // Initialize and start PIO - let pio = rp2040_hal::pio::PIO::new(pac.PIO0, &mut pac.RESETS); - let sm = &pio.state_machines()[0]; + let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); + let installed = pio.install(&program).unwrap(); let div = 0f32; // as slow as possible (0 is interpreted as 65536) - rp2040_hal::pio::PIOBuilder::default() - .with_program(&program) + let sm = rp2040_hal::pio::PIOBuilder::from_program(installed) .set_pins(led_pin_id, 1) .clock_divisor(div) - .build(&pio, sm) - .unwrap(); + .build(sm0); + sm.start(); // PIO runs in background, independently from CPU #[allow(clippy::empty_loop)] diff --git a/rp2040-hal/examples/pio_proc_blink.rs b/rp2040-hal/examples/pio_proc_blink.rs new file mode 100644 index 0000000..73942ba --- /dev/null +++ b/rp2040-hal/examples/pio_proc_blink.rs @@ -0,0 +1,62 @@ +//! This example toggles the GPIO25 pin, using a PIO program compiled via pio_proc::pio!(). +//! +//! If a LED is connected to that pin, like on a Pico board, the LED should blink. +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use hal::gpio::{FunctionPio0, Pin}; +use hal::pac; +use hal::pio::PIOExt; +use hal::sio::Sio; +use panic_halt as _; +use rp2040_hal as hal; + +#[link_section = ".boot2"] +#[used] +pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; + +#[entry] +fn main() -> ! { + let mut pac = pac::Peripherals::take().unwrap(); + + let sio = Sio::new(pac.SIO); + let pins = hal::gpio::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + // configure LED pin for Pio0. + let _led: Pin<_, FunctionPio0> = pins.gpio25.into_mode(); + // PIN id for use inside of PIO + let led_pin_id = 25; + + // Define some simple PIO program. + let program = pio_proc::pio!( + 32, + " +.wrap_target + set pins, 1 [31] + set pins, 0 [31] +.wrap + " + ); + + // Initialize and start PIO + let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); + let installed = pio.install(&program.program).unwrap(); + let div = 0f32; // as slow as possible (0 is interpreted as 65536) + let mut sm = rp2040_hal::pio::PIOBuilder::from_program(installed) + .set_pins(led_pin_id, 1) + .clock_divisor(div) + .build(sm0); + // The GPIO pin needs to be configured as an output. + sm.set_pindirs_with_mask(1 << led_pin_id, 1 << led_pin_id); + sm.start(); + + // PIO runs in background, independently from CPU + #[allow(clippy::empty_loop)] + loop {} +} diff --git a/rp2040-hal/src/pio.rs b/rp2040-hal/src/pio.rs index 1abdbb6..034b3c5 100644 --- a/rp2040-hal/src/pio.rs +++ b/rp2040-hal/src/pio.rs @@ -96,6 +96,8 @@ unsafe impl Send for PIO

{} impl PIO

{ /// Free this instance. + /// + /// All output pins are left in their current state. pub fn free( self, _sm0: UninitStateMachine

, @@ -103,7 +105,7 @@ impl PIO

{ _sm2: UninitStateMachine

, _sm3: UninitStateMachine

, ) -> P { - // TODO: Disable the PIO block. + // All state machines have already been stopped. self.pio } @@ -242,7 +244,19 @@ impl PIO

{ /// `PIO::uninstall(program)` can be used to free the space occupied by the program once it is no /// longer used. /// -/// TODO: Write an example? +/// # Examples +/// +/// ``` +/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +/// // Install a program in instruction memory. +/// let installed = pio.install(&program).unwrap(); +/// // Configure a state machine to use the program. +/// let sm = rp2040_hal::pio::PIOBuilder::from_program(installed).build(sm0); +/// // Uninitialize the state machine again, freeing the program. +/// let (sm, installed) = sm.uninit(); +/// // Uninstall the program to free instruction memory. +/// pio.uninstall(installed); +/// ``` /// /// # Safety /// @@ -251,7 +265,16 @@ impl PIO

{ /// the program anymore. The user must therefore make sure that `uninstall()` is only called on the /// PIO object which was used to install the program. /// -/// TODO: Write an example? +/// ``` +/// let (mut pio, sm0, sm1, sm2, sm3) = pac.PIO0.split(&mut pac.RESETS); +/// // Install a program in instruction memory. +/// let installed = pio.install(&program).unwrap(); +/// // Reinitialize PIO. +/// let pio0 = pio.free(sm0, sm1, sm2, sm3); +/// let (mut pio, _, _, _, _) = pio0.split(&mut pac.RESETS); +/// // Do not do the following, the program is not in instruction memory anymore! +/// pio.uninstall(installed); +/// ``` #[derive(Debug)] pub struct InstalledProgram

{ offset: u8, @@ -350,7 +373,6 @@ impl UninitStateMachine

{ /// Set the current instruction. fn set_instruction(&mut self, instruction: u16) { - // TODO: Check if this function is safe to call while the state machine is running. self.sm() .sm_instr .write(|w| unsafe { w.sm0_instr().bits(instruction) }) @@ -361,6 +383,7 @@ impl UninitStateMachine

{ } } +/// PIO State Machine with an associated program. pub struct StateMachine { sm: UninitStateMachine

, program: InstalledProgram

, @@ -373,6 +396,10 @@ pub struct Stopped; pub struct Running; impl StateMachine { + /// Stops the state machine if it is still running and returns its program. + /// + /// The program can be uninstalled to free space once it is no longer used by any state + /// machine. pub fn uninit(mut self) -> (UninitStateMachine

, InstalledProgram

) { self.sm.set_enabled(false); (self.sm, self.program) @@ -385,6 +412,7 @@ impl StateMachine { /// Set the current instruction. pub fn set_instruction(&mut self, instruction: u16) { + // TODO: Check if this function is safe to call while the state machine is running. self.sm.set_instruction(instruction); } @@ -445,6 +473,15 @@ impl StateMachine { } } + /// Sets the pin directions for the specified pins. + /// + /// The `pins` parameter specifies a set of pins as a mask, and `pindir` contains the + /// directions that are configured for these pins. The bits in both masks correspond to the pin + /// number. The user has to make sure that they do not select any pins that are in use by any + /// other state machines of the same PIO block. + /// + /// This function needs to be called for sideset pins if they are supposed to be used as + /// output pins. pub fn set_pindirs_with_mask(&mut self, mut pins: u32, pindir: u32) { let mut pin = 0; let prev_pinctrl = self.sm.sm().sm_pinctrl.read().bits(); @@ -984,7 +1021,6 @@ impl PIOBuilder

{ /// Build the config and deploy it to a StateMachine. pub fn build(self, mut sm: UninitStateMachine

) -> StateMachine { - // TODO: Currently, the program is just lost and can never be uninstalled again. let offset = self.program.offset; // Stop the SM diff --git a/rp2040-hal/src/prelude.rs b/rp2040-hal/src/prelude.rs index 49bdc3c..447c72b 100644 --- a/rp2040-hal/src/prelude.rs +++ b/rp2040-hal/src/prelude.rs @@ -1,2 +1,3 @@ //! Prelude pub use crate::clocks::Clock as _rphal_clocks_Clock; +pub use crate::pio::PIOExt as _rphal_pio_PIOExt;