mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-10-02 14:44:32 +00:00
Merge pull request #4236 from MatrixSenpai/ws2812-rgbw-pio
Support RGBW on PioWs2812
This commit is contained in:
commit
f73a390bc8
@ -2,7 +2,7 @@
|
||||
|
||||
use embassy_time::Timer;
|
||||
use fixed::types::U24F8;
|
||||
use smart_leds::RGB8;
|
||||
use smart_leds::{RGB8, RGBW};
|
||||
|
||||
use crate::clocks::clk_sys_freq;
|
||||
use crate::dma::{AnyChannel, Channel};
|
||||
@ -50,7 +50,7 @@ impl<'a, PIO: Instance> PioWs2812Program<'a, PIO> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pio backed ws2812 driver
|
||||
/// Pio backed RGB ws2812 driver
|
||||
/// Const N is the number of ws2812 leds attached to this pin
|
||||
pub struct PioWs2812<'d, P: Instance, const S: usize, const N: usize> {
|
||||
dma: Peri<'d, AnyChannel>,
|
||||
@ -111,3 +111,69 @@ impl<'d, P: Instance, const S: usize, const N: usize> PioWs2812<'d, P, S, N> {
|
||||
Timer::after_micros(55).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Pio backed RGBW ws2812 driver
|
||||
/// This version is intended for ws2812 leds with 4 addressable lights
|
||||
/// Const N is the number of ws2812 leds attached to this pin
|
||||
pub struct RgbwPioWs2812<'d, P: Instance, const S: usize, const N: usize> {
|
||||
dma: Peri<'d, AnyChannel>,
|
||||
sm: StateMachine<'d, P, S>,
|
||||
}
|
||||
|
||||
impl<'d, P: Instance, const S: usize, const N: usize> RgbwPioWs2812<'d, P, S, N> {
|
||||
/// Configure a pio state machine to use the loaded ws2812 program.
|
||||
pub fn new(
|
||||
pio: &mut Common<'d, P>,
|
||||
mut sm: StateMachine<'d, P, S>,
|
||||
dma: Peri<'d, impl Channel>,
|
||||
pin: Peri<'d, impl PioPin>,
|
||||
program: &PioWs2812Program<'d, P>,
|
||||
) -> Self {
|
||||
// Setup sm0
|
||||
let mut cfg = Config::default();
|
||||
|
||||
// Pin config
|
||||
let out_pin = pio.make_pio_pin(pin);
|
||||
cfg.set_out_pins(&[&out_pin]);
|
||||
cfg.set_set_pins(&[&out_pin]);
|
||||
|
||||
cfg.use_program(&program.prg, &[&out_pin]);
|
||||
|
||||
// Clock config, measured in kHz to avoid overflows
|
||||
let clock_freq = U24F8::from_num(clk_sys_freq() / 1000);
|
||||
let ws2812_freq = U24F8::from_num(800);
|
||||
let bit_freq = ws2812_freq * CYCLES_PER_BIT;
|
||||
cfg.clock_divider = clock_freq / bit_freq;
|
||||
|
||||
// FIFO config
|
||||
cfg.fifo_join = FifoJoin::TxOnly;
|
||||
cfg.shift_out = ShiftConfig {
|
||||
auto_fill: true,
|
||||
threshold: 32,
|
||||
direction: ShiftDirection::Left,
|
||||
};
|
||||
|
||||
sm.set_config(&cfg);
|
||||
sm.set_enable(true);
|
||||
|
||||
Self { dma: dma.into(), sm }
|
||||
}
|
||||
|
||||
/// Write a buffer of [smart_leds::RGBW] to the ws2812 string
|
||||
pub async fn write(&mut self, colors: &[RGBW<u8>; N]) {
|
||||
// Precompute the word bytes from the colors
|
||||
let mut words = [0u32; N];
|
||||
for i in 0..N {
|
||||
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);
|
||||
words[i] = word;
|
||||
}
|
||||
|
||||
// DMA transfer
|
||||
self.sm.tx().dma_push(self.dma.reborrow(), &words, false).await;
|
||||
|
||||
Timer::after_micros(55).await;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user