mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-23 20:51:31 +11:00
pio: Improve documentation and add an example that uses pio_proc::pio!().
This commit is contained in:
parent
515eac5553
commit
684f483859
|
@ -1,4 +1,5 @@
|
|||
[workspace]
|
||||
resolver = "2"
|
||||
members = [
|
||||
"rp2040-hal",
|
||||
"boards/feather_rp2040",
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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)]
|
||||
|
|
62
rp2040-hal/examples/pio_proc_blink.rs
Normal file
62
rp2040-hal/examples/pio_proc_blink.rs
Normal file
|
@ -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 {}
|
||||
}
|
|
@ -96,6 +96,8 @@ unsafe impl<P: PIOExt + Send> Send for PIO<P> {}
|
|||
|
||||
impl<P: PIOExt> PIO<P> {
|
||||
/// Free this instance.
|
||||
///
|
||||
/// All output pins are left in their current state.
|
||||
pub fn free(
|
||||
self,
|
||||
_sm0: UninitStateMachine<P>,
|
||||
|
@ -103,7 +105,7 @@ impl<P: PIOExt> PIO<P> {
|
|||
_sm2: UninitStateMachine<P>,
|
||||
_sm3: UninitStateMachine<P>,
|
||||
) -> P {
|
||||
// TODO: Disable the PIO block.
|
||||
// All state machines have already been stopped.
|
||||
self.pio
|
||||
}
|
||||
|
||||
|
@ -242,7 +244,19 @@ impl<P: PIOExt> PIO<P> {
|
|||
/// `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<P: PIOExt> PIO<P> {
|
|||
/// 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<P> {
|
||||
offset: u8,
|
||||
|
@ -350,7 +373,6 @@ impl<P: PIOExt> UninitStateMachine<P> {
|
|||
|
||||
/// 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<P: PIOExt> UninitStateMachine<P> {
|
|||
}
|
||||
}
|
||||
|
||||
/// PIO State Machine with an associated program.
|
||||
pub struct StateMachine<P: PIOExt, State> {
|
||||
sm: UninitStateMachine<P>,
|
||||
program: InstalledProgram<P>,
|
||||
|
@ -373,6 +396,10 @@ pub struct Stopped;
|
|||
pub struct Running;
|
||||
|
||||
impl<P: PIOExt, State> StateMachine<P, State> {
|
||||
/// 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<P>, InstalledProgram<P>) {
|
||||
self.sm.set_enabled(false);
|
||||
(self.sm, self.program)
|
||||
|
@ -385,6 +412,7 @@ impl<P: PIOExt, State> StateMachine<P, State> {
|
|||
|
||||
/// 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<P: PIOExt> StateMachine<P, Stopped> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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<P: PIOExt> PIOBuilder<P> {
|
|||
|
||||
/// Build the config and deploy it to a StateMachine.
|
||||
pub fn build(self, mut sm: UninitStateMachine<P>) -> StateMachine<P, Stopped> {
|
||||
// TODO: Currently, the program is just lost and can never be uninstalled again.
|
||||
let offset = self.program.offset;
|
||||
|
||||
// Stop the SM
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
//! Prelude
|
||||
pub use crate::clocks::Clock as _rphal_clocks_Clock;
|
||||
pub use crate::pio::PIOExt as _rphal_pio_PIOExt;
|
||||
|
|
Loading…
Reference in a new issue