From d1a90e48c93030385b50688691cd3a330f81c0b1 Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sat, 22 Feb 2025 22:40:21 -0800 Subject: [PATCH 01/10] Two separate features for rp2040-hal and rp235x-hal --- Cargo.toml | 8 +- src/lib.rs | 319 ++----------------------------------------------- src/rp2040.rs | 321 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/rp235x.rs | 320 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 658 insertions(+), 310 deletions(-) create mode 100644 src/rp2040.rs create mode 100644 src/rp235x.rs diff --git a/Cargo.toml b/Cargo.toml index 6e8abe5..21ad151 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,15 @@ repository = "https://github.com/rp-rs/ws2812-pio-rs/" [dependencies] embedded-hal = "0.2.5" fugit = "0.3.5" -rp2040-hal = "0.11" pio = "0.2.0" smart-leds-trait = "0.3" smart-leds-trait-0-2 = { package = "smart-leds-trait", version = "0.2.1" } nb = "1.0.0" cortex-m = "0.7.3" +rp2040-hal = { version = "0.11.0", optional = true } +rp235x-hal = { version = "0.2.0", optional = true } + +[features] +default = [] +rp2040 = ["dep:rp2040-hal"] +rp235x = ["dep:rp235x-hal"] diff --git a/src/lib.rs b/src/lib.rs index 75ad292..abdc9f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,314 +1,15 @@ #![no_std] -//! WS2812 PIO Driver for the RP2040 -//! -//! This driver implements driving a WS2812 RGB LED strip from -//! a PIO device of the RP2040 chip. -//! -//! You should reach to [Ws2812] if you run the main loop -//! of your controller yourself and you want [Ws2812] to take -//! a hold of your timer. -//! -//! In case you use `cortex-m-rtic` and can't afford this crate -//! to wait blocking for you, you should try [Ws2812Direct]. -//! Bear in mind that you will have to take care of timing requirements -//! yourself then. +#[cfg(feature = "rp2040")] +mod rp2040; -use embedded_hal::timer::CountDown; -use fugit::{ExtU32, HertzU32, MicrosDurationU32}; -use rp2040_hal::{ - gpio::AnyPin, - pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, -}; -use smart_leds_trait::SmartLedsWrite; -use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; +#[cfg(feature = "rp235x")] +mod rp235x; -/// This is the WS2812 PIO Driver. -/// -/// For blocking applications is recommended to use -/// the [Ws2812] struct instead of this raw driver. -/// -/// If you use this driver directly, you will need to -/// take care of the timing expectations of the [Ws2812Direct::write] -/// method. -/// -/// Typical usage example: -///```ignore -/// use rp2040_hal::clocks::init_clocks_and_plls; -/// let clocks = init_clocks_and_plls(...); -/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); -/// -/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); -/// let mut ws = Ws2812Direct::new( -/// pins.gpio4.into_mode(), -/// &mut pio, -/// sm0, -/// clocks.peripheral_clock.freq(), -/// ); -/// -/// // Then you will make sure yourself to not write too frequently: -/// loop { -/// use smart_leds::{SmartLedsWrite, RGB8}; -/// let color : RGB8 = (255, 0, 255).into(); -/// -/// ws.write([color].iter().copied()).unwrap(); -/// delay_for_at_least_60_microseconds(); -/// }; -///``` -pub struct Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - tx: Tx<(P, SM)>, - _pin: I, -} +#[cfg(feature = "rp2040")] +pub use rp2040::*; -impl Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - /// Creates a new instance of this driver. - pub fn new( - pin: I, - pio: &mut PIO

