ws2812_timer_delay/
lib.rs

1//! # Use ws2812 leds with timers
2//!
3//! - For usage with `smart-leds`
4//! - Implements the `SmartLedsWrite` trait
5//!
6//! The `new` method needs a periodic timer running at 3 MHz
7//!
8//! If it's too slow (e.g.  e.g. all/some leds are white or display the wrong color)
9//! you may want to try the `slow` feature.
10
11#![no_std]
12
13use embedded_hal as hal;
14
15use crate::hal::digital::v2::OutputPin;
16use crate::hal::timer::{CountDown, Periodic};
17use smart_leds_trait::{SmartLedsWrite, RGB8};
18
19use nb;
20use nb::block;
21
22pub struct Ws2812<TIMER, PIN> {
23    timer: TIMER,
24    pin: PIN,
25}
26
27impl<TIMER, PIN> Ws2812<TIMER, PIN>
28where
29    TIMER: CountDown + Periodic,
30    PIN: OutputPin,
31{
32    /// The timer has to already run at with a frequency of 3 MHz
33    pub fn new(timer: TIMER, mut pin: PIN) -> Ws2812<TIMER, PIN> {
34        pin.set_low().ok();
35        Self { timer, pin }
36    }
37
38    /// Write a single color for ws2812 devices
39    #[cfg(feature = "slow")]
40    fn write_byte(&mut self, mut data: u8) {
41        for _ in 0..8 {
42            if (data & 0x80) != 0 {
43                block!(self.timer.wait()).ok();
44                self.pin.set_high().ok();
45                block!(self.timer.wait()).ok();
46                block!(self.timer.wait()).ok();
47                self.pin.set_low().ok();
48            } else {
49                block!(self.timer.wait()).ok();
50                self.pin.set_high().ok();
51                self.pin.set_low().ok();
52                block!(self.timer.wait()).ok();
53                block!(self.timer.wait()).ok();
54            }
55            data <<= 1;
56        }
57    }
58
59    /// Write a single color for ws2812 devices
60    #[cfg(not(feature = "slow"))]
61    fn write_byte(&mut self, mut data: u8) {
62        for _ in 0..8 {
63            if (data & 0x80) != 0 {
64                block!(self.timer.wait()).ok();
65                self.pin.set_high().ok();
66                block!(self.timer.wait()).ok();
67                block!(self.timer.wait()).ok();
68                self.pin.set_low().ok();
69            } else {
70                block!(self.timer.wait()).ok();
71                self.pin.set_high().ok();
72                block!(self.timer.wait()).ok();
73                self.pin.set_low().ok();
74                block!(self.timer.wait()).ok();
75            }
76            data <<= 1;
77        }
78    }
79}
80
81impl<TIMER, PIN> SmartLedsWrite for Ws2812<TIMER, PIN>
82where
83    TIMER: CountDown + Periodic,
84    PIN: OutputPin,
85{
86    type Error = ();
87    type Color = RGB8;
88    /// Write all the items of an iterator to a ws2812 strip
89    fn write<T, I>(&mut self, iterator: T) -> Result<(), Self::Error>
90    where
91        T: Iterator<Item = I>,
92        I: Into<Self::Color>,
93    {
94        for item in iterator {
95            let item = item.into();
96            self.write_byte(item.g);
97            self.write_byte(item.r);
98            self.write_byte(item.b);
99        }
100        // Get a timeout period of 300 ns
101        for _ in 0..900 {
102            block!(self.timer.wait()).ok();
103        }
104        Ok(())
105    }
106}