Skip to content

Commit e876838

Browse files
authored
Merge pull request #4805 from bobdoah/main
embassy-rp: Add support for color order to Pio::Ws2812
2 parents a60768c + f5a7d58 commit e876838

File tree

2 files changed

+110
-14
lines changed

2 files changed

+110
-14
lines changed

embassy-rp/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- rp235x: use msplim for stack guard instead of MPU
1717
- Add reset_to_usb_boot for rp235x ([#4705](https://github.com/embassy-rs/embassy/pull/4705))
1818
- Add fix #4822 in PIO onewire. Change to disable the state machine before setting y register ([#4824](https://github.com/embassy-rs/embassy/pull/4824))
19+
- Add PIO::Ws2812 color order support
1920

2021
## 0.8.0 - 2025-08-26
2122

embassy-rp/src/pio_programs/ws2812.rs

Lines changed: 109 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! [ws2812](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf)
1+
//! [ws2812](https://www.sparkfun.com/categories/tags/ws2812)
22
33
use embassy_time::Timer;
44
use fixed::types::U24F8;
@@ -16,6 +16,54 @@ const T2: u8 = 5; // data bit
1616
const T3: u8 = 3; // stop bit
1717
const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
1818

19+
/// Color orders for WS2812B, type RGB8
20+
pub trait RgbColorOrder {
21+
/// Pack an 8-bit RGB color into a u32
22+
fn pack(color: RGB8) -> u32;
23+
}
24+
25+
/// Green, Red, Blue order is the common default for WS2812B
26+
pub struct Grb;
27+
impl RgbColorOrder for Grb {
28+
/// Pack an 8-bit RGB color into a u32 in GRB order
29+
fn pack(color: RGB8) -> u32 {
30+
(u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8)
31+
}
32+
}
33+
34+
/// Red, Green, Blue is used by some WS2812B implementations
35+
pub struct Rgb;
36+
impl RgbColorOrder for Rgb {
37+
/// Pack an 8-bit RGB color into a u32 in RGB order
38+
fn pack(color: RGB8) -> u32 {
39+
(u32::from(color.r) << 24) | (u32::from(color.g) << 16) | (u32::from(color.b) << 8)
40+
}
41+
}
42+
43+
/// Color orders RGBW strips
44+
pub trait RgbwColorOrder {
45+
/// Pack an RGB+W color into a u32
46+
fn pack(color: RGBW<u8>) -> u32;
47+
}
48+
49+
/// Green, Red, Blue, White order is the common default for RGBW strips
50+
pub struct Grbw;
51+
impl RgbwColorOrder for Grbw {
52+
/// Pack an RGB+W color into a u32 in GRBW order
53+
fn pack(color: RGBW<u8>) -> u32 {
54+
(u32::from(color.g) << 24) | (u32::from(color.r) << 16) | (u32::from(color.b) << 8) | u32::from(color.a.0)
55+
}
56+
}
57+
58+
/// Red, Green, Blue, White order
59+
pub struct Rgbw;
60+
impl RgbwColorOrder for Rgbw {
61+
/// Pack an RGB+W color into a u32 in RGBW order
62+
fn pack(color: RGBW<u8>) -> u32 {
63+
(u32::from(color.r) << 24) | (u32::from(color.g) << 16) | (u32::from(color.b) << 8) | u32::from(color.a.0)
64+
}
65+
}
66+
1967
/// This struct represents a ws2812 program loaded into pio instruction memory.
2068
pub struct PioWs2812Program<'a, PIO: Instance> {
2169
prg: LoadedProgram<'a, PIO>,
@@ -52,14 +100,36 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> {
52100

53101
/// Pio backed RGB ws2812 driver
54102
/// Const N is the number of ws2812 leds attached to this pin
55-
pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> {
103+
pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER>
104+
where
105+
ORDER: RgbColorOrder,
106+
{
56107
dma: Peri<'d, AnyChannel>,
57108
sm: StateMachine<'d, P, S>,
109+
_order: core::marker::PhantomData<ORDER>,
58110
}
59111

60-
impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
112+
impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N, Grb> {
61113
/// Configure a pio state machine to use the loaded ws2812 program.
114+
/// Uses the default GRB order.
62115
pub fn new(
116+
pio: &mut Common<'d, P>,
117+
sm: StateMachine<'d, P, S>,
118+
dma: Peri<'d, impl Channel>,
119+
pin: Peri<'d, impl PioPin>,
120+
program: &PioWs2812Program<'d, P>,
121+
) -> Self {
122+
Self::with_color_order(pio, sm, dma, pin, program)
123+
}
124+
}
125+
126+
impl<'d, P: Instance, const S: usize, const N: usize, ORDER> PioWs2812<'d, P, S, N, ORDER>
127+
where
128+
ORDER: RgbColorOrder,
129+
{
130+
/// Configure a pio state machine to use the loaded ws2812 program.
131+
/// Uses the specified color order.
132+
pub fn with_color_order(
63133
pio: &mut Common<'d, P>,
64134
mut sm: StateMachine<'d, P, S>,
65135
dma: Peri<'d, impl Channel>,
@@ -93,16 +163,19 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
93163
sm.set_config(&cfg);
94164
sm.set_enable(true);
95165

96-
Self { dma: dma.into(), sm }
166+
Self {
167+
dma: dma.into(),
168+
sm,
169+
_order: core::marker::PhantomData,
170+
}
97171
}
98172

99173
/// Write a buffer of [smart_leds::RGB8] to the ws2812 string
100174
pub async fn write(&mut self, colors: &[RGB8; N]) {
101175
// Precompute the word bytes from the colors
102176
let mut words = [0u32; N];
103177
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);
105-
words[i] = word;
178+
words[i] = ORDER::pack(colors[i]);
106179
}
107180

108181
// DMA transfer
@@ -115,14 +188,36 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
115188
/// Pio backed RGBW ws2812 driver
116189
/// This version is intended for ws2812 leds with 4 addressable lights
117190
/// Const N is the number of ws2812 leds attached to this pin
118-
pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize> {
191+
pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER>
192+
where
193+
ORDER: RgbwColorOrder,
194+
{
119195
dma: Peri<'d, AnyChannel>,
120196
sm: StateMachine<'d, P, S>,
197+
_order: core::marker::PhantomData<ORDER>,
121198
}
122199

123-
impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> {
200+
impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N, Grbw> {
124201
/// Configure a pio state machine to use the loaded ws2812 program.
202+
/// Uses the default GRBW color order
125203
pub fn new(
204+
pio: &mut Common<'d, P>,
205+
sm: StateMachine<'d, P, S>,
206+
dma: Peri<'d, impl Channel>,
207+
pin: Peri<'d, impl PioPin>,
208+
program: &PioWs2812Program<'d, P>,
209+
) -> Self {
210+
Self::with_color_order(pio, sm, dma, pin, program)
211+
}
212+
}
213+
214+
impl<'d, P: Instance, const S: usize, const N: usize, ORDER> RgbwPioWs2812<'d, P, S, N, ORDER>
215+
where
216+
ORDER: RgbwColorOrder,
217+
{
218+
/// Configure a pio state machine to use the loaded ws2812 program.
219+
/// Uses the specified color order
220+
pub fn with_color_order(
126221
pio: &mut Common<'d, P>,
127222
mut sm: StateMachine<'d, P, S>,
128223
dma: Peri<'d, impl Channel>,
@@ -156,19 +251,19 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N>
156251
sm.set_config(&cfg);
157252
sm.set_enable(true);
158253

159-
Self { dma: dma.into(), sm }
254+
Self {
255+
dma: dma.into(),
256+
sm,
257+
_order: core::marker::PhantomData,
258+
}
160259
}
161260

162261
/// Write a buffer of [smart_leds::RGBW] to the ws2812 string
163262
pub async fn write(&mut self, colors: &[RGBW<u8>; N]) {
164263
// Precompute the word bytes from the colors
165264
let mut words = [0u32; N];
166265
for i in 0..N {
167-
let word = (u32::from(colors[i].g) << 24)
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;
266+
words[i] = ORDER::pack(colors[i]);
172267
}
173268

174269
// DMA transfer

0 commit comments

Comments
 (0)