, - sm: UninitStateMachine<(P, SM)>, - clock_freq: fugit::HertzU32, - ) -> Self { - // prepare the PIO program - let side_set = pio::SideSet::new(false, 1, false); - let mut a = pio::Assembler::new_with_side_set(side_set); +#[cfg(feature = "rp235x")] +pub use rp235x::*; - 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; - const FREQ: HertzU32 = HertzU32::kHz(800); - - let mut wrap_target = a.label(); - let mut wrap_source = a.label(); - let mut do_zero = a.label(); - 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 program = a.assemble_with_wrap(wrap_source, wrap_target); - - // Install the program into PIO instruction memory. - let installed = pio.install(&program).unwrap(); - - // Configure the PIO state machine. - let bit_freq = FREQ * CYCLES_PER_BIT; - let mut int = clock_freq / bit_freq; - let rem = clock_freq - (int * bit_freq); - let frac = (rem * 256) / bit_freq; - assert!( - (1..=65536).contains(&int) && (int != 65536 || frac == 0), - "(System Clock / {}) must be within [1.0, 65536.0].", - bit_freq.to_kHz() - ); - - // 65536.0 is represented as 0 in the pio's clock divider - if int == 65536 { - int = 0; - } - // Using lossy conversion because range have been checked - let int: u16 = int as u16; - let frac: u8 = frac as u8; - - let pin = pin.into(); - let (mut sm, _, tx) = rp2040_hal::pio::PIOBuilder::from_installed_program(installed) - // only use TX FIFO - .buffers(rp2040_hal::pio::Buffers::OnlyTx) - // Pin configuration - .side_set_pin_base(pin.id().num) - // OSR config - .out_shift_direction(rp2040_hal::pio::ShiftDirection::Left) - .autopull(true) - .pull_threshold(24) - .clock_divisor_fixed_point(int, frac) - .build(sm); - - // Prepare pin's direction. - sm.set_pindirs([(pin.id().num, rp2040_hal::pio::PinDir::Output)]); - - sm.start(); - - Self { - tx, - _pin: I::from(pin), - } - } -} - -impl SmartLedsWrite for Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - /// If you call this function, be advised that you will have to wait - /// at least 60 microseconds between calls of this function! - /// That means, either you get hold on a timer and the timing - /// requirements right your self, or rather use [Ws2812]. - /// - /// Please bear in mind, that it still blocks when writing into the - /// PIO FIFO until all data has been transmitted to the LED chain. - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - for item in iterator { - let color: Self::Color = item.into(); - let word = - (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); - - while !self.tx.write(word) { - cortex_m::asm::nop(); - } - } - Ok(()) - } -} - -impl SmartLedsWrite02 for Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - /// If you call this function, be advised that you will have to wait - /// at least 60 microseconds between calls of this function! - /// That means, either you get hold on a timer and the timing - /// requirements right your self, or rather use [Ws2812]. - /// - /// Please bear in mind, that it still blocks when writing into the - /// PIO FIFO until all data has been transmitted to the LED chain. - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: Iterator, - J: Into, - { - SmartLedsWrite::write(self, iterator) - } -} - -/// Instance of a WS2812 LED chain. -/// -/// Use the [Ws2812::write] method to update the WS2812 LED chain. -/// -/// Typical usage example: -///```ignore -/// use rp2040_hal::clocks::init_clocks_and_plls; -/// let clocks = init_clocks_and_plls(...); -/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); -/// -/// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); -/// -/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); -/// let mut ws = Ws2812::new( -/// pins.gpio4.into_mode(), -/// &mut pio, -/// sm0, -/// clocks.peripheral_clock.freq(), -/// timer.count_down(), -/// ); -/// -/// loop { -/// use smart_leds::{SmartLedsWrite, RGB8}; -/// let color : RGB8 = (255, 0, 255).into(); -/// -/// ws.write([color].iter().copied()).unwrap(); -/// -/// // Do other stuff here... -/// }; -///``` -pub struct Ws2812 -where - C: CountDown, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - driver: Ws2812Direct, - cd: C, -} - -impl Ws2812 -where - C: CountDown, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - /// Creates a new instance of this driver. - pub fn new( - pin: I, - pio: &mut PIO

, - sm: UninitStateMachine<(P, SM)>, - clock_freq: fugit::HertzU32, - cd: C, - ) -> Ws2812 { - let driver = Ws2812Direct::new(pin, pio, sm, clock_freq); - - Self { driver, cd } - } -} - -impl SmartLedsWrite for Ws2812 -where - C: CountDown, - C::Time: From, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - self.driver.tx.clear_stalled_flag(); - while !self.driver.tx.is_empty() && !self.driver.tx.has_stalled() {} - - self.cd.start(60u32.micros()); - let _ = nb::block!(self.cd.wait()); - - SmartLedsWrite::write(&mut self.driver, iterator) - } -} - -impl SmartLedsWrite02 for Ws2812 -where - C: CountDown, - C::Time: From, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - SmartLedsWrite::write(self, iterator) - } -} +#[cfg(all(feature = "rp2040", feature = "rp235x"))] +compile_error!("Only one HAL feature can be enabled at a time!"); diff --git a/src/rp2040.rs b/src/rp2040.rs new file mode 100644 index 0000000..eb6e6c4 --- /dev/null +++ b/src/rp2040.rs @@ -0,0 +1,321 @@ + +//! WS2812 PIO Driver for the RP2040 +//! +//! This driver implements driving a WS2812 RGB LED strip from +//! a PIO device of the RP2040 chip. +//! +//! You should reach to [Ws2812] if you run the main loop +//! of your controller yourself and you want [Ws2812] to take +//! a hold of your timer. +//! +//! In case you use `cortex-m-rtic` and can't afford this crate +//! to wait blocking for you, you should try [Ws2812Direct]. +//! Bear in mind that you will have to take care of timing requirements +//! yourself then. + +use embedded_hal::timer::CountDown; +use fugit::{ExtU32, HertzU32, MicrosDurationU32}; +#[cfg(feature = "rp2040")] +use rp2040_hal::{ + gpio::AnyPin, + pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, +}; +use smart_leds_trait::SmartLedsWrite; +use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; + +/// This is the WS2812 PIO Driver. +/// +/// For blocking applications is recommended to use +/// the [Ws2812] struct instead of this raw driver. +/// +/// If you use this driver directly, you will need to +/// take care of the timing expectations of the [Ws2812Direct::write] +/// method. +/// +/// Typical usage example: +///```ignore +/// use rp2040_hal::clocks::init_clocks_and_plls; +/// let clocks = init_clocks_and_plls(...); +/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); +/// +/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +/// let mut ws = Ws2812Direct::new( +/// pins.gpio4.into_mode(), +/// &mut pio, +/// sm0, +/// clocks.peripheral_clock.freq(), +/// ); +/// +/// // Then you will make sure yourself to not write too frequently: +/// loop { +/// use smart_leds::{SmartLedsWrite, RGB8}; +/// let color : RGB8 = (255, 0, 255).into(); +/// +/// ws.write([color].iter().copied()).unwrap(); +/// delay_for_at_least_60_microseconds(); +/// }; +///``` +#[cfg(feature = "rp2040")] +pub struct Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + tx: Tx<(P, SM)>, + _pin: I, +} + +#[cfg(feature = "rp2040")] +impl Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + /// Creates a new instance of this driver. + pub fn new( + pin: I, + pio: &mut PIO

, + sm: UninitStateMachine<(P, SM)>, + clock_freq: fugit::HertzU32, + ) -> Self { + // prepare the PIO program + let side_set = pio::SideSet::new(false, 1, false); + let mut a = 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; + const FREQ: HertzU32 = HertzU32::kHz(800); + + let mut wrap_target = a.label(); + let mut wrap_source = a.label(); + let mut do_zero = a.label(); + 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 program = a.assemble_with_wrap(wrap_source, wrap_target); + + // Install the program into PIO instruction memory. + let installed = pio.install(&program).unwrap(); + + // Configure the PIO state machine. + let bit_freq = FREQ * CYCLES_PER_BIT; + let mut int = clock_freq / bit_freq; + let rem = clock_freq - (int * bit_freq); + let frac = (rem * 256) / bit_freq; + assert!( + (1..=65536).contains(&int) && (int != 65536 || frac == 0), + "(System Clock / {}) must be within [1.0, 65536.0].", + bit_freq.to_kHz() + ); + + // 65536.0 is represented as 0 in the pio's clock divider + if int == 65536 { + int = 0; + } + // Using lossy conversion because range have been checked + let int: u16 = int as u16; + let frac: u8 = frac as u8; + + let pin = pin.into(); + let (mut sm, _, tx) = rp2040_hal::pio::PIOBuilder::from_installed_program(installed) + // only use TX FIFO + .buffers(rp2040_hal::pio::Buffers::OnlyTx) + // Pin configuration + .side_set_pin_base(pin.id().num) + // OSR config + .out_shift_direction(rp2040_hal::pio::ShiftDirection::Left) + .autopull(true) + .pull_threshold(24) + .clock_divisor_fixed_point(int, frac) + .build(sm); + + // Prepare pin's direction. + sm.set_pindirs([(pin.id().num, rp2040_hal::pio::PinDir::Output)]); + + sm.start(); + + Self { + tx, + _pin: I::from(pin), + } + } +} + +#[cfg(feature = "rp2040")] +impl SmartLedsWrite for Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + /// If you call this function, be advised that you will have to wait + /// at least 60 microseconds between calls of this function! + /// That means, either you get hold on a timer and the timing + /// requirements right your self, or rather use [Ws2812]. + /// + /// Please bear in mind, that it still blocks when writing into the + /// PIO FIFO until all data has been transmitted to the LED chain. + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + for item in iterator { + let color: Self::Color = item.into(); + let word = + (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); + + while !self.tx.write(word) { + cortex_m::asm::nop(); + } + } + Ok(()) + } +} + +#[cfg(feature = "rp2040")] +impl SmartLedsWrite02 for Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + /// If you call this function, be advised that you will have to wait + /// at least 60 microseconds between calls of this function! + /// That means, either you get hold on a timer and the timing + /// requirements right your self, or rather use [Ws2812]. + /// + /// Please bear in mind, that it still blocks when writing into the + /// PIO FIFO until all data has been transmitted to the LED chain. + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: Iterator, + J: Into, + { + SmartLedsWrite::write(self, iterator) + } +} + +/// Instance of a WS2812 LED chain. +/// +/// Use the [Ws2812::write] method to update the WS2812 LED chain. +/// +/// Typical usage example: +///```ignore +/// use rp2040_hal::clocks::init_clocks_and_plls; +/// let clocks = init_clocks_and_plls(...); +/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); +/// +/// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); +/// +/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +/// let mut ws = Ws2812::new( +/// pins.gpio4.into_mode(), +/// &mut pio, +/// sm0, +/// clocks.peripheral_clock.freq(), +/// timer.count_down(), +/// ); +/// +/// loop { +/// use smart_leds::{SmartLedsWrite, RGB8}; +/// let color : RGB8 = (255, 0, 255).into(); +/// +/// ws.write([color].iter().copied()).unwrap(); +/// +/// // Do other stuff here... +/// }; +///``` +#[cfg(feature = "rp2040")] +pub struct Ws2812 +where + C: CountDown, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + driver: Ws2812Direct, + cd: C, +} + +#[cfg(feature = "rp2040")] +impl Ws2812 +where + C: CountDown, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + /// Creates a new instance of this driver. + pub fn new( + pin: I, + pio: &mut PIO

, + sm: UninitStateMachine<(P, SM)>, + clock_freq: fugit::HertzU32, + cd: C, + ) -> Ws2812 { + let driver = Ws2812Direct::new(pin, pio, sm, clock_freq); + + Self { driver, cd } + } +} +#[cfg(feature = "rp2040")] +impl SmartLedsWrite for Ws2812 +where + C: CountDown, + C::Time: From, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + self.driver.tx.clear_stalled_flag(); + while !self.driver.tx.is_empty() && !self.driver.tx.has_stalled() {} + + self.cd.start(60u32.micros()); + let _ = nb::block!(self.cd.wait()); + + SmartLedsWrite::write(&mut self.driver, iterator) + } +} +#[cfg(feature = "rp2040")] +impl SmartLedsWrite02 for Ws2812 +where + C: CountDown, + C::Time: From, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + SmartLedsWrite::write(self, iterator) + } +} diff --git a/src/rp235x.rs b/src/rp235x.rs new file mode 100644 index 0000000..6b2aefe --- /dev/null +++ b/src/rp235x.rs @@ -0,0 +1,320 @@ +//! WS2812 PIO Driver for the RP235x +//! +//! This driver implements driving a WS2812 RGB LED strip from +//! a PIO device of the RP235x chip. +//! +//! You should reach to [Ws2812] if you run the main loop +//! of your controller yourself and you want [Ws2812] to take +//! a hold of your timer. +//! +//! In case you use `cortex-m-rtic` and can't afford this crate +//! to wait blocking for you, you should try [Ws2812Direct]. +//! Bear in mind that you will have to take care of timing requirements +//! yourself then. + +use embedded_hal::timer::CountDown; +use fugit::{ExtU32, HertzU32, MicrosDurationU32}; +#[cfg(feature = "rp235x")] +use rp235x_hal::{ + gpio::AnyPin, + pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, +}; +use smart_leds_trait::SmartLedsWrite; +use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; + +/// This is the WS2812 PIO Driver. +/// +/// For blocking applications is recommended to use +/// the [Ws2812] struct instead of this raw driver. +/// +/// If you use this driver directly, you will need to +/// take care of the timing expectations of the [Ws2812Direct::write] +/// method. +/// +/// Typical usage example: +///```ignore +/// use rp235x_hal::clocks::init_clocks_and_plls; +/// let clocks = init_clocks_and_plls(...); +/// let pins = rp235x_hal::gpio::pin::bank0::Pins::new(...); +/// +/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +/// let mut ws = Ws2812Direct::new( +/// pins.gpio4.into_mode(), +/// &mut pio, +/// sm0, +/// clocks.peripheral_clock.freq(), +/// ); +/// +/// // Then you will make sure yourself to not write too frequently: +/// loop { +/// use smart_leds::{SmartLedsWrite, RGB8}; +/// let color : RGB8 = (255, 0, 255).into(); +/// +/// ws.write([color].iter().copied()).unwrap(); +/// delay_for_at_least_60_microseconds(); +/// }; +///``` +#[cfg(feature = "rp235x")] +pub struct Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + tx: Tx<(P, SM)>, + _pin: I, +} + +#[cfg(feature = "rp235x")] +impl Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + /// Creates a new instance of this driver. + pub fn new( + pin: I, + pio: &mut PIO

, + sm: UninitStateMachine<(P, SM)>, + clock_freq: fugit::HertzU32, + ) -> Self { + // prepare the PIO program + let side_set = pio::SideSet::new(false, 1, false); + let mut a = 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; + const FREQ: HertzU32 = HertzU32::kHz(800); + + let mut wrap_target = a.label(); + let mut wrap_source = a.label(); + let mut do_zero = a.label(); + 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 program = a.assemble_with_wrap(wrap_source, wrap_target); + + // Install the program into PIO instruction memory. + let installed = pio.install(&program).unwrap(); + + // Configure the PIO state machine. + let bit_freq = FREQ * CYCLES_PER_BIT; + let mut int = clock_freq / bit_freq; + let rem = clock_freq - (int * bit_freq); + let frac = (rem * 256) / bit_freq; + assert!( + (1..=65536).contains(&int) && (int != 65536 || frac == 0), + "(System Clock / {}) must be within [1.0, 65536.0].", + bit_freq.to_kHz() + ); + + // 65536.0 is represented as 0 in the pio's clock divider + if int == 65536 { + int = 0; + } + // Using lossy conversion because range have been checked + let int: u16 = int as u16; + let frac: u8 = frac as u8; + + let pin = pin.into(); + let (mut sm, _, tx) = rp235x_hal::pio::PIOBuilder::from_installed_program(installed) + // only use TX FIFO + .buffers(rp235x_hal::pio::Buffers::OnlyTx) + // Pin configuration + .side_set_pin_base(pin.id().num) + // OSR config + .out_shift_direction(rp235x_hal::pio::ShiftDirection::Left) + .autopull(true) + .pull_threshold(24) + .clock_divisor_fixed_point(int, frac) + .build(sm); + + // Prepare pin's direction. + sm.set_pindirs([(pin.id().num, rp235x_hal::pio::PinDir::Output)]); + + sm.start(); + + Self { + tx, + _pin: I::from(pin), + } + } +} + +#[cfg(feature = "rp235x")] +impl SmartLedsWrite for Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + /// If you call this function, be advised that you will have to wait + /// at least 60 microseconds between calls of this function! + /// That means, either you get hold on a timer and the timing + /// requirements right your self, or rather use [Ws2812]. + /// + /// Please bear in mind, that it still blocks when writing into the + /// PIO FIFO until all data has been transmitted to the LED chain. + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + for item in iterator { + let color: Self::Color = item.into(); + let word = + (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); + + while !self.tx.write(word) { + cortex_m::asm::nop(); + } + } + Ok(()) + } +} + +#[cfg(feature = "rp235x")] +impl SmartLedsWrite02 for Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + /// If you call this function, be advised that you will have to wait + /// at least 60 microseconds between calls of this function! + /// That means, either you get hold on a timer and the timing + /// requirements right your self, or rather use [Ws2812]. + /// + /// Please bear in mind, that it still blocks when writing into the + /// PIO FIFO until all data has been transmitted to the LED chain. + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: Iterator, + J: Into, + { + SmartLedsWrite::write(self, iterator) + } +} + +/// Instance of a WS2812 LED chain. +/// +/// Use the [Ws2812::write] method to update the WS2812 LED chain. +/// +/// Typical usage example: +///```ignore +/// use rp235x_hal::clocks::init_clocks_and_plls; +/// let clocks = init_clocks_and_plls(...); +/// let pins = rp235x_hal::gpio::pin::bank0::Pins::new(...); +/// +/// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); +/// +/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +/// let mut ws = Ws2812::new( +/// pins.gpio4.into_mode(), +/// &mut pio, +/// sm0, +/// clocks.peripheral_clock.freq(), +/// timer.count_down(), +/// ); +/// +/// loop { +/// use smart_leds::{SmartLedsWrite, RGB8}; +/// let color : RGB8 = (255, 0, 255).into(); +/// +/// ws.write([color].iter().copied()).unwrap(); +/// +/// // Do other stuff here... +/// }; +///``` +#[cfg(feature = "rp235x")] +pub struct Ws2812 +where + C: CountDown, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + driver: Ws2812Direct, + cd: C, +} + +#[cfg(feature = "rp235x")] +impl Ws2812 +where + C: CountDown, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + /// Creates a new instance of this driver. + pub fn new( + pin: I, + pio: &mut PIO

, + sm: UninitStateMachine<(P, SM)>, + clock_freq: fugit::HertzU32, + cd: C, + ) -> Ws2812 { + let driver = Ws2812Direct::new(pin, pio, sm, clock_freq); + + Self { driver, cd } + } +} +#[cfg(feature = "rp235x")] +impl SmartLedsWrite for Ws2812 +where + C: CountDown, + C::Time: From, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + self.driver.tx.clear_stalled_flag(); + while !self.driver.tx.is_empty() && !self.driver.tx.has_stalled() {} + + self.cd.start(60u32.micros()); + let _ = nb::block!(self.cd.wait()); + + SmartLedsWrite::write(&mut self.driver, iterator) + } +} +#[cfg(feature = "rp235x")] +impl SmartLedsWrite02 for Ws2812 +where + C: CountDown, + C::Time: From, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + SmartLedsWrite::write(self, iterator) + } +} From 80474b6a3a544bf4864194e65326df493563d300 Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sat, 22 Feb 2025 22:54:11 -0800 Subject: [PATCH 02/10] Allow unused imports --- Cargo.toml | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 21ad151..a9ab43d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,6 @@ rp2040-hal = { version = "0.11.0", optional = true } rp235x-hal = { version = "0.2.0", optional = true } [features] -default = [] +default = ["rp2040"] rp2040 = ["dep:rp2040-hal"] rp235x = ["dep:rp235x-hal"] diff --git a/src/lib.rs b/src/lib.rs index abdc9f5..6d46cf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ #![no_std] + +#![allow(unused_imports)] #[cfg(feature = "rp2040")] mod rp2040; @@ -11,5 +13,3 @@ pub use rp2040::*; #[cfg(feature = "rp235x")] pub use rp235x::*; -#[cfg(all(feature = "rp2040", feature = "rp235x"))] -compile_error!("Only one HAL feature can be enabled at a time!"); From 85553cc01a558b30fc443be1e93f9dfc560ed55b Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sat, 22 Feb 2025 23:23:37 -0800 Subject: [PATCH 03/10] Cleanup --- src/lib.rs | 13 ++----------- src/rp2040.rs | 1 + 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6d46cf6..039a09c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,15 +1,6 @@ #![no_std] - -#![allow(unused_imports)] -#[cfg(feature = "rp2040")] -mod rp2040; - -#[cfg(feature = "rp235x")] -mod rp235x; - #[cfg(feature = "rp2040")] -pub use rp2040::*; +pub mod rp2040; #[cfg(feature = "rp235x")] -pub use rp235x::*; - +pub mod rp235x; diff --git a/src/rp2040.rs b/src/rp2040.rs index eb6e6c4..fae4bf8 100644 --- a/src/rp2040.rs +++ b/src/rp2040.rs @@ -20,6 +20,7 @@ use rp2040_hal::{ gpio::AnyPin, pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, }; + use smart_leds_trait::SmartLedsWrite; use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; From a5f6dd5e182062a7188967bae24cdd1989d0928d Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sat, 22 Feb 2025 23:38:06 -0800 Subject: [PATCH 04/10] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f41a9c2..38b2694 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,7 @@ name: Build and Test check jobs: builds: name: Build checks - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: matrix: mode: ["", "--release"] From c5f8e26dc54db29da7548ea231459546b5bd54a2 Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sat, 22 Feb 2025 23:39:00 -0800 Subject: [PATCH 05/10] ubuntu-24.04 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f41a9c2..38b2694 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,7 @@ name: Build and Test check jobs: builds: name: Build checks - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 strategy: matrix: mode: ["", "--release"] From 268f66449ce41265bba928ee662dbbaca8ef3ade Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sun, 23 Feb 2025 10:16:23 -0800 Subject: [PATCH 06/10] Removing default feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a9ab43d..21ad151 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,6 @@ rp2040-hal = { version = "0.11.0", optional = true } rp235x-hal = { version = "0.2.0", optional = true } [features] -default = ["rp2040"] +default = [] rp2040 = ["dep:rp2040-hal"] rp235x = ["dep:rp235x-hal"] From bc4a674ead1bed9c392bed7df032170c32c1b7ae Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sun, 23 Feb 2025 11:32:10 -0800 Subject: [PATCH 07/10] Keeping old lib as default --- Cargo.toml | 2 +- src/lib.rs | 322 +++++++++++++++++++++++++++++++++++++++++++++++++- src/rp2040.rs | 322 -------------------------------------------------- 3 files changed, 322 insertions(+), 324 deletions(-) delete mode 100644 src/rp2040.rs diff --git a/Cargo.toml b/Cargo.toml index 21ad151..a9ab43d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,6 @@ rp2040-hal = { version = "0.11.0", optional = true } rp235x-hal = { version = "0.2.0", optional = true } [features] -default = [] +default = ["rp2040"] rp2040 = ["dep:rp2040-hal"] rp235x = ["dep:rp235x-hal"] diff --git a/src/lib.rs b/src/lib.rs index 039a09c..fc728a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,326 @@ #![no_std] +//! WS2812 PIO Driver for the RP2040 +//! +//! This driver implements driving a WS2812 RGB LED strip from +//! a PIO device of the RP2040 chip. +//! +//! You should reach to [Ws2812] if you run the main loop +//! of your controller yourself and you want [Ws2812] to take +//! a hold of your timer. +//! +//! In case you use `cortex-m-rtic` and can't afford this crate +//! to wait blocking for you, you should try [Ws2812Direct]. +//! Bear in mind that you will have to take care of timing requirements +//! yourself then. + +use embedded_hal::timer::CountDown; +use fugit::{ExtU32, HertzU32, MicrosDurationU32}; +#[cfg(feature = "rp2040")] +use rp2040_hal::{ + gpio::AnyPin, + pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, +}; + +use smart_leds_trait::SmartLedsWrite; +use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; + +/// This is the WS2812 PIO Driver. +/// +/// For blocking applications is recommended to use +/// the [Ws2812] struct instead of this raw driver. +/// +/// If you use this driver directly, you will need to +/// take care of the timing expectations of the [Ws2812Direct::write] +/// method. +/// +/// Typical usage example: +///```ignore +/// use rp2040_hal::clocks::init_clocks_and_plls; +/// let clocks = init_clocks_and_plls(...); +/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); +/// +/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +/// let mut ws = Ws2812Direct::new( +/// pins.gpio4.into_mode(), +/// &mut pio, +/// sm0, +/// clocks.peripheral_clock.freq(), +/// ); +/// +/// // Then you will make sure yourself to not write too frequently: +/// loop { +/// use smart_leds::{SmartLedsWrite, RGB8}; +/// let color : RGB8 = (255, 0, 255).into(); +/// +/// ws.write([color].iter().copied()).unwrap(); +/// delay_for_at_least_60_microseconds(); +/// }; +///``` +#[cfg(feature = "rp2040")] +pub struct Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + tx: Tx<(P, SM)>, + _pin: I, +} + +#[cfg(feature = "rp2040")] +impl Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + /// Creates a new instance of this driver. + pub fn new( + pin: I, + pio: &mut PIO

, + sm: UninitStateMachine<(P, SM)>, + clock_freq: fugit::HertzU32, + ) -> Self { + // prepare the PIO program + let side_set = pio::SideSet::new(false, 1, false); + let mut a = 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; + const FREQ: HertzU32 = HertzU32::kHz(800); + + let mut wrap_target = a.label(); + let mut wrap_source = a.label(); + let mut do_zero = a.label(); + 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 program = a.assemble_with_wrap(wrap_source, wrap_target); + + // Install the program into PIO instruction memory. + let installed = pio.install(&program).unwrap(); + + // Configure the PIO state machine. + let bit_freq = FREQ * CYCLES_PER_BIT; + let mut int = clock_freq / bit_freq; + let rem = clock_freq - (int * bit_freq); + let frac = (rem * 256) / bit_freq; + assert!( + (1..=65536).contains(&int) && (int != 65536 || frac == 0), + "(System Clock / {}) must be within [1.0, 65536.0].", + bit_freq.to_kHz() + ); + + // 65536.0 is represented as 0 in the pio's clock divider + if int == 65536 { + int = 0; + } + // Using lossy conversion because range have been checked + let int: u16 = int as u16; + let frac: u8 = frac as u8; + + let pin = pin.into(); + let (mut sm, _, tx) = rp2040_hal::pio::PIOBuilder::from_installed_program(installed) + // only use TX FIFO + .buffers(rp2040_hal::pio::Buffers::OnlyTx) + // Pin configuration + .side_set_pin_base(pin.id().num) + // OSR config + .out_shift_direction(rp2040_hal::pio::ShiftDirection::Left) + .autopull(true) + .pull_threshold(24) + .clock_divisor_fixed_point(int, frac) + .build(sm); + + // Prepare pin's direction. + sm.set_pindirs([(pin.id().num, rp2040_hal::pio::PinDir::Output)]); + + sm.start(); + + Self { + tx, + _pin: I::from(pin), + } + } +} + +#[cfg(feature = "rp2040")] +impl SmartLedsWrite for Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + /// If you call this function, be advised that you will have to wait + /// at least 60 microseconds between calls of this function! + /// That means, either you get hold on a timer and the timing + /// requirements right your self, or rather use [Ws2812]. + /// + /// Please bear in mind, that it still blocks when writing into the + /// PIO FIFO until all data has been transmitted to the LED chain. + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + for item in iterator { + let color: Self::Color = item.into(); + let word = + (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); + + while !self.tx.write(word) { + cortex_m::asm::nop(); + } + } + Ok(()) + } +} + +#[cfg(feature = "rp2040")] +impl SmartLedsWrite02 for Ws2812Direct +where + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + /// If you call this function, be advised that you will have to wait + /// at least 60 microseconds between calls of this function! + /// That means, either you get hold on a timer and the timing + /// requirements right your self, or rather use [Ws2812]. + /// + /// Please bear in mind, that it still blocks when writing into the + /// PIO FIFO until all data has been transmitted to the LED chain. + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: Iterator, + J: Into, + { + SmartLedsWrite::write(self, iterator) + } +} + +/// Instance of a WS2812 LED chain. +/// +/// Use the [Ws2812::write] method to update the WS2812 LED chain. +/// +/// Typical usage example: +///```ignore +/// use rp2040_hal::clocks::init_clocks_and_plls; +/// let clocks = init_clocks_and_plls(...); +/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); +/// +/// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); +/// +/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); +/// let mut ws = Ws2812::new( +/// pins.gpio4.into_mode(), +/// &mut pio, +/// sm0, +/// clocks.peripheral_clock.freq(), +/// timer.count_down(), +/// ); +/// +/// loop { +/// use smart_leds::{SmartLedsWrite, RGB8}; +/// let color : RGB8 = (255, 0, 255).into(); +/// +/// ws.write([color].iter().copied()).unwrap(); +/// +/// // Do other stuff here... +/// }; +///``` #[cfg(feature = "rp2040")] -pub mod rp2040; +pub struct Ws2812 +where + C: CountDown, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + driver: Ws2812Direct, + cd: C, +} + +#[cfg(feature = "rp2040")] +impl Ws2812 +where + C: CountDown, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + /// Creates a new instance of this driver. + pub fn new( + pin: I, + pio: &mut PIO

, + sm: UninitStateMachine<(P, SM)>, + clock_freq: fugit::HertzU32, + cd: C, + ) -> Ws2812 { + let driver = Ws2812Direct::new(pin, pio, sm, clock_freq); + + Self { driver, cd } + } +} +#[cfg(feature = "rp2040")] +impl SmartLedsWrite for Ws2812 +where + C: CountDown, + C::Time: From, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + self.driver.tx.clear_stalled_flag(); + while !self.driver.tx.is_empty() && !self.driver.tx.has_stalled() {} + + self.cd.start(60u32.micros()); + let _ = nb::block!(self.cd.wait()); + + SmartLedsWrite::write(&mut self.driver, iterator) + } +} +#[cfg(feature = "rp2040")] +impl SmartLedsWrite02 for Ws2812 +where + C: CountDown, + C::Time: From, + I: AnyPin, + P: PIOExt, + SM: StateMachineIndex, +{ + type Color = smart_leds_trait::RGB8; + type Error = (); + fn write(&mut self, iterator: T) -> Result<(), ()> + where + T: IntoIterator, + J: Into, + { + SmartLedsWrite::write(self, iterator) + } +} + #[cfg(feature = "rp235x")] pub mod rp235x; diff --git a/src/rp2040.rs b/src/rp2040.rs deleted file mode 100644 index fae4bf8..0000000 --- a/src/rp2040.rs +++ /dev/null @@ -1,322 +0,0 @@ - -//! WS2812 PIO Driver for the RP2040 -//! -//! This driver implements driving a WS2812 RGB LED strip from -//! a PIO device of the RP2040 chip. -//! -//! You should reach to [Ws2812] if you run the main loop -//! of your controller yourself and you want [Ws2812] to take -//! a hold of your timer. -//! -//! In case you use `cortex-m-rtic` and can't afford this crate -//! to wait blocking for you, you should try [Ws2812Direct]. -//! Bear in mind that you will have to take care of timing requirements -//! yourself then. - -use embedded_hal::timer::CountDown; -use fugit::{ExtU32, HertzU32, MicrosDurationU32}; -#[cfg(feature = "rp2040")] -use rp2040_hal::{ - gpio::AnyPin, - pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, -}; - -use smart_leds_trait::SmartLedsWrite; -use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; - -/// This is the WS2812 PIO Driver. -/// -/// For blocking applications is recommended to use -/// the [Ws2812] struct instead of this raw driver. -/// -/// If you use this driver directly, you will need to -/// take care of the timing expectations of the [Ws2812Direct::write] -/// method. -/// -/// Typical usage example: -///```ignore -/// use rp2040_hal::clocks::init_clocks_and_plls; -/// let clocks = init_clocks_and_plls(...); -/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); -/// -/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); -/// let mut ws = Ws2812Direct::new( -/// pins.gpio4.into_mode(), -/// &mut pio, -/// sm0, -/// clocks.peripheral_clock.freq(), -/// ); -/// -/// // Then you will make sure yourself to not write too frequently: -/// loop { -/// use smart_leds::{SmartLedsWrite, RGB8}; -/// let color : RGB8 = (255, 0, 255).into(); -/// -/// ws.write([color].iter().copied()).unwrap(); -/// delay_for_at_least_60_microseconds(); -/// }; -///``` -#[cfg(feature = "rp2040")] -pub struct Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - tx: Tx<(P, SM)>, - _pin: I, -} - -#[cfg(feature = "rp2040")] -impl Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - /// Creates a new instance of this driver. - pub fn new( - pin: I, - pio: &mut PIO

, - sm: UninitStateMachine<(P, SM)>, - clock_freq: fugit::HertzU32, - ) -> Self { - // prepare the PIO program - let side_set = pio::SideSet::new(false, 1, false); - let mut a = 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; - const FREQ: HertzU32 = HertzU32::kHz(800); - - let mut wrap_target = a.label(); - let mut wrap_source = a.label(); - let mut do_zero = a.label(); - 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 program = a.assemble_with_wrap(wrap_source, wrap_target); - - // Install the program into PIO instruction memory. - let installed = pio.install(&program).unwrap(); - - // Configure the PIO state machine. - let bit_freq = FREQ * CYCLES_PER_BIT; - let mut int = clock_freq / bit_freq; - let rem = clock_freq - (int * bit_freq); - let frac = (rem * 256) / bit_freq; - assert!( - (1..=65536).contains(&int) && (int != 65536 || frac == 0), - "(System Clock / {}) must be within [1.0, 65536.0].", - bit_freq.to_kHz() - ); - - // 65536.0 is represented as 0 in the pio's clock divider - if int == 65536 { - int = 0; - } - // Using lossy conversion because range have been checked - let int: u16 = int as u16; - let frac: u8 = frac as u8; - - let pin = pin.into(); - let (mut sm, _, tx) = rp2040_hal::pio::PIOBuilder::from_installed_program(installed) - // only use TX FIFO - .buffers(rp2040_hal::pio::Buffers::OnlyTx) - // Pin configuration - .side_set_pin_base(pin.id().num) - // OSR config - .out_shift_direction(rp2040_hal::pio::ShiftDirection::Left) - .autopull(true) - .pull_threshold(24) - .clock_divisor_fixed_point(int, frac) - .build(sm); - - // Prepare pin's direction. - sm.set_pindirs([(pin.id().num, rp2040_hal::pio::PinDir::Output)]); - - sm.start(); - - Self { - tx, - _pin: I::from(pin), - } - } -} - -#[cfg(feature = "rp2040")] -impl SmartLedsWrite for Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - /// If you call this function, be advised that you will have to wait - /// at least 60 microseconds between calls of this function! - /// That means, either you get hold on a timer and the timing - /// requirements right your self, or rather use [Ws2812]. - /// - /// Please bear in mind, that it still blocks when writing into the - /// PIO FIFO until all data has been transmitted to the LED chain. - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - for item in iterator { - let color: Self::Color = item.into(); - let word = - (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); - - while !self.tx.write(word) { - cortex_m::asm::nop(); - } - } - Ok(()) - } -} - -#[cfg(feature = "rp2040")] -impl SmartLedsWrite02 for Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - /// If you call this function, be advised that you will have to wait - /// at least 60 microseconds between calls of this function! - /// That means, either you get hold on a timer and the timing - /// requirements right your self, or rather use [Ws2812]. - /// - /// Please bear in mind, that it still blocks when writing into the - /// PIO FIFO until all data has been transmitted to the LED chain. - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: Iterator, - J: Into, - { - SmartLedsWrite::write(self, iterator) - } -} - -/// Instance of a WS2812 LED chain. -/// -/// Use the [Ws2812::write] method to update the WS2812 LED chain. -/// -/// Typical usage example: -///```ignore -/// use rp2040_hal::clocks::init_clocks_and_plls; -/// let clocks = init_clocks_and_plls(...); -/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); -/// -/// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); -/// -/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); -/// let mut ws = Ws2812::new( -/// pins.gpio4.into_mode(), -/// &mut pio, -/// sm0, -/// clocks.peripheral_clock.freq(), -/// timer.count_down(), -/// ); -/// -/// loop { -/// use smart_leds::{SmartLedsWrite, RGB8}; -/// let color : RGB8 = (255, 0, 255).into(); -/// -/// ws.write([color].iter().copied()).unwrap(); -/// -/// // Do other stuff here... -/// }; -///``` -#[cfg(feature = "rp2040")] -pub struct Ws2812 -where - C: CountDown, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - driver: Ws2812Direct, - cd: C, -} - -#[cfg(feature = "rp2040")] -impl Ws2812 -where - C: CountDown, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - /// Creates a new instance of this driver. - pub fn new( - pin: I, - pio: &mut PIO

, - sm: UninitStateMachine<(P, SM)>, - clock_freq: fugit::HertzU32, - cd: C, - ) -> Ws2812 { - let driver = Ws2812Direct::new(pin, pio, sm, clock_freq); - - Self { driver, cd } - } -} -#[cfg(feature = "rp2040")] -impl SmartLedsWrite for Ws2812 -where - C: CountDown, - C::Time: From, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - self.driver.tx.clear_stalled_flag(); - while !self.driver.tx.is_empty() && !self.driver.tx.has_stalled() {} - - self.cd.start(60u32.micros()); - let _ = nb::block!(self.cd.wait()); - - SmartLedsWrite::write(&mut self.driver, iterator) - } -} -#[cfg(feature = "rp2040")] -impl SmartLedsWrite02 for Ws2812 -where - C: CountDown, - C::Time: From, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - SmartLedsWrite::write(self, iterator) - } -} From 5cfde66ee3507199a9f9fe7421e690ef42d4897f Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Thu, 6 Mar 2025 12:44:44 -0800 Subject: [PATCH 08/10] Using cfg-if macro to conditionally define hal --- Cargo.toml | 1 + src/lib.rs | 46 ++++---- src/rp235x.rs | 320 -------------------------------------------------- 3 files changed, 25 insertions(+), 342 deletions(-) delete mode 100644 src/rp235x.rs diff --git a/Cargo.toml b/Cargo.toml index a9ab43d..7e8998e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ documentation = "https://docs.rs/ws2812-pio" repository = "https://github.com/rp-rs/ws2812-pio-rs/" [dependencies] +cfg-if = "1.0" embedded-hal = "0.2.5" fugit = "0.3.5" pio = "0.2.0" diff --git a/src/lib.rs b/src/lib.rs index fc728a7..5bbba9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,20 @@ use embedded_hal::timer::CountDown; use fugit::{ExtU32, HertzU32, MicrosDurationU32}; -#[cfg(feature = "rp2040")] -use rp2040_hal::{ + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature = "rp2040")] { + use rp2040_hal as hal; + } else if #[cfg(feature = "rp235x")] { + use rp235x_hal as hal; + } else { + compile_error!("Either 'rp2040' or 'rp235x' feature must be enabled."); + } +} + +use hal::{ gpio::AnyPin, pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, }; @@ -35,9 +47,9 @@ use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; /// /// Typical usage example: ///```ignore -/// use rp2040_hal::clocks::init_clocks_and_plls; +/// use hal::clocks::init_clocks_and_plls; /// let clocks = init_clocks_and_plls(...); -/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); +/// let pins = hal::gpio::pin::bank0::Pins::new(...); /// /// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); /// let mut ws = Ws2812Direct::new( @@ -56,7 +68,7 @@ use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; /// delay_for_at_least_60_microseconds(); /// }; ///``` -#[cfg(feature = "rp2040")] + pub struct Ws2812Direct where I: AnyPin, @@ -67,7 +79,6 @@ where _pin: I, } -#[cfg(feature = "rp2040")] impl Ws2812Direct where I: AnyPin, @@ -130,20 +141,20 @@ where let frac: u8 = frac as u8; let pin = pin.into(); - let (mut sm, _, tx) = rp2040_hal::pio::PIOBuilder::from_installed_program(installed) + let (mut sm, _, tx) = hal::pio::PIOBuilder::from_installed_program(installed) // only use TX FIFO - .buffers(rp2040_hal::pio::Buffers::OnlyTx) + .buffers(hal::pio::Buffers::OnlyTx) // Pin configuration .side_set_pin_base(pin.id().num) // OSR config - .out_shift_direction(rp2040_hal::pio::ShiftDirection::Left) + .out_shift_direction(hal::pio::ShiftDirection::Left) .autopull(true) .pull_threshold(24) .clock_divisor_fixed_point(int, frac) .build(sm); // Prepare pin's direction. - sm.set_pindirs([(pin.id().num, rp2040_hal::pio::PinDir::Output)]); + sm.set_pindirs([(pin.id().num, hal::pio::PinDir::Output)]); sm.start(); @@ -154,7 +165,6 @@ where } } -#[cfg(feature = "rp2040")] impl SmartLedsWrite for Ws2812Direct where I: AnyPin, @@ -188,7 +198,6 @@ where } } -#[cfg(feature = "rp2040")] impl SmartLedsWrite02 for Ws2812Direct where I: AnyPin, @@ -219,9 +228,9 @@ where /// /// Typical usage example: ///```ignore -/// use rp2040_hal::clocks::init_clocks_and_plls; +/// use hal::clocks::init_clocks_and_plls; /// let clocks = init_clocks_and_plls(...); -/// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...); +/// let pins = hal::gpio::pin::bank0::Pins::new(...); /// /// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); /// @@ -243,7 +252,7 @@ where /// // Do other stuff here... /// }; ///``` -#[cfg(feature = "rp2040")] + pub struct Ws2812 where C: CountDown, @@ -255,7 +264,6 @@ where cd: C, } -#[cfg(feature = "rp2040")] impl Ws2812 where C: CountDown, @@ -276,7 +284,6 @@ where Self { driver, cd } } } -#[cfg(feature = "rp2040")] impl SmartLedsWrite for Ws2812 where C: CountDown, @@ -301,7 +308,6 @@ where SmartLedsWrite::write(&mut self.driver, iterator) } } -#[cfg(feature = "rp2040")] impl SmartLedsWrite02 for Ws2812 where C: CountDown, @@ -320,7 +326,3 @@ where SmartLedsWrite::write(self, iterator) } } - - -#[cfg(feature = "rp235x")] -pub mod rp235x; diff --git a/src/rp235x.rs b/src/rp235x.rs deleted file mode 100644 index 6b2aefe..0000000 --- a/src/rp235x.rs +++ /dev/null @@ -1,320 +0,0 @@ -//! WS2812 PIO Driver for the RP235x -//! -//! This driver implements driving a WS2812 RGB LED strip from -//! a PIO device of the RP235x chip. -//! -//! You should reach to [Ws2812] if you run the main loop -//! of your controller yourself and you want [Ws2812] to take -//! a hold of your timer. -//! -//! In case you use `cortex-m-rtic` and can't afford this crate -//! to wait blocking for you, you should try [Ws2812Direct]. -//! Bear in mind that you will have to take care of timing requirements -//! yourself then. - -use embedded_hal::timer::CountDown; -use fugit::{ExtU32, HertzU32, MicrosDurationU32}; -#[cfg(feature = "rp235x")] -use rp235x_hal::{ - gpio::AnyPin, - pio::{PIOExt, StateMachineIndex, Tx, UninitStateMachine, PIO}, -}; -use smart_leds_trait::SmartLedsWrite; -use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; - -/// This is the WS2812 PIO Driver. -/// -/// For blocking applications is recommended to use -/// the [Ws2812] struct instead of this raw driver. -/// -/// If you use this driver directly, you will need to -/// take care of the timing expectations of the [Ws2812Direct::write] -/// method. -/// -/// Typical usage example: -///```ignore -/// use rp235x_hal::clocks::init_clocks_and_plls; -/// let clocks = init_clocks_and_plls(...); -/// let pins = rp235x_hal::gpio::pin::bank0::Pins::new(...); -/// -/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); -/// let mut ws = Ws2812Direct::new( -/// pins.gpio4.into_mode(), -/// &mut pio, -/// sm0, -/// clocks.peripheral_clock.freq(), -/// ); -/// -/// // Then you will make sure yourself to not write too frequently: -/// loop { -/// use smart_leds::{SmartLedsWrite, RGB8}; -/// let color : RGB8 = (255, 0, 255).into(); -/// -/// ws.write([color].iter().copied()).unwrap(); -/// delay_for_at_least_60_microseconds(); -/// }; -///``` -#[cfg(feature = "rp235x")] -pub struct Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - tx: Tx<(P, SM)>, - _pin: I, -} - -#[cfg(feature = "rp235x")] -impl Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - /// Creates a new instance of this driver. - pub fn new( - pin: I, - pio: &mut PIO

, - sm: UninitStateMachine<(P, SM)>, - clock_freq: fugit::HertzU32, - ) -> Self { - // prepare the PIO program - let side_set = pio::SideSet::new(false, 1, false); - let mut a = 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; - const FREQ: HertzU32 = HertzU32::kHz(800); - - let mut wrap_target = a.label(); - let mut wrap_source = a.label(); - let mut do_zero = a.label(); - 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 program = a.assemble_with_wrap(wrap_source, wrap_target); - - // Install the program into PIO instruction memory. - let installed = pio.install(&program).unwrap(); - - // Configure the PIO state machine. - let bit_freq = FREQ * CYCLES_PER_BIT; - let mut int = clock_freq / bit_freq; - let rem = clock_freq - (int * bit_freq); - let frac = (rem * 256) / bit_freq; - assert!( - (1..=65536).contains(&int) && (int != 65536 || frac == 0), - "(System Clock / {}) must be within [1.0, 65536.0].", - bit_freq.to_kHz() - ); - - // 65536.0 is represented as 0 in the pio's clock divider - if int == 65536 { - int = 0; - } - // Using lossy conversion because range have been checked - let int: u16 = int as u16; - let frac: u8 = frac as u8; - - let pin = pin.into(); - let (mut sm, _, tx) = rp235x_hal::pio::PIOBuilder::from_installed_program(installed) - // only use TX FIFO - .buffers(rp235x_hal::pio::Buffers::OnlyTx) - // Pin configuration - .side_set_pin_base(pin.id().num) - // OSR config - .out_shift_direction(rp235x_hal::pio::ShiftDirection::Left) - .autopull(true) - .pull_threshold(24) - .clock_divisor_fixed_point(int, frac) - .build(sm); - - // Prepare pin's direction. - sm.set_pindirs([(pin.id().num, rp235x_hal::pio::PinDir::Output)]); - - sm.start(); - - Self { - tx, - _pin: I::from(pin), - } - } -} - -#[cfg(feature = "rp235x")] -impl SmartLedsWrite for Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - /// If you call this function, be advised that you will have to wait - /// at least 60 microseconds between calls of this function! - /// That means, either you get hold on a timer and the timing - /// requirements right your self, or rather use [Ws2812]. - /// - /// Please bear in mind, that it still blocks when writing into the - /// PIO FIFO until all data has been transmitted to the LED chain. - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - for item in iterator { - let color: Self::Color = item.into(); - let word = - (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8); - - while !self.tx.write(word) { - cortex_m::asm::nop(); - } - } - Ok(()) - } -} - -#[cfg(feature = "rp235x")] -impl SmartLedsWrite02 for Ws2812Direct -where - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - /// If you call this function, be advised that you will have to wait - /// at least 60 microseconds between calls of this function! - /// That means, either you get hold on a timer and the timing - /// requirements right your self, or rather use [Ws2812]. - /// - /// Please bear in mind, that it still blocks when writing into the - /// PIO FIFO until all data has been transmitted to the LED chain. - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: Iterator, - J: Into, - { - SmartLedsWrite::write(self, iterator) - } -} - -/// Instance of a WS2812 LED chain. -/// -/// Use the [Ws2812::write] method to update the WS2812 LED chain. -/// -/// Typical usage example: -///```ignore -/// use rp235x_hal::clocks::init_clocks_and_plls; -/// let clocks = init_clocks_and_plls(...); -/// let pins = rp235x_hal::gpio::pin::bank0::Pins::new(...); -/// -/// let timer = Timer::new(pac.TIMER, &mut pac.RESETS); -/// -/// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS); -/// let mut ws = Ws2812::new( -/// pins.gpio4.into_mode(), -/// &mut pio, -/// sm0, -/// clocks.peripheral_clock.freq(), -/// timer.count_down(), -/// ); -/// -/// loop { -/// use smart_leds::{SmartLedsWrite, RGB8}; -/// let color : RGB8 = (255, 0, 255).into(); -/// -/// ws.write([color].iter().copied()).unwrap(); -/// -/// // Do other stuff here... -/// }; -///``` -#[cfg(feature = "rp235x")] -pub struct Ws2812 -where - C: CountDown, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - driver: Ws2812Direct, - cd: C, -} - -#[cfg(feature = "rp235x")] -impl Ws2812 -where - C: CountDown, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - /// Creates a new instance of this driver. - pub fn new( - pin: I, - pio: &mut PIO

, - sm: UninitStateMachine<(P, SM)>, - clock_freq: fugit::HertzU32, - cd: C, - ) -> Ws2812 { - let driver = Ws2812Direct::new(pin, pio, sm, clock_freq); - - Self { driver, cd } - } -} -#[cfg(feature = "rp235x")] -impl SmartLedsWrite for Ws2812 -where - C: CountDown, - C::Time: From, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - self.driver.tx.clear_stalled_flag(); - while !self.driver.tx.is_empty() && !self.driver.tx.has_stalled() {} - - self.cd.start(60u32.micros()); - let _ = nb::block!(self.cd.wait()); - - SmartLedsWrite::write(&mut self.driver, iterator) - } -} -#[cfg(feature = "rp235x")] -impl SmartLedsWrite02 for Ws2812 -where - C: CountDown, - C::Time: From, - I: AnyPin, - P: PIOExt, - SM: StateMachineIndex, -{ - type Color = smart_leds_trait::RGB8; - type Error = (); - fn write(&mut self, iterator: T) -> Result<(), ()> - where - T: IntoIterator, - J: Into, - { - SmartLedsWrite::write(self, iterator) - } -} From 56ee5575aea92c894387814238ab3d68be000d45 Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Sun, 7 Dec 2025 20:42:43 -0800 Subject: [PATCH 09/10] Update rp235x-hal to version 0.3.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7e8998e..ef2aa47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ smart-leds-trait-0-2 = { package = "smart-leds-trait", version = "0.2.1" } nb = "1.0.0" cortex-m = "0.7.3" rp2040-hal = { version = "0.11.0", optional = true } -rp235x-hal = { version = "0.2.0", optional = true } +rp235x-hal = { version = "0.3.0", optional = true } [features] default = ["rp2040"] From 3546fdd28cdae8f8a4364fa92e921f975006c9c7 Mon Sep 17 00:00:00 2001 From: Mariusz Jurgielewicz Date: Mon, 8 Dec 2025 21:32:25 -0800 Subject: [PATCH 10/10] Fixing clippy warnings --- .gitignore | 1 + src/lib.rs | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 96ef6c0..77147e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Cargo.lock +.idea/ diff --git a/src/lib.rs b/src/lib.rs index 5bbba9f..d042fb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,7 +68,6 @@ use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02; /// delay_for_at_least_60_microseconds(); /// }; ///``` - pub struct Ws2812Direct where I: AnyPin, @@ -252,7 +251,6 @@ where /// // Do other stuff here... /// }; ///``` - pub struct Ws2812 where C: CountDown,