rktk_drivers_nrf/rgb/
ws2812_pwm.rs1use core::convert::Infallible;
5
6use bitvec::prelude::*;
7use embassy_nrf::{
8 Peri,
9 gpio::{OutputDrive, Pin},
10 pwm::{
11 Config, Instance, Prescaler, SequenceLoad, SequencePwm, SingleSequenceMode, SingleSequencer,
12 },
13};
14use embassy_time::Timer;
15use rktk::drivers::interface::rgb::{LedRgb, RgbDriver};
16
17pub struct Ws2812Pwm<const BUFFER_SIZE: usize, PWM: Instance, DATA: Pin> {
25 pwm: Peri<'static, PWM>,
26 pin: Peri<'static, DATA>,
27}
28
29const T1H: u16 = 0x8000 | 13;
30const T0H: u16 = 0x8000 | 7;
31const RES: u16 = 0x8000;
32
33impl<const BUFFER_SIZE: usize, PWM: Instance + 'static, DATA: Pin>
34 Ws2812Pwm<BUFFER_SIZE, PWM, DATA>
35{
36 pub fn new(pwm: Peri<'static, PWM>, data: Peri<'static, DATA>) -> Self {
37 Self { pwm, pin: data }
38 }
39}
40
41impl<const BUFFER_SIZE: usize, PWM: Instance + 'static, DATA: Pin> RgbDriver
42 for Ws2812Pwm<BUFFER_SIZE, PWM, DATA>
43{
44 type Error = Infallible;
45
46 async fn write<I: IntoIterator<Item = LedRgb<u8>>>(
47 &mut self,
48 pixels: I,
49 ) -> Result<(), Self::Error> {
50 let mut pwm_config = Config::default();
51 pwm_config.sequence_load = SequenceLoad::Common;
52 pwm_config.prescaler = Prescaler::Div1; pwm_config.max_duty = 20; pwm_config.ch0_drive = OutputDrive::HighDrive;
55 let Ok(mut seq_pwm) =
56 SequencePwm::new_1ch(self.pwm.reborrow(), self.pin.reborrow(), pwm_config)
57 else {
58 return Ok(());
60 };
61
62 let mut words = heapless::Vec::<u16, BUFFER_SIZE>::from_slice(&[RES; 100]).unwrap();
63
64 'outer: for color in pixels {
65 for bit in color[1]
66 .view_bits::<Msb0>()
67 .iter()
68 .chain(color[0].view_bits())
69 .chain(color[2].view_bits())
70 {
71 if words.push(if *bit { T1H } else { T0H }).is_err() {
72 rktk_log::warn!("WS2812Pwm buffer size is not enough. Increase BUFFER_SIZE.");
73 break 'outer;
74 }
75 }
76 }
77
78 let seq_config = embassy_nrf::pwm::SequenceConfig::default();
79 let sequencer = SingleSequencer::new(&mut seq_pwm, words.as_slice(), seq_config);
80 let _ = sequencer.start(SingleSequenceMode::Times(1));
81
82 Timer::after_millis(5).await;
85
86 Ok(())
87 }
88}