apa102_spi/
lib.rs

1//! Send data to APA102 LEDs (also known as DotStar LEDs) via SPI. This crate is also compatible with SK9822 LEDs which share the same protocol as APA102 LEDs. Both blocking and asynchronous implementations are provided, which require a HAL crate for your microcontroller with an implementation of the [embedded_hal::spi::SpiBus] or [embedded_hal_async::spi::SpiBus] trait.
2//!
3//! There are several ways to send pixel data:
4//!   * Handle all details of the protocol yourself with the [Apa102Pixel] struct, 8 bit RGB + 5 bits brightness
5//!   * Simply provide [RGB8] values, hardcoding maximum brightness. This may be uncomfortably bright.
6//!   * Use [FastLED's pseudo-13-bit gamma correction algorithm](https://github.com/FastLED/FastLED/blob/master/APA102.md) to convert [RGB8] + 8 bit brightness to 8 bit RGB + 5 bit brightness.
7//!
8//! ```
9//! # use embedded_hal::spi::{SpiBus, ErrorType, ErrorKind};
10//! # struct DummySpi;
11//! # impl ErrorType for DummySpi {
12//! #   type Error = ErrorKind;
13//! # }
14//! #
15//! # impl SpiBus for DummySpi {
16//! #   fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
17//! #     Ok(())
18//! #   }
19//! #
20//! #   fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
21//! #     Ok(())
22//! #   }
23//! #
24//! #   fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
25//! #     Ok(())
26//! #   }
27//! #
28//! #   fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
29//! #     Ok(())
30//! #   }
31//! #
32//! #   fn flush(&mut self) -> Result<(), Self::Error> {
33//! #     Ok(())
34//! #   }
35//! # }
36//! # let get_spi_peripheral_from_your_hal = DummySpi {};
37//! use apa102_spi::{u5, Apa102Pixel, Apa102Writer, PixelOrder, SmartLedsWrite, RGB8};
38//!
39//! // You only need to specify MOSI and clock pins for your SPI peripheral.
40//! // APA102 LEDs do not send data over MISO and do not have a CS pin.
41//! let spi = get_spi_peripheral_from_your_hal;
42//! let mut led_strip = Apa102Writer::new(spi, 1, PixelOrder::default());
43//!
44//! // Specify pixel values as 8 bit RGB + 5 bit brightness
45//! let led_buffer = [Apa102Pixel { red: 255, green: 0, blue: 0, brightness: u5::new(1) }];
46//! led_strip.write(led_buffer);
47//!
48//! // Specify pixel values with 8 bit RGB values
49//! let led_buffer_rgb = [RGB8 { r: 255, g: 0, b: 0 }];
50//! // Brightness is set to maximum value (31) in `impl From<RGB8> for Apa102Pixel`
51//! led_strip.write(led_buffer_rgb);
52//!
53//! // Convert RGB8 + 8 bit brightness into Apa102Pixels
54//! // using FastLED's pseudo-13-bit gamma correction algorithm.
55//! led_strip.write(led_buffer_rgb.map(
56//!   |p| Apa102Pixel::from_rgb8_with_brightness(p, 255, None)));
57//! ```
58//!
59//! ## Cargo features
60//!   * `defmt`: impl [defmt::Format] for [Apa102Pixel] (off by default)
61
62#![no_std]
63
64pub use smart_leds_trait::{SmartLedsWrite, SmartLedsWriteAsync, RGB, RGB16, RGB8};
65
66mod pixel;
67pub use pixel::Apa102Pixel;
68pub use ux::u5;
69
70mod bitshift;
71mod math;
72mod pseudo13;
73
74use embedded_hal::spi::{Mode, Phase, Polarity};
75
76/// SPI mode that is needed for this crate
77///
78/// Provided for convenience
79pub const MODE: Mode = Mode {
80    polarity: Polarity::IdleLow,
81    phase: Phase::CaptureOnFirstTransition,
82};
83
84/// What order to transmit pixel colors. The standard order
85/// is [PixelOrder::BGR], however in practice, some LEDs
86/// swap the order of the colors in the protocol.
87pub enum PixelOrder {
88    RGB,
89    RBG,
90    GRB,
91    GBR,
92    BRG,
93    BGR,
94}
95
96impl Default for PixelOrder {
97    fn default() -> Self {
98        PixelOrder::BGR
99    }
100}
101
102#[path = "."]
103mod asynchronous {
104    use bisync::asynchronous::*;
105    use embedded_hal_async::spi::SpiBus;
106    use smart_leds_trait::SmartLedsWriteAsync as SmartLedsWrite;
107    mod writer;
108    pub use writer::*;
109}
110pub use asynchronous::Apa102Writer as Apa102WriterAsync;
111
112#[path = "."]
113mod blocking {
114    use bisync::synchronous::*;
115    use embedded_hal::spi::SpiBus;
116    use smart_leds_trait::SmartLedsWrite;
117    #[allow(clippy::duplicate_mod)]
118    mod writer;
119    pub use writer::*;
120}
121pub use blocking::Apa102Writer;