aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/pio_programs/ws2812.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-rp/src/pio_programs/ws2812.rs')
-rw-r--r--embassy-rp/src/pio_programs/ws2812.rs125
1 files changed, 110 insertions, 15 deletions
diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs
index 37dd1c4e0..0b6035316 100644
--- a/embassy-rp/src/pio_programs/ws2812.rs
+++ b/embassy-rp/src/pio_programs/ws2812.rs
@@ -1,21 +1,69 @@
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;
7use crate::clocks::clk_sys_freq; 8use crate::clocks::clk_sys_freq;
8use crate::dma::{AnyChannel, Channel}; 9use crate::dma::{AnyChannel, Channel};
9use crate::pio::{ 10use crate::pio::{
10 Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine, 11 Common, Config, FifoJoin, Instance, LoadedProgram, PioPin, ShiftConfig, ShiftDirection, StateMachine,
11}; 12};
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/// Color orders for WS2812B, type RGB8
20pub 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
26pub struct Grb;
27impl 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
35pub struct Rgb;
36impl 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
44pub 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
50pub struct Grbw;
51impl 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
59pub struct Rgbw;
60impl 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.
20pub struct PioWs2812Program<'a, PIO: Instance> { 68pub 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
55pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { 103pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER>
104where
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
60impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { 112impl<'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
126impl<'d, P: Instance, const S: usize, const N: usize, ORDER> PioWs2812<'d, P, S, N, ORDER>
127where
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
118pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize> { 191pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize, ORDER>
192where
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
123impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> { 200impl<'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
214impl<'d, P: Instance, const S: usize, const N: usize, ORDER> RgbwPioWs2812<'d, P, S, N, ORDER>
215where
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