From 8e4d65e163bd484efc4fb31d20b14e6ac4a88de7 Mon Sep 17 00:00:00 2001 From: pennae Date: Sat, 6 May 2023 11:36:07 +0200 Subject: [PATCH] rp/pio: configure state machines with Config struct the many individual sets aren't very efficient, and almost no checks were done to ensure that the configuration written to the hardware was actually valid. this adresses both of these. --- embassy-rp/src/pio.rs | 438 ++++++++++++++--------------- examples/rp/Cargo.toml | 2 + examples/rp/src/bin/pio_async.rs | 37 +-- examples/rp/src/bin/pio_dma.rs | 27 +- examples/rp/src/bin/pio_hd44780.rs | 42 +-- examples/rp/src/bin/ws2812-pio.rs | 37 ++- 6 files changed, 299 insertions(+), 284 deletions(-) diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 8d054790..a1b7cf1c 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -6,9 +6,13 @@ use core::task::{Context, Poll}; use atomic_polyfill::{AtomicU32, AtomicU8}; use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; +use embassy_embedded_hal::SetConfig; use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +use fixed::types::extra::U8; +use fixed::FixedU32; use pac::io::vals::Gpio0ctrlFuncsel; +use pac::pio::vals::SmExecctrlStatusSel; use pio::{SideSet, Wrap}; use crate::dma::{Channel, Transfer, Word}; @@ -39,8 +43,12 @@ const NEW_AW: AtomicWaker = AtomicWaker::new(); const PIO_WAKERS_INIT: Wakers = Wakers([NEW_AW; 12]); static WAKERS: [Wakers; 2] = [PIO_WAKERS_INIT; 2]; +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] pub enum FifoJoin { /// Both TX and RX fifo is enabled + #[default] Duplex, /// Rx fifo twice as deep. TX fifo disabled RxOnly, @@ -48,8 +56,11 @@ pub enum FifoJoin { TxOnly, } -#[derive(PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] pub enum ShiftDirection { + #[default] Right = 1, Left = 0, } @@ -62,6 +73,15 @@ pub enum Direction { Out = 1, } +#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum StatusSource { + #[default] + TxFifoLevel = 0, + RxFifoLevel = 1, +} + const RXNEMPTY_MASK: u32 = 1 << 0; const TXNFULL_MASK: u32 = 1 << 4; const SMIRQ_MASK: u32 = 1 << 8; @@ -477,6 +497,202 @@ fn assert_consecutive<'d, PIO: Instance>(pins: &[&Pin<'d, PIO>]) { } } +#[derive(Clone, Copy, Default, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub struct ExecConfig { + pub side_en: bool, + pub side_pindir: bool, + pub jmp_pin: u8, + pub wrap_top: u8, + pub wrap_bottom: u8, +} + +#[derive(Clone, Copy, Default, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ShiftConfig { + pub threshold: u8, + pub direction: ShiftDirection, + pub auto_fill: bool, +} + +#[derive(Clone, Copy, Default, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct PinConfig { + pub sideset_count: u8, + pub set_count: u8, + pub out_count: u8, + pub in_base: u8, + pub sideset_base: u8, + pub set_base: u8, + pub out_base: u8, +} + +#[derive(Clone, Copy, Debug)] +pub struct Config<'d, PIO: Instance> { + // CLKDIV + pub clock_divider: FixedU32, + // EXECCTRL + pub out_en_sel: u8, + pub inline_out_en: bool, + pub out_sticky: bool, + pub status_sel: StatusSource, + pub status_n: u8, + exec: ExecConfig, + origin: Option, + // SHIFTCTRL + pub fifo_join: FifoJoin, + pub shift_in: ShiftConfig, + pub shift_out: ShiftConfig, + // PINCTRL + pins: PinConfig, + in_count: u8, + _pio: PhantomData<&'d mut PIO>, +} + +impl<'d, PIO: Instance> Default for Config<'d, PIO> { + fn default() -> Self { + Self { + clock_divider: 1u8.into(), + out_en_sel: Default::default(), + inline_out_en: Default::default(), + out_sticky: Default::default(), + status_sel: Default::default(), + status_n: Default::default(), + exec: Default::default(), + origin: Default::default(), + fifo_join: Default::default(), + shift_in: Default::default(), + shift_out: Default::default(), + pins: Default::default(), + in_count: Default::default(), + _pio: Default::default(), + } + } +} + +impl<'d, PIO: Instance> Config<'d, PIO> { + pub fn get_exec(&self) -> ExecConfig { + self.exec + } + pub unsafe fn set_exec(&mut self, e: ExecConfig) { + self.exec = e; + } + + pub fn get_pins(&self) -> PinConfig { + self.pins + } + pub unsafe fn set_pins(&mut self, p: PinConfig) { + self.pins = p; + } + + /// Configures this state machine to use the given program, including jumping to the origin + /// of the program. The state machine is not started. + /// + /// `side_set` sets the range of pins affected by side-sets. The range must be consecutive. + /// Side-set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be + /// effective. + pub fn use_program(&mut self, prog: &LoadedProgram<'d, PIO>, side_set: &[&Pin<'d, PIO>]) { + assert!((prog.side_set.bits() - prog.side_set.optional() as u8) as usize == side_set.len()); + assert_consecutive(side_set); + self.exec.side_en = prog.side_set.optional(); + self.exec.side_pindir = prog.side_set.pindirs(); + self.exec.wrap_bottom = prog.wrap.target; + self.exec.wrap_top = prog.wrap.source; + self.pins.sideset_count = prog.side_set.bits(); + self.pins.sideset_base = side_set.first().map_or(0, |p| p.pin()); + self.origin = Some(prog.origin); + } + + pub fn set_jmp_pin(&mut self, pin: &Pin<'d, PIO>) { + self.exec.jmp_pin = pin.pin(); + } + + /// Sets the range of pins affected by SET instructions. The range must be consecutive. + /// Set pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be + /// effective. + pub fn set_set_pins(&mut self, pins: &[&Pin<'d, PIO>]) { + assert!(pins.len() <= 5); + assert_consecutive(pins); + self.pins.set_base = pins.first().map_or(0, |p| p.pin()); + self.pins.set_count = pins.len() as u8; + } + + /// Sets the range of pins affected by OUT instructions. The range must be consecutive. + /// Out pins must configured as outputs using [`StateMachine::set_pin_dirs`] to be + /// effective. + pub fn set_out_pins(&mut self, pins: &[&Pin<'d, PIO>]) { + assert_consecutive(pins); + self.pins.out_base = pins.first().map_or(0, |p| p.pin()); + self.pins.out_count = pins.len() as u8; + } + + /// Sets the range of pins used by IN instructions. The range must be consecutive. + /// In pins must configured as inputs using [`StateMachine::set_pin_dirs`] to be + /// effective. + pub fn set_in_pins(&mut self, pins: &[&Pin<'d, PIO>]) { + assert_consecutive(pins); + self.pins.in_base = pins.first().map_or(0, |p| p.pin()); + self.in_count = pins.len() as u8; + } +} + +impl<'d, PIO: Instance, const SM: usize> SetConfig for StateMachine<'d, PIO, SM> { + type Config = Config<'d, PIO>; + + fn set_config(&mut self, config: &Self::Config) { + // sm expects 0 for 65536, truncation makes that happen + assert!(config.clock_divider <= 65536, "clkdiv must be <= 65536"); + assert!(config.clock_divider >= 1, "clkdiv must be >= 1"); + assert!(config.out_en_sel < 32, "out_en_sel must be < 32"); + assert!(config.status_n < 32, "status_n must be < 32"); + // sm expects 0 for 32, truncation makes that happen + assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32"); + assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32"); + let sm = Self::this_sm(); + unsafe { + sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8); + sm.execctrl().write(|w| { + w.set_side_en(config.exec.side_en); + w.set_side_pindir(config.exec.side_pindir); + w.set_jmp_pin(config.exec.jmp_pin); + w.set_out_en_sel(config.out_en_sel); + w.set_inline_out_en(config.inline_out_en); + w.set_out_sticky(config.out_sticky); + w.set_wrap_top(config.exec.wrap_top); + w.set_wrap_bottom(config.exec.wrap_bottom); + w.set_status_sel(match config.status_sel { + StatusSource::TxFifoLevel => SmExecctrlStatusSel::TXLEVEL, + StatusSource::RxFifoLevel => SmExecctrlStatusSel::RXLEVEL, + }); + w.set_status_n(config.status_n); + }); + sm.shiftctrl().write(|w| { + w.set_fjoin_rx(config.fifo_join == FifoJoin::RxOnly); + w.set_fjoin_tx(config.fifo_join == FifoJoin::TxOnly); + w.set_pull_thresh(config.shift_out.threshold); + w.set_push_thresh(config.shift_in.threshold); + w.set_out_shiftdir(config.shift_out.direction == ShiftDirection::Right); + 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); + }); + sm.pinctrl().write(|w| { + w.set_sideset_count(config.pins.sideset_count); + w.set_set_count(config.pins.set_count); + w.set_out_count(config.pins.out_count); + w.set_in_base(config.pins.in_base); + w.set_sideset_base(config.pins.sideset_base); + w.set_set_base(config.pins.set_base); + w.set_out_base(config.pins.out_base); + }); + if let Some(origin) = config.origin { + pio_instr_util::exec_jmp(self, origin); + } + } + } +} + impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { #[inline(always)] fn this_sm() -> crate::pac::pio::StateMachine { @@ -504,16 +720,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 } } - pub fn set_clkdiv(&mut self, div_x_256: u32) { - unsafe { - Self::this_sm().clkdiv().write(|w| w.0 = div_x_256 << 8); - } - } - - pub fn get_clkdiv(&self) -> u32 { - unsafe { Self::this_sm().clkdiv().read().0 >> 8 } - } - pub fn clkdiv_restart(&mut self) { let mask = 1u8 << SM; unsafe { @@ -521,26 +727,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } } - /// Configures this state machine to use the given program, including jumping to the origin - /// of the program. The state machine is not started. - pub fn use_program(&mut self, prog: &LoadedProgram<'d, PIO>, side_set: &[&Pin<'d, PIO>]) { - assert!((prog.side_set.bits() - prog.side_set.optional() as u8) as usize == side_set.len()); - assert_consecutive(side_set); - unsafe { - Self::this_sm().execctrl().modify(|w| { - w.set_side_en(prog.side_set.optional()); - w.set_side_pindir(prog.side_set.pindirs()); - w.set_wrap_bottom(prog.wrap.target); - w.set_wrap_top(prog.wrap.source); - }); - Self::this_sm().pinctrl().modify(|w| { - w.set_sideset_count(prog.side_set.bits()); - w.set_sideset_base(side_set.first().map_or(0, |p| p.pin())); - }); - pio_instr_util::exec_jmp(self, prog.origin); - } - } - fn with_paused(&mut self, f: impl FnOnce(&mut Self)) { let enabled = self.is_enabled(); self.set_enable(false); @@ -591,43 +777,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { }); } - pub fn set_jmp_pin(&mut self, pin: u8) { - unsafe { - Self::this_sm().execctrl().modify(|w| w.set_jmp_pin(pin)); - } - } - - pub fn get_jmp_pin(&mut self) -> u8 { - unsafe { Self::this_sm().execctrl().read().jmp_pin() } - } - - pub fn set_fifo_join(&mut self, join: FifoJoin) { - let (rx, tx) = match join { - FifoJoin::Duplex => (false, false), - FifoJoin::RxOnly => (true, false), - FifoJoin::TxOnly => (false, true), - }; - unsafe { - Self::this_sm().shiftctrl().modify(|w| { - w.set_fjoin_rx(rx); - w.set_fjoin_tx(tx) - }); - } - } - pub fn get_fifo_join(&self) -> FifoJoin { - unsafe { - let r = Self::this_sm().shiftctrl().read(); - // Ignores the invalid state when both bits are set - if r.fjoin_rx() { - FifoJoin::RxOnly - } else if r.fjoin_tx() { - FifoJoin::TxOnly - } else { - FifoJoin::Duplex - } - } - } - pub fn clear_fifos(&mut self) { // Toggle FJOIN_RX to flush FIFOs unsafe { @@ -641,159 +790,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> { } } - pub fn set_pull_threshold(&mut self, threshold: u8) { - unsafe { - Self::this_sm().shiftctrl().modify(|w| w.set_pull_thresh(threshold)); - } - } - - pub fn get_pull_threshold(&self) -> u8 { - unsafe { Self::this_sm().shiftctrl().read().pull_thresh() } - } - pub fn set_push_threshold(&mut self, threshold: u8) { - unsafe { - Self::this_sm().shiftctrl().modify(|w| w.set_push_thresh(threshold)); - } - } - - pub fn get_push_threshold(&self) -> u8 { - unsafe { Self::this_sm().shiftctrl().read().push_thresh() } - } - - pub fn set_out_shift_dir(&mut self, dir: ShiftDirection) { - unsafe { - Self::this_sm() - .shiftctrl() - .modify(|w| w.set_out_shiftdir(dir == ShiftDirection::Right)); - } - } - pub fn get_out_shiftdir(&self) -> ShiftDirection { - unsafe { - if Self::this_sm().shiftctrl().read().out_shiftdir() { - ShiftDirection::Right - } else { - ShiftDirection::Left - } - } - } - - pub fn set_in_shift_dir(&mut self, dir: ShiftDirection) { - unsafe { - Self::this_sm() - .shiftctrl() - .modify(|w| w.set_in_shiftdir(dir == ShiftDirection::Right)); - } - } - pub fn get_in_shiftdir(&self) -> ShiftDirection { - unsafe { - if Self::this_sm().shiftctrl().read().in_shiftdir() { - ShiftDirection::Right - } else { - ShiftDirection::Left - } - } - } - - pub fn set_autopull(&mut self, auto: bool) { - unsafe { - Self::this_sm().shiftctrl().modify(|w| w.set_autopull(auto)); - } - } - - pub fn is_autopull(&self) -> bool { - unsafe { Self::this_sm().shiftctrl().read().autopull() } - } - - pub fn set_autopush(&mut self, auto: bool) { - unsafe { - Self::this_sm().shiftctrl().modify(|w| w.set_autopush(auto)); - } - } - - pub fn is_autopush(&self) -> bool { - unsafe { Self::this_sm().shiftctrl().read().autopush() } - } - - pub fn get_addr(&self) -> u8 { - unsafe { Self::this_sm().addr().read().addr() } - } - - /// Set the range of out pins affected by a set instruction. - pub fn set_set_range(&mut self, base: u8, count: u8) { - assert!(base + count < 32); - unsafe { - Self::this_sm().pinctrl().modify(|w| { - w.set_set_base(base); - w.set_set_count(count) - }); - } - } - - /// Get the range of out pins affected by a set instruction. Returns (base, count). - pub fn get_set_range(&self) -> (u8, u8) { - unsafe { - let r = Self::this_sm().pinctrl().read(); - (r.set_base(), r.set_count()) - } - } - - pub fn set_in_base_pin(&mut self, base: &Pin) { - unsafe { - Self::this_sm().pinctrl().modify(|w| w.set_in_base(base.pin())); - } - } - - pub fn get_in_base(&self) -> u8 { - unsafe { - let r = Self::this_sm().pinctrl().read(); - r.in_base() - } - } - - pub fn set_out_range(&mut self, base: u8, count: u8) { - assert!(base + count < 32); - unsafe { - Self::this_sm().pinctrl().modify(|w| { - w.set_out_base(base); - w.set_out_count(count) - }); - } - } - - /// Get the range of out pins affected by a set instruction. Returns (base, count). - pub fn get_out_range(&self) -> (u8, u8) { - unsafe { - let r = Self::this_sm().pinctrl().read(); - (r.out_base(), r.out_count()) - } - } - - pub fn set_out_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { - let count = pins.len(); - assert!(count >= 1); - let start = pins[0].pin() as usize; - assert!(start + pins.len() <= 32); - for i in 0..count { - assert!(pins[i].pin() as usize == start + i, "Pins must be sequential"); - } - self.set_out_range(start as u8, count as u8); - } - - pub fn set_set_pins<'a, 'b: 'a>(&'a mut self, pins: &'b [&Pin]) { - let count = pins.len(); - assert!(count >= 1); - let start = pins[0].pin() as usize; - assert!(start + pins.len() <= 32); - for i in 0..count { - assert!(pins[i].pin() as usize == start + i, "Pins must be sequential"); - } - self.set_set_range(start as u8, count as u8); - } - - pub fn get_current_instr() -> u32 { - unsafe { Self::this_sm().instr().read().0 } - } - pub fn exec_instr(&mut self, instr: u16) { unsafe { Self::this_sm().instr().write(|w| w.set_instr(instr)); diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 57f6f5c6..d2829df9 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -22,6 +22,8 @@ lorawan = { version = "0.7.3", default-features = false, features = ["default-cr defmt = "0.3" defmt-rtt = "0.4" +fixed = "1.23.1" +fixed-macro = "1.2" #cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m = { version = "0.7.6", features = ["inline-asm"] } diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 9f47c231..12484e88 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -2,10 +2,13 @@ #![no_main] #![feature(type_alias_impl_trait)] use defmt::info; +use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Irq, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::pio::{Common, Config, Irq, Pio, PioPin, ShiftDirection, StateMachine}; use embassy_rp::relocate::RelocatedProgram; +use fixed::traits::ToFixed; +use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { @@ -21,15 +24,14 @@ fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, ); let relocated = RelocatedProgram::new(&prg.program); - sm.use_program(&pio.load_program(&relocated), &[]); + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&relocated), &[]); let out_pin = pio.make_pio_pin(pin); - let pio_pins = [&out_pin]; - sm.set_out_pins(&pio_pins); - sm.set_clkdiv((125e6 / 20.0 / 2e2 * 256.0) as u32); - sm.set_set_range(0, 1); - - sm.set_autopull(true); - sm.set_out_shift_dir(ShiftDirection::Left); + cfg.set_out_pins(&[&out_pin]); + cfg.set_set_pins(&[&out_pin]); + cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed(); + cfg.shift_out.auto_fill = true; + sm.set_config(&cfg); } #[embassy_executor::task] @@ -51,11 +53,12 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, let prg = pio_proc::pio_asm!(".origin 8", "set x, 0x15", ".wrap_target", "in x, 5 [31]", ".wrap",); let relocated = RelocatedProgram::new(&prg.program); - sm.use_program(&pio.load_program(&relocated), &[]); - sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); - sm.set_set_range(0, 0); - sm.set_autopush(true); - sm.set_in_shift_dir(ShiftDirection::Right); + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&relocated), &[]); + cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); + cfg.shift_in.auto_fill = true; + cfg.shift_in.direction = ShiftDirection::Right; + sm.set_config(&cfg); } #[embassy_executor::task] @@ -81,8 +84,10 @@ fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, ".wrap", ); let relocated = RelocatedProgram::new(&prg.program); - sm.use_program(&pio.load_program(&relocated), &[]); - sm.set_clkdiv((125e6 / 2e3 * 256.0) as u32); + let mut cfg = Config::default(); + cfg.use_program(&pio.load_program(&relocated), &[]); + cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed(); + sm.set_config(&cfg); } #[embassy_executor::task] diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 1c4e127c..7f85288b 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -2,11 +2,14 @@ #![no_main] #![feature(type_alias_impl_trait)] use defmt::info; +use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; use embassy_futures::join::join; -use embassy_rp::pio::{Pio, ShiftDirection}; +use embassy_rp::pio::{Config, Pio, ShiftConfig, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::Peripheral; +use fixed::traits::ToFixed; +use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; fn swap_nibbles(v: u32) -> u32 { @@ -38,15 +41,21 @@ async fn main(_spawner: Spawner) { ); let relocated = RelocatedProgram::new(&prg.program); - sm.use_program(&common.load_program(&relocated), &[]); - sm.set_clkdiv((125e6 / 10e3 * 256.0) as u32); - sm.set_autopull(true); - sm.set_autopush(true); - sm.set_pull_threshold(32); - sm.set_push_threshold(32); - sm.set_out_shift_dir(ShiftDirection::Right); - sm.set_in_shift_dir(ShiftDirection::Left); + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&relocated), &[]); + cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed(); + cfg.shift_in = ShiftConfig { + auto_fill: true, + threshold: 32, + direction: ShiftDirection::Left, + }; + cfg.shift_out = ShiftConfig { + auto_fill: true, + threshold: 32, + direction: ShiftDirection::Right, + }; + sm.set_config(&cfg); sm.set_enable(true); let mut dma_out_ref = p.DMA_CH0.into_ref(); diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 40dee1c4..61c5565d 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -4,11 +4,12 @@ use core::fmt::Write; +use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; use embassy_rp::dma::{AnyChannel, Channel}; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Direction, FifoJoin, Pio, PioPin, ShiftDirection, StateMachine}; -use embassy_rp::pwm::{Config, Pwm}; +use embassy_rp::pio::{Config, Direction, FifoJoin, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use embassy_rp::pwm::{self, Pwm}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{into_ref, Peripheral, PeripheralRef}; use embassy_time::{Duration, Instant, Timer}; @@ -29,7 +30,7 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, { - let mut c = Config::default(); + let mut c = pwm::Config::default(); c.divider = 125.into(); c.top = 100; c.compare_b = 50; @@ -83,7 +84,6 @@ impl<'l> HD44780<'l> { ) -> HD44780<'l> { into_ref!(dma); - let db7pin = db7.pin(); let Pio { mut common, mut irq0, @@ -118,13 +118,17 @@ impl<'l> HD44780<'l> { sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); let relocated = RelocatedProgram::new(&prg.program); - sm0.use_program(&common.load_program(&relocated), &[&e]); - sm0.set_clkdiv(125 * 256); - sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); - sm0.set_out_shift_dir(ShiftDirection::Left); - sm0.set_fifo_join(FifoJoin::TxOnly); - sm0.set_autopull(true); - sm0.set_pull_threshold(32); + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&relocated), &[&e]); + cfg.clock_divider = 125u8.into(); + cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); + cfg.shift_out = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Left, + threshold: 32, + }; + cfg.fifo_join = FifoJoin::TxOnly; + sm0.set_config(&cfg); sm0.set_enable(true); // init to 8 bit thrice @@ -188,13 +192,15 @@ impl<'l> HD44780<'l> { ); let relocated = RelocatedProgram::new(&prg.program); - sm0.use_program(&common.load_program(&relocated), &[&e]); - sm0.set_clkdiv(8 * 256); // ~64ns/insn - sm0.set_jmp_pin(db7pin); - sm0.set_set_pins(&[&rs, &rw]); - sm0.set_out_pins(&[&db4, &db5, &db6, &db7]); - sm0.set_out_shift_dir(ShiftDirection::Left); - sm0.set_fifo_join(FifoJoin::TxOnly); + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&relocated), &[&e]); + cfg.clock_divider = 8u8.into(); // ~64ns/insn + cfg.set_jmp_pin(&db7); + cfg.set_set_pins(&[&rs, &rw]); + cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); + cfg.shift_out.direction = ShiftDirection::Left; + cfg.fifo_join = FifoJoin::TxOnly; + sm0.set_config(&cfg); sm0.set_enable(true); diff --git a/examples/rp/src/bin/ws2812-pio.rs b/examples/rp/src/bin/ws2812-pio.rs index 88997054..d7c4742d 100644 --- a/examples/rp/src/bin/ws2812-pio.rs +++ b/examples/rp/src/bin/ws2812-pio.rs @@ -3,10 +3,12 @@ #![feature(type_alias_impl_trait)] use defmt::*; +use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; -use embassy_rp::pio::{Common, FifoJoin, Instance, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::pio::{Common, Config, FifoJoin, Instance, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; use embassy_rp::relocate::RelocatedProgram; use embassy_time::{Duration, Timer}; +use fixed_macro::fixed; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; pub struct Ws2812<'d, P: Instance, const S: usize> { @@ -43,35 +45,30 @@ impl<'d, P: Instance, const S: usize> Ws2812<'d, P, S> { a.bind(&mut wrap_source); let prg = a.assemble_with_wrap(wrap_source, wrap_target); + let mut cfg = Config::default(); // Pin config let out_pin = pio.make_pio_pin(pin); let relocated = RelocatedProgram::new(&prg); - sm.use_program(&pio.load_program(&relocated), &[&out_pin]); + cfg.use_program(&pio.load_program(&relocated), &[&out_pin]); - // Clock config + // Clock config, measured in kHz to avoid overflows // TODO CLOCK_FREQ should come from embassy_rp - const CLOCK_FREQ: u32 = 125_000_000; - const WS2812_FREQ: u32 = 800_000; - - let bit_freq = WS2812_FREQ * CYCLES_PER_BIT; - let mut int = CLOCK_FREQ / bit_freq; - let rem = CLOCK_FREQ - (int * bit_freq); - let frac = (rem * 256) / bit_freq; - // 65536.0 is represented as 0 in the pio's clock divider - if int == 65536 { - int = 0; - } - - sm.set_clkdiv((int << 8) | frac); + let clock_freq = fixed!(125_000: U24F8); + let ws2812_freq = fixed!(800: U24F8); + let bit_freq = ws2812_freq * CYCLES_PER_BIT; + cfg.clock_divider = clock_freq / bit_freq; // FIFO config - sm.set_autopull(true); - sm.set_fifo_join(FifoJoin::TxOnly); - sm.set_pull_threshold(24); - sm.set_out_shift_dir(ShiftDirection::Left); + cfg.fifo_join = FifoJoin::TxOnly; + cfg.shift_out = ShiftConfig { + auto_fill: true, + threshold: 24, + direction: ShiftDirection::Left, + }; + sm.set_config(&cfg); sm.set_enable(true); Self { sm }