ESP32/Interrupts and timing/21. Addressable LEDs with RMT
Your chip
Your language
Interrupts and timing · 21 of 81

Addressable LEDs with RMT

A WS2812 strip is one data wire and a protocol measured in hundreds of nanoseconds - far too fast to bit-bang reliably while Wi-Fi is running. The RMT peripheral does the timing in hardware, which is why it exists.

/esp32/addressable-leds-with-rmt · arduino · S3

Two ceilings, both invisible

30 pixels at 60%
1110 mA
Pixels30
Brightness60%
Peak current
1110 mA
Time to send a frame
1.2 ms
Fastest frame rate
833 fps
1110 mA is more than a USB port will give you, and the board browns out first. The symptom is a reset in the middle of an animation, blamed on the code. Power the strip from its own 5 V supply, join the grounds, and keep brightness under about 40% if it must run from USB.

The wiring that stops the flickering

Four things, and all four are cheap:

  • A separate 5 V supply for the strip, with its ground joined to the board's ground. Not optional past about 20 pixels.
  • A 300–500 Ω resistor in series with the data line, at the board.
  • A 1000 µF capacitor across the strip's 5 V and ground, at the strip.
  • A level shifter, or a first pixel you never use.

What RMT actually is

A peripheral for sending and receiving precisely timed pulse trains. Addressable LEDs are its most common use, but the same hardware drives infrared remotes, one-wire sensors and anything else where the timing is tighter than software can guarantee. It runs in the background with DMA, so a 300-pixel frame does not block your loop for 9 ms.

On your S3
ChipXtensa LX7 · 2 × 240 MHz
Board settingESP32S3 Dev Module
Default I2CSDA 8 · SCL 9
Watch out forThe port vanishes after upload

The code

FastLED and NeoPixelBus both use RMT on the ESP32, so you get hardware timing without asking. The two lines that matter are the brightness cap and the power arithmetic behind it.

strip.ino
#include <FastLED.h>

#define PIN     18
#define NUM     60

CRGB leds[NUM];

void setup() {
  FastLED.addLeds<WS2812B, PIN, GRB>(leds, NUM);
  FastLED.setBrightness(40);          // out of 255
  FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);   // honour USB
}

void loop() {
  static uint8_t hue = 0;
  fill_rainbow(leds, NUM, hue++, 4);
  FastLED.show();                     // RMT sends it in the background
  delay(20);
}

setBrightness is not cosmetic on a strip this size - it is the difference between drawing 1.8 A and drawing 700 mA. Set it before you wonder why the board resets.

When it does not work

The board resets partway through a bright animation

The strip is pulling more than the supply can give. Sixty pixels at full white is nearly 3 A. Power the strip separately, join the grounds, and cap the brightness.

The first pixel is wrong and the rest are fine

A 3.3 V data pin driving a 5 V strip. It usually works, and the first pixel is where usually runs out. Use a level shifter, or sacrifice pixel zero by never displaying anything on it.

Random flickering that gets worse as the strip gets longer

Two causes, both wiring. Put a 300 to 500 Ω resistor in series with the data line at the board end, and a 1000 µF capacitor across the strip's supply at the strip end.

Colours are swapped

WS2812B is GRB, not RGB, and clones vary. Change the colour order in the constructor rather than swapping the values in your code.

Where this goes next

Time to leave the chip. The next chapter is about how two devices agree what a wire means, on any board at all.

Digital in and digital out

Edit this page — content/esp32/addressable-leds-with-rmt.mdx

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 ESP32 on the forum