Skip to main content

Section 4.4 WS2812 RGB LEDs (aka neopixels)

The WS2812 is an LED module which contains a red, green, and blue LED in a single package, along with a tiny circuit to control the intensity using PWM. Thanks to some clever design, the WS2182 modules can be chained together but still controlled individually: your microcontroller sends a series of LED configurations on single wire connected to the first LED module. The module applies the configuration for the first LED, but then forwards the rest of the data on to the next LED module. The second module applies the first configuration it receives and passes the rest, and so on. Thanks to Adafruit's marketing, these LEDs are popularly known as "neopixels".

Subsection 4.4.1 Wiring

The LED strip has 3 contacts which should be labeled on the strip:

  • Ground - Connect this to ground (GND) on your microcontroller.

  • 5V - Connect this to 5V (VBUS) on your microcontroller.

  • Din (Data in) - Connect this to any microcontroller I/O pin. Note that the other end of the LED strip will have this pin labeled as Dout (Data out). Make sure to connect to the Din end!

Subsection 4.4.2 Power concerns

The LED modules consume about 12mA per color per LED module at full power.

With 10 modules at full brightness, this will be:

\begin{equation*} 12\mathrm{\frac{mA}{LED}}\cdot3\mathrm{\frac{LEDs}{module}\cdot10\mathrm{modules}=}360\,\mathrm{mA} \end{equation*}

A laptop will often limit the current out of a USB port to 500 mA, so if you're trying to drive more than about 15 LEDs at full power, you may experience "brownouts" where the ESP32 suddenly reboots or quits responding.

You can work around this by powering your ESP32 with a USB power pack or USB charger instead of your laptop. Or you can just make sure to not turn on all the LEDs at once!

Subsection 4.4.3 Basic control

MicroPython has neopixel support built in. The following code will set up a string of 10 LEDs:

from machine import Pin
import neopixel

NUM_LEDS = 10
NEOPIXEL_DATA_PIN = 14 # Any digital output should work

leds = neopixel.NeoPixel(Pin(NEOPIXEL_DATA_PIN), NUM_LEDS)

An LED's color can be specified with a \term{tuple} of 3 numbers corresponding to red, green, and blue. A value of 0 is off; a value of 255 is on at full intensity. We use square brackets to access particular LEDs by their index:

# Set the first LED to be red
leds[0] = (255, 0, 0)

# Set the second one to be blue
leds[1] = (255, 0, 0)

# Set the tenth one to be greenish-yellow
leds[9] = (130, 255, 0)

Finally, we have to actually send the updated configuration to the LED strip:

leds.write()

Subsection 4.4.4 More exciting patterns

It's easy to set lots of LEDs all at once using a for loop:

for i in range(NUM_LEDS):
    leds[i] = (255, 128, 0)
for i in range(NUM_LEDS):
    leds[i] = (round(255 * i / NUM_LEDS), 128, 0)