WS2812B & SK6812 — One-Wire Protocol#
The WS2812B is the LED that launched a thousand LED projects. Each package integrates a controller and RGB (or RGBW in the SK6812 variant) emitters in a single 5050-size SMD footprint, with data cascading from one LED to the next over a single wire. The protocol is dead simple in concept — timed high/low pulses encode bits — but the tight timing requirements make it one of the more demanding peripherals to drive from a microcontroller.
Protocol Basics#
Data is sent as a stream of 24-bit (WS2812B) or 32-bit (SK6812 RGBW) words, one per LED, most-significant bit first. Each bit is encoded as a high pulse followed by a low pulse on the data line. A 1 bit uses a long high pulse (~800ns) and short low pulse (~450ns); a 0 bit uses a short high pulse (~400ns) and long low pulse (~850ns). The total bit period is roughly 1.25µs. After all pixel data is sent, holding the line low for at least 280µs (50µs on older datasheets, but 280µs is safer across clones) triggers a latch, and the LEDs update simultaneously.
The first LED in the chain consumes the first 24 (or 32) bits and passes everything else downstream, reshaping the signal in the process. This cascading architecture means only one GPIO pin is needed regardless of strip length, but it also means the entire strip must be refreshed every frame — there’s no way to address a single LED without resending the full chain.
Timing Tolerances and Clones#
The timing windows on genuine WorldSemi WS2812B parts are tighter than they look on paper. The datasheet specifies ±150ns tolerances, but clone chips (and there are many) vary considerably. Some clones accept sloppier timing; others are pickier than the originals. The SK6812 — originally a clone that became a product family — generally has more relaxed timing and adds the RGBW variant with a dedicated white channel for better color rendering and more efficient white output.
Running the protocol from a busy-loop with NOP delays works on simple microcontrollers but falls apart the moment an interrupt fires mid-stream. On ARM Cortex-M parts, the standard approach is to use SPI or a timer peripheral to generate the waveform in hardware, often with DMA to free the CPU entirely. On ESP32, the RMT (Remote Control Transceiver) peripheral handles WS2812B timing natively. On AVR (Arduino Uno), the tight timing is typically handled with hand-tuned assembly in libraries like FastLED or Adafruit NeoPixel, with interrupts disabled during transmission.
Color Order#
Not all WS2812B-protocol LEDs use GRB color order. The original WS2812B sends Green-Red-Blue, but the SK6812 RGBW variant sends Red-Green-Blue-White. Some newer WS2812B-compatible LEDs use RGB order. Getting the color order wrong produces recognizable symptoms — requesting red and getting green (or vice versa) is the telltale sign. Most libraries allow specifying the color order explicitly.
Data Rate and Refresh#
At 1.25µs per bit, 24 bits per LED, a 300-LED strip takes about 9ms to refresh — roughly 111 fps maximum. Adding the 280µs latch time is negligible. For RGBW strips at 32 bits per LED, the same 300 LEDs take about 12ms, capping at roughly 83 fps. These rates are more than adequate for smooth animation, but the single-wire bottleneck means very long strips (1000+ LEDs) start to limit achievable frame rates.
Tips#
- Use the RMT peripheral on ESP32, PIO on RP2040, or DMA-driven SPI on STM32 — bit-banging the WS2812B protocol invites timing glitches from interrupts
- Add a 300–500Ω resistor in series with the data line, placed close to the first LED, to reduce ringing on the signal edge
- Place a 100µF–1000µF decoupling capacitor across the power rails near the strip’s power input to handle inrush current on first power-on
- When mixing WS2812B and SK6812 strips in a project, verify color order for each strip type — assuming GRB universally leads to swapped channels
Caveats#
- Interrupts during transmission corrupt the data stream — Even a short ISR firing mid-frame can shift the timing enough to garble downstream LEDs. Disabling interrupts for the duration of transmission is common but impacts other real-time tasks
- The “one-wire” protocol is not electrically robust — Signal integrity degrades over long runs and in noisy environments. A WS2812B data line is not a bus — it’s a daisy-chain with each LED reshaping the signal for the next, which helps, but the first LED in the chain is the most vulnerable
- Clone timing varies unpredictably — A strip that works perfectly with one library version or MCU clock speed may glitch with another. When switching LED suppliers, re-test with the actual hardware before committing to a design
- 5V logic levels are expected — The WS2812B datasheet specifies a minimum high-level input of 0.7×VDD. At 5V power, that’s 3.5V, which is above the 3.3V output of most modern MCUs. A level shifter or the “sacrificial first LED powered at 3.3V” trick is often needed
In Practice#
- A strip that lights the first few LEDs correctly but shows random colors further down the chain typically indicates a signal integrity problem — either the data line is too long without buffering, or a level-shifting issue is attenuating the signal
- Requesting red and seeing green (or the reverse) means the color order in the library doesn’t match the strip — swap between GRB and RGB in the driver configuration
- Flickering or occasional glitching that appears at irregular intervals usually traces back to interrupt contention — an ISR is firing during the data transmission window and corrupting the timing
- A strip that works on the bench but glitches when installed in a final enclosure may be picking up noise from nearby switching power supplies or motor drivers — shielding the data line or adding a buffer IC at the strip input often resolves it