WS2812 LED bar/How it works/05. Bits as pulse widths
How it works · 05 of 9

Bits as pulse widths

Every bit on DATA starts with the line going HIGH, and the LED tells a 0 from a 1 by how long it stays there: 0.2 to 0.41 µs is a 0, 0.64 to 1 µs a 1, in a slot of 1.25 µs. A line held LOW for 80 µs ends the frame. The gap between a 0 and a 1 is a few hundred nanoseconds, which is why a library sends them and a sketch never does.

A 0 and a 1 differ only in width

A 0 and a 1 differ only in width
reads 1
Time HIGH800 ns
HIGH
800 ns
LOW
450 ns
LED reads
1
High for 800 ns: a 1. Anything from 640 to 1000 ns is a 1. Adafruit NeoPixel on an ESP32 sends 800. The data sheet's table gives a typical 595, short of this window: the sheet disagrees with itself.

DATA carries one bit every 1.25 µs, 800 thousand a second. Every bit starts with the line going HIGH. The LED measures how long it stays there:

  • HIGH for 200 to 410 ns is a 0.
  • HIGH for 640 to 1000 ns is a 1.
  • In between, or outside both, the data sheet promises nothing.

The rest of the slot is LOW. The LED watches for the next rising edge and measures again.

These windows are from the notes under the data sheet's timing table. The table itself does not quite agree with them: its typical 0 is 295 ns, and its typical 1, 595 ns, falls short of the notes' 640. On an ESP32, Adafruit NeoPixel sends 400 ns and 800 ns in a 1.2 µs slot, inside both of the notes' windows, the 0 with little to spare.

The end of a frame

A frame ends when DATA stays LOW for at least 80 µs; the data sheet's notes ask for 100 to be safe. That is the moment every LED switches to the colour it kept. So a pause inside a frame is dangerous too: the data sheet warns that a gap of more than about 35 µs between two bits may be taken as the end.

Why a library sends them

digitalWrite() followed by a delay cannot make a 300 ns pulse, and an interrupt from Wi-Fi or a timer can land in the middle of one and turn a 0 into something the LED cannot read. So nobody sends these bits by hand.

On an ESP32 the library hands them to the RMT, a peripheral built to send pulses of exact length while the processor does something else. The sketch writes colours into an array and calls show(); the RMT does the timing.

When it does not work

Can I send the bits with digitalWrite and delayMicroseconds?

No. The shortest delay those give is a microsecond, longer than a whole 0 pulse, and an interrupt landing mid-pulse stretches it further. The LED needs its HIGH times right to within a couple of hundred nanoseconds. Adafruit NeoPixel hands the bits to the ESP32's RMT peripheral, which times them in hardware; FastLED does the same by default.

The LEDs glitch when Wi-Fi is busy.

On an ESP32 the RMT times every pulse in hardware, so a busy processor cannot stretch a bit the way it stretches a delay. If the colours still glitch, look at the data level and the ground before the timing: a 3.3 V HIGH against a full 5 V supply, or a ground that only meets through one thin jumper, gives the same symptom.

How fast can I update the bar?

A frame for five LEDs is 120 bits, about 150 µs, and then the line must rest low for at least 80 µs; Adafruit NeoPixel waits 300 µs before it sends again. So a few thousand frames a second is possible, and anything over about a hundred looks the same to an eye.

Where this goes next

The order the three bytes go in, and what swapping it looks like.

Green, red, blue

Edit this page — content/books/ws2812-led-bar/bits-as-pulse-widths.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

WS2812 RGB LED Bar

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum