1313//! Bear in mind that you will have to take care of timing requirements
1414//! yourself then.
1515
16+ use core:: marker:: PhantomData ;
1617use embedded_hal:: timer:: CountDown ;
1718use fugit:: { ExtU32 , HertzU32 , MicrosDurationU32 } ;
1819use rp2040_hal:: {
@@ -54,21 +55,47 @@ use smart_leds_trait_0_2::SmartLedsWrite as SmartLedsWrite02;
5455/// delay_for_at_least_60_microseconds();
5556/// };
5657///```
57- pub struct Ws2812Direct < P , SM , I >
58+ ///
59+ /// Typical RGBW usage example:
60+ ///```ignore
61+ /// use rp2040_hal::clocks::init_clocks_and_plls;
62+ /// let clocks = init_clocks_and_plls(...);
63+ /// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...);
64+ ///
65+ /// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
66+ /// let mut ws = Ws2812Direct::<_, _, _, smart_leds::RGBA8>::new(
67+ /// pins.gpio4.into_mode(),
68+ /// &mut pio,
69+ /// sm0,
70+ /// clocks.peripheral_clock.freq(),
71+ /// );
72+ ///
73+ /// // Then you will make sure yourself to not write too frequently:
74+ /// loop {
75+ /// use smart_leds::{SmartLedsWrite, RGBA8};
76+ /// let color : RGBA8 = (255, 0, 255, 127).into();
77+ ///
78+ /// ws.write([color].iter().copied()).unwrap();
79+ /// delay_for_at_least_60_microseconds();
80+ /// };
81+ ///```
82+ pub struct Ws2812Direct < P , SM , I , CF = smart_leds_trait:: RGB8 >
5883where
5984 I : AnyPin < Function = P :: PinFunction > ,
6085 P : PIOExt ,
6186 SM : StateMachineIndex ,
6287{
6388 tx : Tx < ( P , SM ) > ,
6489 _pin : I ,
90+ _color_format : PhantomData < CF > ,
6591}
6692
67- impl < P , SM , I > Ws2812Direct < P , SM , I >
93+ impl < P , SM , I , CF > Ws2812Direct < P , SM , I , CF >
6894where
6995 I : AnyPin < Function = P :: PinFunction > ,
7096 P : PIOExt ,
7197 SM : StateMachineIndex ,
98+ CF : ColorFormat ,
7299{
73100 /// Creates a new instance of this driver.
74101 pub fn new (
@@ -134,7 +161,7 @@ where
134161 // OSR config
135162 . out_shift_direction ( rp2040_hal:: pio:: ShiftDirection :: Left )
136163 . autopull ( true )
137- . pull_threshold ( 24 )
164+ . pull_threshold ( < CF as ColorFormat > :: COLOR_BYTES . num_bits ( ) )
138165 . clock_divisor_fixed_point ( int, frac)
139166 . build ( sm) ;
140167
@@ -146,17 +173,63 @@ where
146173 Self {
147174 tx,
148175 _pin : I :: from ( pin) ,
176+ _color_format : PhantomData ,
149177 }
150178 }
151179}
152180
153- impl < P , SM , I > SmartLedsWrite for Ws2812Direct < P , SM , I >
181+ /// Specify whether to use 3 or 4 bytes per led color.
182+ pub enum ColorBytes {
183+ ThreeBytes ,
184+ FourBytes ,
185+ }
186+
187+ impl ColorBytes {
188+ const fn num_bits ( & self ) -> u8 {
189+ match self {
190+ ColorBytes :: ThreeBytes => 24 ,
191+ ColorBytes :: FourBytes => 32 ,
192+ }
193+ }
194+ }
195+
196+ /// Implement this trait to support a user-defined color format.
197+ ///
198+ /// smart_leds::RGB8 and smart_leds::RGBA are implemented by the ws2812-pio
199+ /// crate.
200+ pub trait ColorFormat {
201+ /// Select the number of bytes per led.
202+ const COLOR_BYTES : ColorBytes ;
203+
204+ /// Map the color to a 32-bit word.
205+ fn to_word ( self ) -> u32 ;
206+ }
207+
208+ impl ColorFormat for smart_leds_trait:: RGB8 {
209+ const COLOR_BYTES : ColorBytes = ColorBytes :: ThreeBytes ;
210+ fn to_word ( self ) -> u32 {
211+ ( u32:: from ( self . g ) << 24 ) | ( u32:: from ( self . r ) << 16 ) | ( u32:: from ( self . b ) << 8 )
212+ }
213+ }
214+
215+ impl ColorFormat for smart_leds_trait:: RGBA < u8 > {
216+ const COLOR_BYTES : ColorBytes = ColorBytes :: FourBytes ;
217+ fn to_word ( self ) -> u32 {
218+ ( u32:: from ( self . g ) << 24 )
219+ | ( u32:: from ( self . r ) << 16 )
220+ | ( u32:: from ( self . b ) << 8 )
221+ | ( u32:: from ( self . a ) )
222+ }
223+ }
224+
225+ impl < P , SM , I , CF > SmartLedsWrite for Ws2812Direct < P , SM , I , CF >
154226where
155227 I : AnyPin < Function = P :: PinFunction > ,
156228 P : PIOExt ,
157229 SM : StateMachineIndex ,
230+ CF : ColorFormat ,
158231{
159- type Color = smart_leds_trait :: RGB8 ;
232+ type Color = CF ;
160233 type Error = ( ) ;
161234 /// If you call this function, be advised that you will have to wait
162235 /// at least 60 microseconds between calls of this function!
@@ -172,8 +245,7 @@ where
172245 {
173246 for item in iterator {
174247 let color: Self :: Color = item. into ( ) ;
175- let word =
176- ( u32:: from ( color. g ) << 24 ) | ( u32:: from ( color. r ) << 16 ) | ( u32:: from ( color. b ) << 8 ) ;
248+ let word = color. to_word ( ) ;
177249
178250 while !self . tx . write ( word) {
179251 cortex_m:: asm:: nop ( ) ;
@@ -237,23 +309,51 @@ where
237309/// // Do other stuff here...
238310/// };
239311///```
240- pub struct Ws2812 < P , SM , C , I >
312+ ///
313+ /// Typical RGBW usage example:
314+ ///```ignore
315+ /// use rp2040_hal::clocks::init_clocks_and_plls;
316+ /// let clocks = init_clocks_and_plls(...);
317+ /// let pins = rp2040_hal::gpio::pin::bank0::Pins::new(...);
318+ ///
319+ /// let timer = Timer::new(pac.TIMER, &mut pac.RESETS);
320+ ///
321+ /// let (mut pio, sm0, _, _, _) = pac.PIO0.split(&mut pac.RESETS);
322+ /// let mut ws = Ws2812::<_, _, _, _, smart_leds::RGBA8>::new(
323+ /// pins.gpio4.into_mode(),
324+ /// &mut pio,
325+ /// sm0,
326+ /// clocks.peripheral_clock.freq(),
327+ /// timer.count_down(),
328+ /// );
329+ ///
330+ /// loop {
331+ /// use smart_leds::{SmartLedsWrite, RGBA8};
332+ /// let color : RGBA8 = (255, 0, 255, 127).into();
333+ ///
334+ /// ws.write([color].iter().copied()).unwrap();
335+ ///
336+ /// // Do other stuff here...
337+ /// };
338+ ///```
339+ pub struct Ws2812 < P , SM , C , I , CF = smart_leds_trait:: RGB8 >
241340where
242341 C : CountDown ,
243342 I : AnyPin < Function = P :: PinFunction > ,
244343 P : PIOExt ,
245344 SM : StateMachineIndex ,
246345{
247- driver : Ws2812Direct < P , SM , I > ,
346+ driver : Ws2812Direct < P , SM , I , CF > ,
248347 cd : C ,
249348}
250349
251- impl < P , SM , C , I > Ws2812 < P , SM , C , I >
350+ impl < P , SM , C , I , CF > Ws2812 < P , SM , C , I , CF >
252351where
253352 C : CountDown ,
254353 I : AnyPin < Function = P :: PinFunction > ,
255354 P : PIOExt ,
256355 SM : StateMachineIndex ,
356+ CF : ColorFormat ,
257357{
258358 /// Creates a new instance of this driver.
259359 pub fn new (
@@ -262,22 +362,23 @@ where
262362 sm : UninitStateMachine < ( P , SM ) > ,
263363 clock_freq : fugit:: HertzU32 ,
264364 cd : C ,
265- ) -> Ws2812 < P , SM , C , I > {
365+ ) -> Ws2812 < P , SM , C , I , CF > {
266366 let driver = Ws2812Direct :: new ( pin, pio, sm, clock_freq) ;
267367
268368 Self { driver, cd }
269369 }
270370}
271371
272- impl < P , SM , I , C > SmartLedsWrite for Ws2812 < P , SM , C , I >
372+ impl < P , SM , I , C , CF > SmartLedsWrite for Ws2812 < P , SM , C , I , CF >
273373where
274374 C : CountDown ,
275375 C :: Time : From < MicrosDurationU32 > ,
276376 I : AnyPin < Function = P :: PinFunction > ,
277377 P : PIOExt ,
278378 SM : StateMachineIndex ,
379+ CF : ColorFormat ,
279380{
280- type Color = smart_leds_trait :: RGB8 ;
381+ type Color = CF ;
281382 type Error = ( ) ;
282383 fn write < T , J > ( & mut self , iterator : T ) -> Result < ( ) , ( ) >
283384 where
0 commit comments