aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-05-27 06:24:03 +0000
committerGitHub <[email protected]>2025-05-27 06:24:03 +0000
commitf73a390bc895f196b0f1f6ab05a8890cb84cd693 (patch)
treed1ab90704427eac773848a0a42fa9189062e9f1a
parent4a63a2a16c11f3a3a16522c599e072c23c85ebe8 (diff)
parent7eaea84fb769f739f884bc0a474b518b65c126e4 (diff)
Merge pull request #4236 from MatrixSenpai/ws2812-rgbw-pio
Support RGBW on PioWs2812
-rw-r--r--embassy-rp/src/pio_programs/ws2812.rs70
1 files changed, 68 insertions, 2 deletions
diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs
index 578937e11..37dd1c4e0 100644
--- a/embassy-rp/src/pio_programs/ws2812.rs
+++ b/embassy-rp/src/pio_programs/ws2812.rs
@@ -2,7 +2,7 @@
2 2
3use embassy_time::Timer; 3use embassy_time::Timer;
4use fixed::types::U24F8; 4use fixed::types::U24F8;
5use smart_leds::RGB8; 5use smart_leds::{RGB8, RGBW};
6 6
7use crate::clocks::clk_sys_freq; 7use crate::clocks::clk_sys_freq;
8use crate::dma::{AnyChannel, Channel}; 8use crate::dma::{AnyChannel, Channel};
@@ -50,7 +50,7 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> {
50 } 50 }
51} 51}
52 52
53/// Pio backed ws2812 driver 53/// Pio backed RGB ws2812 driver
54/// Const N is the number of ws2812 leds attached to this pin 54/// Const N is the number of ws2812 leds attached to this pin
55pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> { 55pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> {
56 dma: Peri<'d, AnyChannel>, 56 dma: Peri<'d, AnyChannel>,
@@ -111,3 +111,69 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
111 Timer::after_micros(55).await; 111 Timer::after_micros(55).await;
112 } 112 }
113} 113}
114
115/// Pio backed RGBW ws2812 driver
116/// This version is intended for ws2812 leds with 4 addressable lights
117/// Const N is the number of ws2812 leds attached to this pin
118pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize> {
119 dma: Peri<'d, AnyChannel>,
120 sm: StateMachine<'d, P, S>,
121}
122
123impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> {
124 /// Configure a pio state machine to use the loaded ws2812 program.
125 pub fn new(
126 pio: &mut Common<'d, P>,
127 mut sm: StateMachine<'d, P, S>,
128 dma: Peri<'d, impl Channel>,
129 pin: Peri<'d, impl PioPin>,
130 program: &PioWs2812Program<'d, P>,
131 ) -> Self {
132 // Setup sm0
133 let mut cfg = Config::default();
134
135 // Pin config
136 let out_pin = pio.make_pio_pin(pin);
137 cfg.set_out_pins(&[&out_pin]);
138 cfg.set_set_pins(&[&out_pin]);
139
140 cfg.use_program(&program.prg, &[&out_pin]);
141
142 // Clock config, measured in kHz to avoid overflows
143 let clock_freq = U24F8::from_num(clk_sys_freq() / 1000);
144 let ws2812_freq = U24F8::from_num(800);
145 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
146 cfg.clock_divider = clock_freq / bit_freq;
147
148 // FIFO config
149 cfg.fifo_join = FifoJoin::TxOnly;
150 cfg.shift_out = ShiftConfig {
151 auto_fill: true,
152 threshold: 32,
153 direction: ShiftDirection::Left,
154 };
155
156 sm.set_config(&cfg);
157 sm.set_enable(true);
158
159 Self { dma: dma.into(), sm }
160 }
161
162 /// Write a buffer of [smart_leds::RGBW] to the ws2812 string
163 pub async fn write(&mut self, colors: &[RGBW<u8>; N]) {
164 // Precompute the word bytes from the colors
165 let mut words = [0u32; N];
166 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;
172 }
173
174 // DMA transfer
175 self.sm.tx().dma_push(self.dma.reborrow(), &words, false).await;
176
177 Timer::after_micros(55).await;
178 }
179}