1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
//! # Use ws2811 leds via spi
//!
//! - For usage with `smart-leds`
//! - Implements the `SmartLedsWrite` trait
//!
//! Needs a type implementing the `spi::FullDuplex` trait.
//!
//! The spi peripheral should run at 2MHz to 3.8 MHz
#![no_std]
use embedded_hal as hal;
pub mod prerendered;
use hal::spi::{FullDuplex, Mode, Phase, Polarity};
use core::marker::PhantomData;
use smart_leds_trait::{SmartLedsWrite, RGB8};
use nb;
use nb::block;
/// SPI mode that can be used for this crate
///
/// Provided for convenience
/// Doesn't really matter
pub const MODE: Mode = Mode {
polarity: Polarity::IdleLow,
phase: Phase::CaptureOnFirstTransition,
};
pub mod devices {
pub struct Ws2811;
}
pub struct Ws2811<SPI, DEVICE = devices::Ws2811> {
spi: SPI,
device: PhantomData<DEVICE>,
}
impl<SPI, E> Ws2811<SPI>
where
SPI: FullDuplex<u8, Error = E>,
{
/// Use Ws2811 devices via spi
///
/// The SPI bus should run within 2 MHz to 3.8 MHz
///
/// You may need to look at the datasheet and your own hal to verify this.
///
/// Please ensure that the mcu is pretty fast, otherwise weird timing
/// issues will occur
pub fn new(spi: SPI) -> Self {
Self {
spi,
device: PhantomData {},
}
}
}
impl<SPI, D, E> Ws2811<SPI, D>
where
SPI: FullDuplex<u8, Error = E>,
{
/// Write a single byte for Ws2811 devices
fn write_byte(&mut self, mut data: u8) -> Result<(), E> {
// Send two bits in one spi byte. High time first, then the low time
// The maximum for T0H is 500ns, the minimum for one bit 1063 ns.
// These result in the upper and lower spi frequency limits
let patterns = [0b1000_1000, 0b1000_1110, 0b11101000, 0b11101110];
for _ in 0..4 {
let bits = (data & 0b1100_0000) >> 6;
block!(self.spi.send(patterns[bits as usize]))?;
block!(self.spi.read()).ok();
data <<= 2;
}
Ok(())
}
fn flush(&mut self) -> Result<(), E> {
// Should be > 300μs, so for an SPI Freq. of 3.8MHz, we have to send at least 1140 low bits or 140 low bytes
for _ in 0..140 {
block!(self.spi.send(0))?;
block!(self.spi.read()).ok();
}
Ok(())
}
}
impl<SPI, E> SmartLedsWrite for Ws2811<SPI>
where
SPI: FullDuplex<u8, Error = E>,
{
type Error = E;
type Color = RGB8;
/// Write all the items of an iterator to a Ws2811 strip
fn write<T, I>(&mut self, iterator: T) -> Result<(), E>
where
T: Iterator<Item = I>,
I: Into<Self::Color>,
{
// We introduce an offset in the fifo here, so there's always one byte in transit
// Some MCUs (like the stm32f1) only a one byte fifo, which would result
// in overrun error if two bytes need to be stored
block!(self.spi.send(0))?;
if cfg!(feature = "mosi_idle_high") {
self.flush()?;
}
for item in iterator {
let item = item.into();
self.write_byte(item.r)?;
self.write_byte(item.g)?;
self.write_byte(item.b)?;
}
self.flush()?;
// Now, resolve the offset we introduced at the beginning
block!(self.spi.read())?;
Ok(())
}
}