From 57c1fbf3089e2a2dc9fe5b7d1f1e094596566395 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 10:04:35 -0400 Subject: Move pio programs into embassy-rp --- examples/rp/src/bin/pio_hd44780.rs | 201 ++++----------------------- examples/rp/src/bin/pio_i2s.rs | 71 +++------- examples/rp/src/bin/pio_onewire.rs | 98 ++----------- examples/rp/src/bin/pio_pwm.rs | 90 +----------- examples/rp/src/bin/pio_rotary_encoder.rs | 85 +++++------- examples/rp/src/bin/pio_servo.rs | 96 ++----------- examples/rp/src/bin/pio_stepper.rs | 135 ++---------------- examples/rp/src/bin/pio_uart.rs | 222 +++--------------------------- examples/rp/src/bin/pio_ws2812.rs | 105 +------------- 9 files changed, 131 insertions(+), 972 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 6c02630e0..164e6f8d3 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -7,13 +7,11 @@ use core::fmt::Write; use embassy_executor::Spawner; -use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::hd44780::{PioHD44780, PioHD44780CommandSequenceProgram, PioHD44780CommandWordProgram}; use embassy_rp::pwm::{self, Pwm}; -use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -43,8 +41,27 @@ async fn main(_spawner: Spawner) { c }); - let mut hd = HD44780::new( - p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, + let Pio { + mut common, sm0, irq0, .. + } = Pio::new(p.PIO0, Irqs); + + let word_prg = PioHD44780CommandWordProgram::new(&mut common); + let seq_prg = PioHD44780CommandSequenceProgram::new(&mut common); + + let mut hd = PioHD44780::new( + &mut common, + sm0, + irq0, + p.DMA_CH3, + p.PIN_0, + p.PIN_1, + p.PIN_2, + p.PIN_3, + p.PIN_4, + p.PIN_5, + p.PIN_6, + &word_prg, + &seq_prg, ) .await; @@ -68,173 +85,3 @@ async fn main(_spawner: Spawner) { Timer::after_secs(1).await; } } - -pub struct HD44780<'l> { - dma: PeripheralRef<'l, AnyChannel>, - sm: StateMachine<'l, PIO0, 0>, - - buf: [u8; 40], -} - -impl<'l> HD44780<'l> { - pub async fn new( - pio: impl Peripheral

+ 'l, - irq: Irqs, - dma: impl Peripheral

