WS2812B Rust Driver (no std)
A lightweight, platform-agnostic Rust driver for WS2812B RGB LEDs. Designed with embedded systems in mind, this crate provides configurable timing strategies for controlling LED strips. It supports traditional bit-banging over a single data line, as well as highly reliable hardware SPI waveform generation. Compatible with #![no_std], it includes full support for synchronous (embedded-hal) and asynchronous (embedded-hal-async / embassy-time) environments.
Features
- 1-Wire RGB Protocol: Fully compatible with WS2812B LEDs.
- Hardware SPI Support: Generate strict timing waveforms automatically using an SPI MOSI pin, completely eliminating Wi-Fi/RTOS interrupt glitches. Uses dynamic frequency calculation to guarantee timing accuracy.
- Multiple Sync Timing Strategies: *
own_delay: Uses an external delay provider implementingDelayNs.manual: Expects delay objects at each function call.spinloop_delay(Default): Pure spin-loop timing using CPU frequency.
- Async Support: First-class async/await support via the
asyncfeature, leveragingembedded-hal-asyncandembassy-time. - Rich Color Library: Built-in modular
Colorstruct with pre-defined constants (Red, Green, Blue, Cyan, Magenta, Yellow, White, Orange, Purple, Pink, Brown).
Configuration
Enable your desired bit-banging timing backend by activating one of the following features in your Cargo.toml. (Note: SPI support does not require a specific timing feature).
| Feature | Description |
|---|---|
spinloop_delay |
(Default) Delay through CPU spin-loops using a known CPU frequency. |
own_delay |
Passes a mutable reference to an embedded_hal::delay::DelayNs trait impl upon driver creation. |
manual |
Requires a delay provider to be passed explicitly at each call to send_color. |
async |
Enables asynchronous operation (AsyncGlowColor trait / send_color_w_embassy), requiring embedded-hal-async and embassy-time. |
Note: You should only enable one of the synchronous delay strategies (
spinloop_delay,own_delay, ormanual) at a time. Theasyncfeature can be layered on top of them.
Usage
Cargo.toml
[]
= "*" # Replace with the actual version
= "1.0"
# Only required if using the `async` feature:
= "1.0"
= "0.3"
Core Traits & Methods
Depending on your hardware setup, you will interact with the LED strip using one of the following traits:
1. Hardware SPI Operation (SendColorBySPI)
The most stable method for systems running Wi-Fi or RTOS.
write_colors([Color; N], freq): Dynamically translates colors into SPI bit-patterns based on your SPI bus frequency and sends them to the strip.
2. Synchronous GPIO Operation (GlowColor)
Available by default for traditional bit-banging. Use this for blocking execution on simpler boards.
send_color([Color; N]): Sends an array of colors to the LED strip. (Requires a delay reference ifmanualis enabled).
3. Asynchronous GPIO Operation (AsyncGlowColor)
Available when the async feature is enabled. Use this in async contexts (e.g., Embassy).
async_send_color([Color; N]): Asynchronously drives the LED pins, awaiting on high/low pin states and nanosecond delays.send_color_w_embassy([Color; N]): A dedicated async method utilizingembassy_time::Timerfor precision non-blocking delays.
The Color Struct
You can easily define custom colors using RGB values or use the built-in constant methods:
use Color;
// Custom RGB
let custom_color = Color;
// Built-in presets
let red = red;
let cyan = cyan;
let orange = orange;
// Also available: green(), blue(), magenta(), yellow(), white(), purple(), pink(), brown()
Driver Instantiation Examples
1. Using Hardware SPI (Recommended for ESP32/Wi-Fi)
use ;
// Assuming `spi` is an initialized embedded_hal SpiBus running at ~3.2 MHz
let mut ws2812 = WS2812SPI ;
// Write colors dynamically by passing the current SPI frequency
ws2812.write_colors.unwrap;
2. Using spinloop_delay (Default Bit-Banging)
// Requires the output pin and your board's CPU frequency in Hz
let mut ws2812 = WS2812new;
ws2812.send_color;
3. Using own_delay
// Requires the output pin and a mutable reference to a DelayNs provider
let mut ws2812 = WS2812new;
4. Using manual
// Requires only the output pin upon creation
let mut ws2812 = WS2812new;
// The delay provider is passed during the transfer
ws2812.send_color;