Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
ws2812-rmt
A minimal, no_std WS2812/NeoPixel driver over esp-hal's RMT peripheral —
no third-party smart-leds/RMT abstraction in between.
Why this exists
Extracted from real-hardware debugging on an ESP32-C6
(jcmendez/fall_sensor-rust)
after esp-hal-smartled2
proved unable to reliably update a WS2812 pixel to a changing value on
repeated writes — a single steady color always rendered correctly, but
blink/breathe patterns (i.e. anything other than "set it once and leave it")
reliably corrupted: either sticking on a stale frame, or bleeding a
previously-sent channel's value into later frames (a once-used blue value
would visibly tint every later color — red became pink, green became cyan).
Root cause: that crate — like most WS2812/RMT drivers, including an earlier
version of this one — relies on the RMT channel's idle-low state between
separate transmissions to serve as the WS2812's required ≥50µs reset/latch
pulse, rather than encoding that reset explicitly in the transmitted buffer
the way Espressif's own reference encoder
(esp-idf/examples/peripherals/rmt/led_strip_simple_encoder)
does. This crate always appends an explicit reset pulse, and transmits in
blocking mode (Channel::transmit(..).wait(), which busy-polls hardware
status registers — no interrupt/async-waker path at all) so a bug in an
async completion path can't be a variable either.
Full debugging writeup:
jcmendez/alerter_o1space_rust's doc/learnings.md
(search "WS2812").
RMT clock tick period is chip- and configuration-specific — verify it
Every Timing field is a count of RMT clock ticks, not nanoseconds. The
tick period depends on your chip's RMT clock source (which varies by chip
family, and isn't always what esp-hal's own metadata suggests — this crate
exists partly because that assumption was wrong once already) and on
Rmt::new's requested frequency.
Timing::WS2812_AT_12_5NS_TICK is confirmed correct on an ESP32-C6 with:
let rmt = new?;
in your own setup code (this crate fixes the channel's additional clock divider internally to reproduce the same recipe). If you're on a different chip or clock configuration, verify on real hardware — a logic analyzer is the reliable way. Empirically, a wrong tick period here doesn't fail loudly; it renders as anything from "stuck on one color" to "completely dark".
Usage
use ;
let rmt = new?;
let mut led = buffer_len }>new?;
led.write?;
For more than one pixel, size the buffer for however many you have:
const PIXELS: usize = 25;
let mut leds = buffer_len }>new?;
leds.write?;
Chip support
Gated behind Cargo features matching esp-hal's own chip features — enable
the one matching your target:
esp32, esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2,
esp32s2, esp32s3.
CI only exercises esp32c3/esp32c6 (RISC-V targets installable via plain
rustup, no Xtensa toolchain needed) — the others should work by the same
esp-hal feature-forwarding mechanism, but haven't been build-tested here.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.