+ 'l, - rs: impl PioPin, - rw: impl PioPin, - e: impl PioPin, - db4: impl PioPin, - db5: impl PioPin, - db6: impl PioPin, - db7: impl PioPin, - ) -> HD44780<'l> { - into_ref!(dma); - - let Pio { - mut common, - mut irq0, - mut sm0, - .. - } = Pio::new(pio, irq); - - // takes command words ( <0:4>) - let prg = pio_proc::pio_asm!( - r#" - .side_set 1 opt - .origin 20 - - 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_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); - - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&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 - sm0.tx().push((50000 << 8) | 0x30); - sm0.tx().push((5000 << 8) | 0x30); - sm0.tx().push((200 << 8) | 0x30); - // init 4 bit - sm0.tx().push((200 << 8) | 0x20); - // set font and lines - sm0.tx().push((50 << 8) | 0x20); - sm0.tx().push(0b1100_0000); - - irq0.wait().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 27 - .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 mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&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); - - // display on and cursor on and blinking, reset display - sm0.tx().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.tx().dma_push(self.dma.reborrow(), &self.buf).await; - } -} diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index cf60e5b30..447100ddf 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -13,10 +13,10 @@ use core::mem; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; -use embassy_rp::{bind_interrupts, Peripheral}; -use fixed::traits::ToFixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -25,61 +25,32 @@ bind_interrupts!(struct Irqs { }); const SAMPLE_RATE: u32 = 48_000; +const BIT_DEPTH: u32 = 16; +const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut p = embassy_rp::init(Default::default()); // Setup pio state machine for i2s output - let mut pio = Pio::new(p.PIO0, Irqs); - - #[rustfmt::skip] - let pio_program = pio_proc::pio_asm!( - ".side_set 2", - " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock - "left_data:", - " out pins, 1 side 0b00", - " jmp x-- left_data side 0b01", - " out pins 1 side 0b10", - " set x, 14 side 0b11", - "right_data:", - " out pins 1 side 0b10", - " jmp x-- right_data side 0b11", - " out pins 1 side 0b00", - ); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); let bit_clock_pin = p.PIN_18; let left_right_clock_pin = p.PIN_19; let data_pin = p.PIN_20; - let data_pin = pio.common.make_pio_pin(data_pin); - let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); - let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); - - let cfg = { - let mut cfg = Config::default(); - cfg.use_program( - &pio.common.load_program(&pio_program.program), - &[&bit_clock_pin, &left_right_clock_pin], - ); - cfg.set_out_pins(&[&data_pin]); - const BIT_DEPTH: u32 = 16; - const CHANNELS: u32 = 2; - let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS; - cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); - cfg.shift_out = ShiftConfig { - threshold: 32, - direction: ShiftDirection::Left, - auto_fill: true, - }; - // join fifos to have twice the time to start the next dma transfer - cfg.fifo_join = FifoJoin::TxOnly; - cfg - }; - pio.sm0.set_config(&cfg); - pio.sm0.set_pin_dirs( - embassy_rp::pio::Direction::Out, - &[&data_pin, &left_right_clock_pin, &bit_clock_pin], + let program = PioI2sOutProgram::new(&mut common); + let mut i2s = PioI2sOut::new( + &mut common, + sm0, + p.DMA_CH0, + data_pin, + bit_clock_pin, + left_right_clock_pin, + SAMPLE_RATE, + BIT_DEPTH, + CHANNELS, + &program, ); // create two audio buffers (back and front) which will take turns being @@ -90,17 +61,13 @@ async fn main(_spawner: Spawner) { let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); // start pio state machine - pio.sm0.set_enable(true); - let tx = pio.sm0.tx(); - let mut dma_ref = p.DMA_CH0.into_ref(); - let mut fade_value: i32 = 0; let mut phase: i32 = 0; loop { // trigger transfer of front buffer data to the pio fifo // but don't await the returned future, yet - let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); + let dma_future = i2s.write(front_buffer); // fade in audio when bootsel is pressed let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 5076101ec..991510851 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs @@ -6,7 +6,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use embassy_rp::pio::{self, InterruptHandler, Pio}; +use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -18,7 +19,11 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let mut pio = Pio::new(p.PIO0, Irqs); - let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); + + let prg = PioOneWireProgram::new(&mut pio.common); + let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); + + let mut sensor = Ds18b20::new(onewire); loop { sensor.start().await; // Start a new measurement @@ -33,89 +38,12 @@ async fn main(_spawner: Spawner) { /// DS18B20 temperature sensor driver pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { - sm: StateMachine<'d, PIO, SM>, + wire: PioOneWire<'d, PIO, SM>, } impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { - /// Create a new instance the driver - pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - r#" - .wrap_target - again: - pull block - mov x, osr - jmp !x, read - write: - set pindirs, 1 - set pins, 0 - loop1: - jmp x--,loop1 - set pindirs, 0 [31] - wait 1 pin 0 [31] - pull block - mov x, osr - bytes1: - pull block - set y, 7 - set pindirs, 1 - bit1: - set pins, 0 [1] - out pins,1 [31] - set pins, 1 [20] - jmp y--,bit1 - jmp x--,bytes1 - set pindirs, 0 [31] - jmp again - read: - pull block - mov x, osr - bytes2: - set y, 7 - bit2: - set pindirs, 1 - set pins, 0 [1] - set pindirs, 0 [5] - in pins,1 [10] - jmp y--,bit2 - jmp x--,bytes2 - .wrap - "#, - ); - - let pin = common.make_pio_pin(pin); - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[]); - cfg.set_out_pins(&[&pin]); - cfg.set_in_pins(&[&pin]); - cfg.set_set_pins(&[&pin]); - cfg.shift_in = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Right, - threshold: 8, - }; - cfg.clock_divider = 255_u8.into(); - sm.set_config(&cfg); - sm.set_enable(true); - Self { sm } - } - - /// Write bytes over the wire - async fn write_bytes(&mut self, bytes: &[u8]) { - self.sm.tx().wait_push(250).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes { - self.sm.tx().wait_push(*b as u32).await; - } - } - - /// Read bytes from the wire - async fn read_bytes(&mut self, bytes: &mut [u8]) { - self.sm.tx().wait_push(0).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes.iter_mut() { - *b = (self.sm.rx().wait_pull().await >> 24) as u8; - } + pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { + Self { wire } } /// Calculate CRC8 of the data @@ -139,14 +67,14 @@ impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { /// Start a new measurement. Allow at least 1000ms before getting `temperature`. pub async fn start(&mut self) { - self.write_bytes(&[0xCC, 0x44]).await; + self.wire.write_bytes(&[0xCC, 0x44]).await; } /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. pub async fn temperature(&mut self) -> Result { - self.write_bytes(&[0xCC, 0xBE]).await; + self.wire.write_bytes(&[0xCC, 0xBE]).await; let mut data = [0; 9]; - self.read_bytes(&mut data).await; + self.wire.read_bytes(&mut data).await; match Self::crc8(&data) == 0 { true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), false => Err(()), diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs index 23d63d435..7eabb2289 100644 --- a/examples/rp/src/bin/pio_pwm.rs +++ b/examples/rp/src/bin/pio_pwm.rs @@ -5,12 +5,11 @@ use core::time::Duration; use embassy_executor::Spawner; -use embassy_rp::gpio::Level; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; const REFRESH_INTERVAL: u64 = 20000; @@ -19,93 +18,14 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - #[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); // Note that PIN_25 is the led pin on the Pico - let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); + let prg = PioPwmProgram::new(&mut common); + let mut pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_25, &prg); pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); pwm_pio.start(); diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs index 58bdadbc0..a7ecc8d0e 100644 --- a/examples/rp/src/bin/pio_rotary_encoder.rs +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -5,70 +5,32 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; -use embassy_rp::{bind_interrupts, pio}; -use fixed::traits::ToFixed; -use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{ + bind_interrupts, + pio::{InterruptHandler, Pio}, + pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, +}; use {defmt_rtt as _, panic_probe as _}; 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!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); - - let mut cfg = Config::default(); - cfg.set_in_pins(&[&pin_a, &pin_b]); - cfg.fifo_join = FifoJoin::RxOnly; - 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) -> Direction { - loop { - match self.sm.rx().wait_pull().await { - 0 => return Direction::CounterClockwise, - 1 => return Direction::Clockwise, - _ => {} - } - } +#[embassy_executor::task] +async fn encoder_0(mut encoder: PioEncoder<'static, PIO0, 0>) { + let mut count = 0; + loop { + info!("Count: {}", count); + count += match encoder.read().await { + Direction::Clockwise => 1, + Direction::CounterClockwise => -1, + }; } } -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); - +#[embassy_executor::task] +async fn encoder_1(mut encoder: PioEncoder<'static, PIO0, 1>) { let mut count = 0; loop { info!("Count: {}", count); @@ -78,3 +40,18 @@ async fn main(_spawner: Spawner) { }; } } + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { + mut common, sm0, sm1, .. + } = Pio::new(p.PIO0, Irqs); + + let prg = PioEncoderProgram::new(&mut common); + let encoder0 = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5, &prg); + let encoder1 = PioEncoder::new(&mut common, sm1, p.PIN_6, p.PIN_7, &prg); + + spawner.must_spawn(encoder_0(encoder0)); + spawner.must_spawn(encoder_1(encoder1)); +} diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs index a79540479..c52ee7492 100644 --- a/examples/rp/src/bin/pio_servo.rs +++ b/examples/rp/src/bin/pio_servo.rs @@ -5,12 +5,11 @@ use core::time::Duration; use embassy_executor::Spawner; -use embassy_rp::gpio::Level; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{Instance, InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo @@ -22,88 +21,8 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - pub struct ServoBuilder<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, period: Duration, min_pulse_width: Duration, max_pulse_width: Duration, @@ -111,7 +30,7 @@ pub struct ServoBuilder<'d, T: Instance, const SM: usize> { } impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { - pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { + pub fn new(pwm: PioPwm<'d, T, SM>) -> Self { Self { pwm, period: Duration::from_micros(REFRESH_INTERVAL), @@ -153,7 +72,7 @@ impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { } pub struct Servo<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, min_pulse_width: Duration, max_pulse_width: Duration, max_degree_rotation: u64, @@ -190,7 +109,8 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); + let prg = PioPwmProgram::new(&mut common); + let pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_1, &prg); let mut servo = ServoBuilder::new(pwm_pio) .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 6ee45a414..3862c248b 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -3,143 +3,20 @@ #![no_std] #![no_main] -use core::mem::{self, MaybeUninit}; use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; use embassy_time::{with_timeout, Duration, Timer}; -use fixed::traits::ToFixed; -use fixed::types::extra::U8; -use fixed::FixedU32; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct PioStepper<'d, T: Instance, const SM: usize> { - irq: Irq<'d, T, SM>, - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { - pub fn new( - pio: &mut Common<'d, T>, - mut sm: StateMachine<'d, T, SM>, - irq: Irq<'d, T, SM>, - pin0: impl PioPin, - pin1: impl PioPin, - pin2: impl PioPin, - pin3: impl PioPin, - ) -> Self { - let prg = pio_proc::pio_asm!( - "pull block", - "mov x, osr", - "pull block", - "mov y, osr", - "jmp !x end", - "loop:", - "jmp !osre step", - "mov osr, y", - "step:", - "out pins, 4 [31]" - "jmp x-- loop", - "end:", - "irq 0 rel" - ); - let pin0 = pio.make_pio_pin(pin0); - let pin1 = pio.make_pio_pin(pin1); - let pin2 = pio.make_pio_pin(pin2); - let pin3 = pio.make_pio_pin(pin3); - sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); - let mut cfg = Config::default(); - cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); - cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); - cfg.use_program(&pio.load_program(&prg.program), &[]); - sm.set_config(&cfg); - sm.set_enable(true); - Self { irq, sm } - } - - // Set pulse frequency - pub fn set_frequency(&mut self, freq: u32) { - let clock_divider: FixedU32 = (125_000_000 / (freq * 136)).to_fixed(); - assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); - assert!(clock_divider >= 1, "clkdiv must be >= 1"); - self.sm.set_clock_divider(clock_divider); - self.sm.clkdiv_restart(); - } - - // Full step, one phase - pub async fn step(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await - } else { - self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await - } - } - - // Full step, two phase - pub async fn step2(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await - } else { - self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await - } - } - - // Half step - pub async fn step_half(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await - } else { - self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await - } - } - - async fn run(&mut self, steps: i32, pattern: u32) { - self.sm.tx().wait_push(steps as u32).await; - self.sm.tx().wait_push(pattern).await; - let drop = OnDrop::new(|| { - self.sm.clear_fifos(); - unsafe { - self.sm.exec_instr( - pio::InstructionOperands::JMP { - address: 0, - condition: pio::JmpCondition::Always, - } - .encode(), - ); - } - }); - self.irq.wait().await; - drop.defuse(); - } -} - -struct OnDrop { - f: MaybeUninit, -} - -impl OnDrop { - pub fn new(f: F) -> Self { - Self { f: MaybeUninit::new(f) } - } - - pub fn defuse(self) { - mem::forget(self) - } -} - -impl Drop for OnDrop { - fn drop(&mut self) { - unsafe { self.f.as_ptr().read()() } - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -147,14 +24,18 @@ async fn main(_spawner: Spawner) { mut common, irq0, sm0, .. } = Pio::new(p.PIO0, Irqs); - let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); + let prg = PioStepperProgram::new(&mut common); + let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7, &prg); stepper.set_frequency(120); loop { info!("CW full steps"); stepper.step(1000).await; info!("CCW full steps, drop after 1 sec"); - if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)).await { + if with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)) + .await + .is_err() + { info!("Time's up!"); Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index 53b696309..b9e01b0ac 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -15,7 +15,8 @@ use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::{PIO0, USB}; -use embassy_rp::pio::InterruptHandler as PioInterruptHandler; +use embassy_rp::pio; +use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe::Pipe; @@ -25,13 +26,11 @@ use embassy_usb::{Builder, Config}; use embedded_io_async::{Read, Write}; use {defmt_rtt as _, panic_probe as _}; -use crate::uart::PioUart; -use crate::uart_rx::PioUartRx; -use crate::uart_tx::PioUartTx; +//use crate::uart::PioUart; bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; - PIO0_IRQ_0 => PioInterruptHandler; + PIO0_IRQ_0 => pio::InterruptHandler; }); #[embassy_executor::main] @@ -85,8 +84,15 @@ async fn main(_spawner: Spawner) { let usb_fut = usb.run(); // PIO UART setup - let uart = PioUart::new(9600, p.PIO0, p.PIN_4, p.PIN_5); - let (mut uart_tx, mut uart_rx) = uart.split(); + let pio::Pio { + mut common, sm0, sm1, .. + } = pio::Pio::new(p.PIO0, Irqs); + + let tx_program = PioUartTxProgram::new(&mut common); + let mut uart_tx = PioUartTx::new(9600, &mut common, sm0, p.PIN_4, &tx_program); + + let rx_program = PioUartRxProgram::new(&mut common); + let mut uart_rx = PioUartRx::new(9600, &mut common, sm1, p.PIN_5, &rx_program); // Pipe setup let mut usb_pipe: Pipe = Pipe::new(); @@ -163,8 +169,8 @@ async fn usb_write<'d, T: Instance + 'd>( } /// Read from the UART and write it to the USB TX pipe -async fn uart_read( - uart_rx: &mut PioUartRx<'_>, +async fn uart_read( + uart_rx: &mut PioUartRx<'_, PIO, SM>, usb_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>, ) -> ! { let mut buf = [0; 64]; @@ -180,8 +186,8 @@ async fn uart_read( } /// Read from the UART TX pipe and write it to the UART -async fn uart_write( - uart_tx: &mut PioUartTx<'_>, +async fn uart_write( + uart_tx: &mut PioUartTx<'_, PIO, SM>, uart_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>, ) -> ! { let mut buf = [0; 64]; @@ -192,197 +198,3 @@ async fn uart_write( let _ = uart_tx.write(&data).await; } } - -mod uart { - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Pio, PioPin}; - use embassy_rp::Peripheral; - - use crate::uart_rx::PioUartRx; - use crate::uart_tx::PioUartTx; - use crate::Irqs; - - pub struct PioUart<'a> { - tx: PioUartTx<'a>, - rx: PioUartRx<'a>, - } - - impl<'a> PioUart<'a> { - pub fn new( - baud: u64, - pio: impl Peripheral

+ 'a, - tx_pin: impl PioPin, - rx_pin: impl PioPin, - ) -> PioUart<'a> { - let Pio { - mut common, sm0, sm1, .. - } = Pio::new(pio, Irqs); - - let tx = PioUartTx::new(&mut common, sm0, tx_pin, baud); - let rx = PioUartRx::new(&mut common, sm1, rx_pin, baud); - - PioUart { tx, rx } - } - - pub fn split(self) -> (PioUartTx<'a>, PioUartRx<'a>) { - (self.tx, self.rx) - } - } -} - -mod uart_tx { - use core::convert::Infallible; - - use embassy_rp::gpio::Level; - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; - use embedded_io_async::{ErrorType, Write}; - use fixed::traits::ToFixed; - use fixed_macro::types::U56F8; - - pub struct PioUartTx<'a> { - sm_tx: StateMachine<'a, PIO0, 0>, - } - - impl<'a> PioUartTx<'a> { - pub fn new( - common: &mut Common<'a, PIO0>, - mut sm_tx: StateMachine<'a, PIO0, 0>, - tx_pin: impl PioPin, - baud: u64, - ) -> Self { - let prg = pio_proc::pio_asm!( - r#" - .side_set 1 opt - - ; An 8n1 UART transmit program. - ; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin. - - pull side 1 [7] ; Assert stop bit, or stall with line in idle state - set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks - bitloop: ; This loop will run 8 times (8n1 UART) - out pins, 1 ; Shift 1 bit from OSR to the first OUT pin - jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. - "# - ); - let tx_pin = common.make_pio_pin(tx_pin); - sm_tx.set_pins(Level::High, &[&tx_pin]); - sm_tx.set_pin_dirs(Direction::Out, &[&tx_pin]); - - let mut cfg = Config::default(); - - cfg.set_out_pins(&[&tx_pin]); - cfg.use_program(&common.load_program(&prg.program), &[&tx_pin]); - cfg.shift_out.auto_fill = false; - cfg.shift_out.direction = ShiftDirection::Right; - cfg.fifo_join = FifoJoin::TxOnly; - cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed(); - sm_tx.set_config(&cfg); - sm_tx.set_enable(true); - - Self { sm_tx } - } - - pub async fn write_u8(&mut self, data: u8) { - self.sm_tx.tx().wait_push(data as u32).await; - } - } - - impl ErrorType for PioUartTx<'_> { - type Error = Infallible; - } - - impl Write for PioUartTx<'_> { - async fn write(&mut self, buf: &[u8]) -> Result { - for byte in buf { - self.write_u8(*byte).await; - } - Ok(buf.len()) - } - } -} - -mod uart_rx { - use core::convert::Infallible; - - use embassy_rp::gpio::Level; - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; - use embedded_io_async::{ErrorType, Read}; - use fixed::traits::ToFixed; - use fixed_macro::types::U56F8; - - pub struct PioUartRx<'a> { - sm_rx: StateMachine<'a, PIO0, 1>, - } - - impl<'a> PioUartRx<'a> { - pub fn new( - common: &mut Common<'a, PIO0>, - mut sm_rx: StateMachine<'a, PIO0, 1>, - rx_pin: impl PioPin, - baud: u64, - ) -> Self { - let prg = pio_proc::pio_asm!( - r#" - ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and - ; break conditions more gracefully. - ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. - - start: - wait 0 pin 0 ; Stall until start bit is asserted - set x, 7 [10] ; Preload bit counter, then delay until halfway through - rx_bitloop: ; the first data bit (12 cycles incl wait, set). - in pins, 1 ; Shift data bit into ISR - jmp x-- rx_bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles - jmp pin good_rx_stop ; Check stop bit (should be high) - - irq 4 rel ; Either a framing error or a break. Set a sticky flag, - wait 1 pin 0 ; and wait for line to return to idle state. - jmp start ; Don't push data if we didn't see good framing. - - good_rx_stop: ; No delay before returning to start; a little slack is - in null 24 - push ; important in case the TX clock is slightly too fast. - "# - ); - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[]); - - let rx_pin = common.make_pio_pin(rx_pin); - sm_rx.set_pins(Level::High, &[&rx_pin]); - cfg.set_in_pins(&[&rx_pin]); - cfg.set_jmp_pin(&rx_pin); - sm_rx.set_pin_dirs(Direction::In, &[&rx_pin]); - - cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed(); - cfg.shift_in.auto_fill = false; - cfg.shift_in.direction = ShiftDirection::Right; - cfg.shift_in.threshold = 32; - cfg.fifo_join = FifoJoin::RxOnly; - sm_rx.set_config(&cfg); - sm_rx.set_enable(true); - - Self { sm_rx } - } - - pub async fn read_u8(&mut self) -> u8 { - self.sm_rx.rx().wait_pull().await as u8 - } - } - - impl ErrorType for PioUartRx<'_> { - type Error = Infallible; - } - - impl Read for PioUartRx<'_> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - while i < buf.len() { - buf[i] = self.read_u8().await; - i += 1; - } - Ok(i) - } - } -} diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index ac145933c..d1fcfc471 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs @@ -6,15 +6,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; -use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; -use embassy_time::{Duration, Ticker, Timer}; -use fixed::types::U24F8; -use fixed_macro::fixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program}; +use embassy_time::{Duration, Ticker}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; @@ -22,96 +18,6 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { - dma: PeripheralRef<'d, AnyChannel>, - sm: StateMachine<'d, P, S>, -} - -impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { - pub fn new( - pio: &mut Common<'d, P>, - mut sm: StateMachine<'d, P, S>, - dma: impl Peripheral

+ 'd, - pin: impl PioPin, - ) -> Self { - into_ref!(dma); - - // Setup sm0 - - // prepare the PIO program - let side_set = pio::SideSet::new(false, 1, false); - let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); - - const T1: u8 = 2; // start bit - const T2: u8 = 5; // data bit - const T3: u8 = 3; // stop bit - const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; - - let mut wrap_target = a.label(); - let mut wrap_source = a.label(); - let mut do_zero = a.label(); - a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); - a.bind(&mut wrap_target); - // Do stop bit - a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); - // Do start bit - a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); - // Do data bit = 1 - a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); - a.bind(&mut do_zero); - // Do data bit = 0 - a.nop_with_delay_and_side_set(T2 - 1, 0); - 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); - cfg.set_out_pins(&[&out_pin]); - cfg.set_set_pins(&[&out_pin]); - - cfg.use_program(&pio.load_program(&prg), &[&out_pin]); - - // Clock config, measured in kHz to avoid overflows - // TODO CLOCK_FREQ should come from embassy_rp - let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); - let ws2812_freq = fixed!(800: U24F8); - let bit_freq = ws2812_freq * CYCLES_PER_BIT; - cfg.clock_divider = clock_freq / bit_freq; - - // FIFO config - 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 { - dma: dma.map_into(), - sm, - } - } - - pub async fn write(&mut self, colors: &[RGB8; N]) { - // Precompute the word bytes from the colors - let mut words = [0u32; N]; - for i in 0..N { - let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); - words[i] = word; - } - - // DMA transfer - self.sm.tx().dma_push(self.dma.reborrow(), &words).await; - - Timer::after_micros(55).await; - } -} - /// Input a value 0 to 255 to get a color value /// The colours are a transition r - g - b - back to r. fn wheel(mut wheel_pos: u8) -> RGB8 { @@ -142,7 +48,8 @@ async fn main(_spawner: Spawner) { // Common neopixel pins: // Thing plus: 8 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 - let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); + let program = PioWs2812Program::new(&mut common); + let mut ws2812 = PioWs2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16, &program); // Loop forever making RGB values and pushing them out to the WS2812. let mut ticker = Ticker::every(Duration::from_millis(10)); -- cgit From e47c031b671555f3fffe6b128cbb9d3f8bfec534 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 11:47:04 -0400 Subject: fmt examples too --- examples/rp/src/bin/pio_rotary_encoder.rs | 8 +++----- examples/rp/src/bin/pio_uart.rs | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs index a7ecc8d0e..2750f61ae 100644 --- a/examples/rp/src/bin/pio_rotary_encoder.rs +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -5,12 +5,10 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::{ - bind_interrupts, - pio::{InterruptHandler, Pio}, - pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index b9e01b0ac..aaf2a524f 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -13,11 +13,10 @@ use defmt::{info, panic, trace}; use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; -use embassy_rp::bind_interrupts; use embassy_rp::peripherals::{PIO0, USB}; -use embassy_rp::pio; use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_rp::{bind_interrupts, pio}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe::Pipe; use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; -- cgit