Quickstart¶
Light a WS2812B strip from an ESP32: wire three signals, add the component, write one loop.
ESP32 and ESP-IDF only
The driver calls ESP-IDF's RMT driver directly. You need an ESP32-family chip with an RMT peripheral and ESP-IDF v5.3 or later; CI builds the examples for the ESP32-C6 with ESP-IDF v5.5.
1. Wire it¶
| ESP32 | Strip | Notes |
|---|---|---|
| GPIO (GPIO8 in the example) | DIN of the first LED | Through a 3.3 V to 5 V level shifter; see below |
| GND | GND (VSS) | One ground for the ESP32, the strip and its supply |
| 5 V (VDD) | From a supply sized for the strip: up to about 60 mA per LED at full white |
A WS2812B powered from 5 V needs at least 3.5 V (0.7 × VDD) on DIN to see a high. An ESP32 drives 3.3 V, which is below that: it often works on a short wire, but it is out of specification. A 74AHCT125 or 74HCT245 powered from 5 V fixes it. Hardware has the pin table, the power budget and the protection parts.
2. Add the driver¶
Add the repository as a submodule and copy the ESP-IDF component wrapper into your project's components/
folder. Installation has the details and the alternatives.
git submodule add https://github.com/hardfoc/hf-ws2812-rmt-driver.git external/hf-ws2812-rmt-driver
cp -r external/hf-ws2812-rmt-driver/examples/esp32/components/hf_ws2812_rmt components/
Tell the wrapper where the driver is, in your top-level CMakeLists.txt before the project.cmake include, and
add hf_ws2812_rmt to the REQUIRES of your main component:
set(HF_WS2812_RMT_ROOT ${CMAKE_SOURCE_DIR}/external/hf-ws2812-rmt-driver CACHE PATH "WS2812 driver checkout")
3. Light it¶
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ws2812_cpp.hpp"
// WS2812B bit timing in RMT ticks of 100 ns (the driver runs the RMT at 10 MHz).
constexpr uint16_t kT0H = 4, kT1H = 8, kT0L = 9, kT1L = 5;
extern "C" void app_main() {
// 8 LEDs on GPIO8, brightness 32 of 255. The constructor claims an RMT TX channel.
WS2812Strip strip(GPIO_NUM_8, -1, 8, LedType::RGB, kT0H, kT1H, kT0L, kT1L, 32);
if (strip.Begin() != ESP_OK) { // no free RMT channel, or a bad GPIO
ESP_LOGE("leds", "RMT channel set-up failed");
return;
}
for (uint32_t i = 0;; i = (i + 1) % strip.Length()) {
strip.SetPixel(i, 0xFF0000); // 0xRRGGBB: one red LED walks along the strip
if (strip.Show() != ESP_OK) { // blocks until the frame is on the wire
ESP_LOGE("leds", "RMT transmit failed");
}
strip.SetPixel(i, 0);
vTaskDelay(pdMS_TO_TICKS(100));
}
}
What each step does:
- The
WS2812Stripconstructor creates an RMT transmit channel on the GPIO at 10 MHz, so the four timing arguments are in ticks of 100 ns: 4, 8, 9 and 5 give 400, 800, 900 and 500 ns, inside the WS2812B's ±150 ns window. They are also the Kconfig defaults (Configuration). Begin()reports whether the RMT channel was set up; a failure (no free channel, a bad GPIO) is returned, not an abort.- Colours are packed
0xRRGGBB; the driver sends green first, as a WS2812B expects. SetPixel()writes the buffer; nothing reaches the LEDs untilShow(), which scales by the brightness, encodes 24 symbols per LED, appends the reset that latches the frame and blocks until the RMT has sent them.
The host CI compiles this example against the driver's headers, so it matches the current API.
If it does not work¶
| Symptom | First thing to check |
|---|---|
| Every LED white or full on | The timing arguments: ticks are 100 ns, so values in ns or µs are far too long |
| Red and green swapped | Colour packing: SetPixel() takes 0xRRGGBB; drop any 0xGGRRBB workaround from older code |
| Nothing lights | Ground shared with the strip, data into DIN (not DOUT), the GPIO number |
| First LED flickers or shows random colours | Data level: add the level shifter, keep the data wire short |
Begin() fails |
No free RMT transmit channel, or an invalid GPIO (Troubleshooting) |
Next¶
- API guide: brightness, resizing, effects, several strips, errors.
- Signal timing: how the ticks, frame time and reset gap work.
- Hardware: level shifting, power injection, protection parts.