aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Williams <[email protected]>2025-10-26 21:33:05 +0000
committerRobert Williams <[email protected]>2025-11-03 21:37:09 +0000
commit2546d26cf2748a37b74aac4dbdab3ff4df460cc1 (patch)
treebf6e77b49e4eb6c0fc9e87e2396b9d6c551c3f7a
parent345efc383fa9afabaf23b629f0937855ea4c754f (diff)
embassy-rp: add color order to ws2812 pio program
-rw-r--r--embassy-rp/src/pio_programs/ws2812.rs93
1 files changed, 78 insertions, 15 deletions
diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs
index e6851b1a6..3c16367e6 100644
--- a/embassy-rp/src/pio_programs/ws2812.rs
+++ b/embassy-rp/src/pio_programs/ws2812.rs
@@ -1,21 +1,67 @@
1//! [ws2812](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) 1//! [ws2812](https://www.sparkfun.com/categories/tags/ws2812)
2 2
3use embassy_time::Timer; 3use embassy_time::Timer;
4use fixed::types::U24F8; 4use fixed::types::U24F8;
5use smart_leds::{RGB8, RGBW}; 5use smart_leds::{RGB8, RGBW};
6 6
7use crate::Peri;
8use crate::clocks::clk_sys_freq; 7use crate::clocks::clk_sys_freq;
9use crate::dma::{AnyChannel, Channel}; 8use crate::dma::{AnyChannel, Channel};
10use crate::pio::{ 9use crate::pio::{
11 Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, 10 Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine,
12}; 11};
12use crate::Peri;
13 13
14const T1: u8 = 2; // start bit 14const T1: u8 = 2; // start bit
15const T2: u8 = 5; // data bit 15const T2: u8 = 5; // data bit
16const T3: u8 = 3; // stop bit 16const T3: u8 = 3; // stop bit
17const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; 17const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
18 18
19/// This trait defines the contract for color ordering
20pub trait ColorOrder {
21 type ColorType;
22
23 // Pack the type specific struct into a u32 word in the correct order
24 fn pack(color: Self::ColorType) -> u32;
25}
26
27/// Color orders for WS2812B, type RGB8
28/// Green, Red, Blue order is the common default for WS2812B
29pub struct Grb;
30impl ColorOrder for Grb {
31 type ColorType = RGB8;
32 fn pack(color: Self::ColorType) -> u32 {
33 (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8)
34 }
35}
36
37/// Red, Green, Blue is used by some WS2812B implementations
38pub struct Rgb;
39impl ColorOrder for Rgb {
40 type ColorType = RGB8;
41 fn pack(color: Self::ColorType) -> u32 {
42 (u32::from(color.r) << 24) | (u32::from(color.g) << 16) | (u32::from(color.b) << 8)
43 }
44}
45
46/// Color orders RGBW strips
47/// Green, Red, Blue, White order is the common default for RGBW strips
48pub struct Grbw;
49impl ColorOrder for Grbw {
50 type ColorType = RGBW<u8>;
51 fn pack(color: Self::ColorType) -> u32 {
52 (u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8) | u32::from(color.a.0)
53 }
54}
55
56/// Red, Green, Blue, White order
57pub struct Rgbw;
58impl ColorOrder for Rgbw {
59 type ColorType = RGBW<u8>;
60 fn pack(color: Self::ColorType) -> u32 {
61 (u32::from(color.r) << 24) | (u32::from(color.g) << 16) | (u32::from(color.b) << 8) | u32::from(color.a.0)
62 }
63}
64
19/// This struct represents a ws2812 program loaded into pio instruction memory. 65/// This struct represents a ws2812 program loaded into pio instruction memory.
20pub struct PioWs2812Program<'a, PIO: Instance> { 66pub struct PioWs2812Program<'a, PIO: Instance> {
21 prg: LoadedProgram<'a, PIO>, 67 prg: LoadedProgram<'a, PIO>,
@@ -52,12 +98,19 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> {
52 98
53/// Pio backed RGB ws2812 driver 99/// Pio backed RGB ws2812 driver
54/// Const N is the number of ws2812 leds attached to this pin 100/// Const N is the number of ws2812 leds attached to this pin
55pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { 101pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER = Grb>
102where
103 ORDER: ColorOrder<ColorType = RGB8>,
104{
56 dma: Peri<'d, AnyChannel>, 105 dma: Peri<'d, AnyChannel>,
57 sm: StateMachine<'d, P, S>, 106 sm: StateMachine<'d, P, S>,
107 _order: core::marker::PhantomData<ORDER>,
58} 108}
59 109
60impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { 110impl<'d, P: Instance, const S: usize, const N: usize, ORDER = Grb> PioWs2812<'d, P, S, N, ORDER>
111where
112 ORDER: ColorOrder<ColorType = RGB8>,
113{
61 /// Configure a pio state machine to use the loaded ws2812 program. 114 /// Configure a pio state machine to use the loaded ws2812 program.
62 pub fn new( 115 pub fn new(
63 pio: &mut Common<'d, P>, 116 pio: &mut Common<'d, P>,
@@ -93,7 +146,11 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
93 sm.set_config(&cfg); 146 sm.set_config(&cfg);
94 sm.set_enable(true); 147 sm.set_enable(true);
95 148
96 Self { dma: dma.into(), sm } 149 Self {
150 dma: dma.into(),
151 sm,
152 _order: core::marker::PhantomData,
153 }
97 } 154 }
98 155
99 /// Write a buffer of [smart_leds::RGB8] to the ws2812 string 156 /// Write a buffer of [smart_leds::RGB8] to the ws2812 string
@@ -101,8 +158,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
101 // Precompute the word bytes from the colors 158 // Precompute the word bytes from the colors
102 let mut words = [0u32; N]; 159 let mut words = [0u32; N];
103 for i in 0..N { 160 for i in 0..N {
104 let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); 161 words[i] = ORDER::pack(colors[i]);
105 words[i] = word;
106 } 162 }
107 163
108 // DMA transfer 164 // DMA transfer
@@ -115,12 +171,19 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
115/// Pio backed RGBW ws2812 driver 171/// Pio backed RGBW ws2812 driver
116/// This version is intended for ws2812 leds with 4 addressable lights 172/// This version is intended for ws2812 leds with 4 addressable lights
117/// Const N is the number of ws2812 leds attached to this pin 173/// Const N is the number of ws2812 leds attached to this pin
118pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize> { 174pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER = Grbw>
175where
176 ORDER: ColorOrder<ColorType = RGBW<u8>>,
177{
119 dma: Peri<'d, AnyChannel>, 178 dma: Peri<'d, AnyChannel>,
120 sm: StateMachine<'d, P, S>, 179 sm: StateMachine<'d, P, S>,
180 _order: core::marker::PhantomData<ORDER>,
121} 181}
122 182
123impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> { 183impl<'d, P: Instance, const S: usize, const N: usize, ORDER = Grbw> RgbwPioWs2812<'d, P, S, N, ORDER>
184where
185 ORDER: ColorOrder<ColorType = RGBW<u8>>,
186{
124 /// Configure a pio state machine to use the loaded ws2812 program. 187 /// Configure a pio state machine to use the loaded ws2812 program.
125 pub fn new( 188 pub fn new(
126 pio: &mut Common<'d, P>, 189 pio: &mut Common<'d, P>,
@@ -156,7 +219,11 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N>
156 sm.set_config(&cfg); 219 sm.set_config(&cfg);
157 sm.set_enable(true); 220 sm.set_enable(true);
158 221
159 Self { dma: dma.into(), sm } 222 Self {
223 dma: dma.into(),
224 sm,
225 _order: core::marker::PhantomData,
226 }
160 } 227 }
161 228
162 /// Write a buffer of [smart_leds::RGBW] to the ws2812 string 229 /// Write a buffer of [smart_leds::RGBW] to the ws2812 string
@@ -164,11 +231,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N>
164 // Precompute the word bytes from the colors 231 // Precompute the word bytes from the colors
165 let mut words = [0u32; N]; 232 let mut words = [0u32; N];
166 for i in 0..N { 233 for i in 0..N {
167 let word = (u32::from(colors[i].g) << 24) 234 words[i] = ORDER::pack(colors[i]);
168 | (u32::from(colors[i].r) << 16)
169 | (u32::from(colors[i].b) << 8)
170 | u32::from(colors[i].a.0);
171 words[i] = word;
172 } 235 }
173 236
174 // DMA transfer 237 // DMA transfer