diff options
| author | Ulf Lilleengen <[email protected]> | 2025-11-04 07:19:58 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-11-04 07:19:58 +0000 |
| commit | e8768384b45b30b7165dfdc7369f60ae7669f45a (patch) | |
| tree | 4ea7c2f19e7f52865754351483917b04c28ec299 | |
| parent | a60768c63826e1ce266891e06a02aba5993a040e (diff) | |
| parent | f5a7d581da5ff631802cc1fab4265b402f4ef9cf (diff) | |
Merge pull request #4805 from bobdoah/main
embassy-rp: Add support for color order to Pio::Ws2812
| -rw-r--r-- | embassy-rp/CHANGELOG.md | 1 | ||||
| -rw-r--r-- | embassy-rp/src/pio_programs/ws2812.rs | 123 |
2 files changed, 110 insertions, 14 deletions
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md index 4fab20f08..3b3cb5351 100644 --- a/embassy-rp/CHANGELOG.md +++ b/embassy-rp/CHANGELOG.md | |||
| @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |||
| 16 | - rp235x: use msplim for stack guard instead of MPU | 16 | - rp235x: use msplim for stack guard instead of MPU |
| 17 | - Add reset_to_usb_boot for rp235x ([#4705](https://github.com/embassy-rs/embassy/pull/4705)) | 17 | - Add reset_to_usb_boot for rp235x ([#4705](https://github.com/embassy-rs/embassy/pull/4705)) |
| 18 | - 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)) | 18 | - 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 | ||
| 19 | 20 | ||
| 20 | ## 0.8.0 - 2025-08-26 | 21 | ## 0.8.0 - 2025-08-26 |
| 21 | 22 | ||
diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs index e6851b1a6..0b6035316 100644 --- a/embassy-rp/src/pio_programs/ws2812.rs +++ b/embassy-rp/src/pio_programs/ws2812.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | //! [ws2812](https://www.sparkfun.com/datasheets/LCD/HD44780.pdf) | 1 | //! [ws2812](https://www.sparkfun.com/categories/tags/ws2812) |
| 2 | 2 | ||
| 3 | use embassy_time::Timer; | 3 | use embassy_time::Timer; |
| 4 | use fixed::types::U24F8; | 4 | use fixed::types::U24F8; |
| @@ -16,6 +16,54 @@ const T2: u8 = 5; // data bit | |||
| 16 | const T3: u8 = 3; // stop bit | 16 | const T3: u8 = 3; // stop bit |
| 17 | const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; | 17 | const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; |
| 18 | 18 | ||
| 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 | |||
| 19 | /// This struct represents a ws2812 program loaded into pio instruction memory. | 67 | /// This struct represents a ws2812 program loaded into pio instruction memory. |
| 20 | pub struct PioWs2812Program<'a, PIO: Instance> { | 68 | pub struct PioWs2812Program<'a, PIO: Instance> { |
| 21 | prg: LoadedProgram<'a, PIO>, | 69 | prg: LoadedProgram<'a, PIO>, |
| @@ -52,15 +100,37 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> { | |||
| 52 | 100 | ||
| 53 | /// Pio backed RGB ws2812 driver | 101 | /// Pio backed RGB ws2812 driver |
| 54 | /// Const N is the number of ws2812 leds attached to this pin | 102 | /// 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 | { | ||
| 56 | dma: Peri<'d, AnyChannel>, | 107 | dma: Peri<'d, AnyChannel>, |
| 57 | sm: StateMachine<'d, P, S>, | 108 | sm: StateMachine<'d, P, S>, |
| 109 | _order: core::marker::PhantomData<ORDER>, | ||
| 58 | } | 110 | } |
| 59 | 111 | ||
| 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> { |
| 61 | /// Configure a pio state machine to use the loaded ws2812 program. | 113 | /// Configure a pio state machine to use the loaded ws2812 program. |
| 114 | /// Uses the default GRB order. | ||
| 62 | pub fn new( | 115 | pub fn new( |
| 63 | pio: &mut Common<'d, P>, | 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( | ||
| 133 | pio: &mut Common<'d, P>, | ||
| 64 | mut sm: StateMachine<'d, P, S>, | 134 | mut sm: StateMachine<'d, P, S>, |
| 65 | dma: Peri<'d, impl Channel>, | 135 | dma: Peri<'d, impl Channel>, |
| 66 | pin: Peri<'d, impl PioPin>, | 136 | pin: Peri<'d, impl PioPin>, |
| @@ -93,7 +163,11 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { | |||
| 93 | sm.set_config(&cfg); | 163 | sm.set_config(&cfg); |
| 94 | sm.set_enable(true); | 164 | sm.set_enable(true); |
| 95 | 165 | ||
| 96 | Self { dma: dma.into(), sm } | 166 | Self { |
| 167 | dma: dma.into(), | ||
| 168 | sm, | ||
| 169 | _order: core::marker::PhantomData, | ||
| 170 | } | ||
| 97 | } | 171 | } |
| 98 | 172 | ||
| 99 | /// Write a buffer of [smart_leds::RGB8] to the ws2812 string | 173 | /// Write a buffer of [smart_leds::RGB8] to the ws2812 string |
| @@ -101,8 +175,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { | |||
| 101 | // Precompute the word bytes from the colors | 175 | // Precompute the word bytes from the colors |
| 102 | let mut words = [0u32; N]; | 176 | let mut words = [0u32; N]; |
| 103 | for i in 0..N { | 177 | 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); | 178 | words[i] = ORDER::pack(colors[i]); |
| 105 | words[i] = word; | ||
| 106 | } | 179 | } |
| 107 | 180 | ||
| 108 | // DMA transfer | 181 | // DMA transfer |
| @@ -115,15 +188,37 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { | |||
| 115 | /// Pio backed RGBW ws2812 driver | 188 | /// Pio backed RGBW ws2812 driver |
| 116 | /// This version is intended for ws2812 leds with 4 addressable lights | 189 | /// This version is intended for ws2812 leds with 4 addressable lights |
| 117 | /// Const N is the number of ws2812 leds attached to this pin | 190 | /// 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 | { | ||
| 119 | dma: Peri<'d, AnyChannel>, | 195 | dma: Peri<'d, AnyChannel>, |
| 120 | sm: StateMachine<'d, P, S>, | 196 | sm: StateMachine<'d, P, S>, |
| 197 | _order: core::marker::PhantomData<ORDER>, | ||
| 121 | } | 198 | } |
| 122 | 199 | ||
| 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> { |
| 124 | /// Configure a pio state machine to use the loaded ws2812 program. | 201 | /// Configure a pio state machine to use the loaded ws2812 program. |
| 202 | /// Uses the default GRBW color order | ||
| 125 | pub fn new( | 203 | pub fn new( |
| 126 | pio: &mut Common<'d, P>, | 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( | ||
| 221 | pio: &mut Common<'d, P>, | ||
| 127 | mut sm: StateMachine<'d, P, S>, | 222 | mut sm: StateMachine<'d, P, S>, |
| 128 | dma: Peri<'d, impl Channel>, | 223 | dma: Peri<'d, impl Channel>, |
| 129 | pin: Peri<'d, impl PioPin>, | 224 | pin: Peri<'d, impl PioPin>, |
| @@ -156,7 +251,11 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> | |||
| 156 | sm.set_config(&cfg); | 251 | sm.set_config(&cfg); |
| 157 | sm.set_enable(true); | 252 | sm.set_enable(true); |
| 158 | 253 | ||
| 159 | Self { dma: dma.into(), sm } | 254 | Self { |
| 255 | dma: dma.into(), | ||
| 256 | sm, | ||
| 257 | _order: core::marker::PhantomData, | ||
| 258 | } | ||
| 160 | } | 259 | } |
| 161 | 260 | ||
| 162 | /// Write a buffer of [smart_leds::RGBW] to the ws2812 string | 261 | /// Write a buffer of [smart_leds::RGBW] to the ws2812 string |
| @@ -164,11 +263,7 @@ impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> | |||
| 164 | // Precompute the word bytes from the colors | 263 | // Precompute the word bytes from the colors |
| 165 | let mut words = [0u32; N]; | 264 | let mut words = [0u32; N]; |
| 166 | for i in 0..N { | 265 | for i in 0..N { |
| 167 | let word = (u32::from(colors[i].g) << 24) | 266 | 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 | } | 267 | } |
| 173 | 268 | ||
| 174 | // DMA transfer | 269 | // DMA transfer |
