aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/pio_programs
diff options
context:
space:
mode:
authorMatrixSenpai <[email protected]>2025-05-22 10:54:24 -0500
committerMatrixSenpai <[email protected]>2025-05-22 10:58:09 -0500
commit9baf5fc5eb8b317c7ac86ddd7bdc7434fbe7c26c (patch)
treecbe3ad772ec24ea81aeb47ba6783e53c567f6ef7 /embassy-rp/src/pio_programs
parentedceb0dc7da32848fd31b525b4c247671a14eb2d (diff)
adding compatibility with ws2812 leds that have 4 addressable lights
Diffstat (limited to 'embassy-rp/src/pio_programs')
-rw-r--r--embassy-rp/src/pio_programs/ws2812.rs71
1 files changed, 67 insertions, 4 deletions
diff --git a/embassy-rp/src/pio_programs/ws2812.rs b/embassy-rp/src/pio_programs/ws2812.rs
index 578937e11..f257bfcdc 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,14 +50,14 @@ 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 RgbPioWs2812<'d, P: Instance, const S: usize, const N: usize> {
56 dma: Peri<'d, AnyChannel>, 56 dma: Peri<'d, AnyChannel>,
57 sm: StateMachine<'d, P, S>, 57 sm: StateMachine<'d, P, S>,
58} 58}
59 59
60impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> { 60impl<'d, P: Instance, const S: usize, const N: usize> RgbPioWs2812<'d, P, S, N> {
61 /// Configure a pio state machine to use the loaded ws2812 program. 61 /// Configure a pio state machine to use the loaded ws2812 program.
62 pub fn new( 62 pub fn new(
63 pio: &mut Common<'d, P>, 63 pio: &mut Common<'d, P>,
@@ -111,3 +111,66 @@ 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) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8) | u32::from(colors[i].a.0);
168 words[i] = word;
169 }
170
171 // DMA transfer
172 self.sm.tx().dma_push(self.dma.reborrow(), &words, false).await;
173
174 Timer::after_micros(55).await;
175 }
176}