ESP32-C6 rainbow
A hue wheel on the DevKitC-1's own RGB LED and seven more, bit-banged on GPIO 8. The whole build, an ESP32-C6 and 1 more part, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Beginner About 15 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $17. On Mokxi they're free.
What you'll learn
- How addressable RGB LEDs take colors down one data wire
- Why a 0 and a 1 bit are pulses of different lengths
- Building a color wheel with whole numbers instead of floats
- Using a phase offset to spread a pattern along a strip
- Difficulty: Beginner
- Time: About 15 minutes
- Board: ESP32-C6-DevKitC-1
- Parts: 3
How it works
GPIO 8 on this board drives an addressable RGB LED, not a plain one. It wants a precise stream of pulses, 24 bits per LED. Your wired LEDs connect to the same pin, so the board's LED comes first in the chain, followed by seven more.
Each frame the sketch picks a color for every LED from a color wheel, each one a step further round than its neighbor. Then it sends all the colors out in one go. The whole wheel moves a little each frame, so the rainbow appears to roll along the strip.
The sketch runs at about 50 frames a second. The brightness is held low on purpose, so eight LEDs at full power do not blind you.
Parts list
3 parts, plus the jumper wires. They retail for about $17; on Mokxi they're free.
- 1 × ESP32-C6-DevKitC-1
- 1 × Full-size breadboard
- 1 × Addressable RGB LEDsIn Claw Machine Kit, Halloween Prop Kit, Christmas Lights Kit.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Addressable RGB LEDs pin DIN | ESP32-C6-DevKitC-1 pin 8 |
| Addressable RGB LEDs pin VDD | ESP32-C6-DevKitC-1 pin 5V |
| Addressable RGB LEDs pin VSS | ESP32-C6-DevKitC-1 pin GND |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Rainbow: the DevKitC-1's own RGB LED, and a strip beside it.
//
// GPIO 8 on this board is not a plain LED. It is an addressable one (a
// WS2812 in the corner by the USB socket), and it wants twenty-four bits, not
// a level. That is the pin `LED_BUILTIN` names, so this is what the board's
// LED is actually for.
//
// Wiring, strip to board:
// DIN -> GPIO 8 VDD -> 5 V VSS -> GND
//
// One wire carries the whole chain: the board's own LED first, then anything
// wired after it. There is no clock: a bit is a high pulse whose length is
// the bit, 0.4 us for a 0 and 0.8 us for a 1, twenty-four bits an LED, green
// first. Fifty microseconds of quiet at the end is the latch.
//
// The driver in mokxi_ws2812.h makes those pulses with a counted loop rather
// than a timer, because SYSTIMER ticks at 16 MHz, 62.5 ns a tick, and
// reading it takes longer than the pulse being measured. The RMT peripheral
// that would normally do this on a C6 is not modelled (docs/esp32c6.md section
// 7), so bit-banging is not a shortcut here: it is the only way.
//
// There is no floating point in this runtime, so the colour wheel is integers:
// 1536 steps round the six edges of the RGB cube, one channel at full, one at
// nothing and one sliding between them.
#include "mokxi_ws2812.h"
const uint8_t DIN_PIN = 8;
const uint16_t LEDS = 8;
// Three bytes an LED, green first: the order the wire wants them in.
uint8_t pixels[LEDS * 3];
Ws2812 strip(DIN_PIN, pixels, LEDS);
// Where the wheel has got to, and how far apart two neighbours are on it.
uint16_t phase = 0;
const uint16_t SPREAD = 1536 / LEDS;
const uint16_t SPEED = 16;
// Full scale on all eight would be a floodlight. This is a sixth of it.
const uint8_t LEVEL = 40;
const int FRAME_MS = 20;
void setup() {
Serial.begin(115200);
Serial.println("Mokxi ESP32-C6: a rainbow on the RGB LED and seven more");
strip.begin();
strip.clear();
strip.show();
}
void loop() {
for (uint16_t i = 0; i < LEDS; i++) {
uint8_t r;
uint8_t g;
uint8_t b;
ws2812_wheel((uint16_t)(phase + i * SPREAD), &r, &g, &b);
strip.setPixel(i, ws2812_scale(r, LEVEL), ws2812_scale(g, LEVEL),
ws2812_scale(b, LEVEL));
}
strip.show();
phase = (uint16_t)((phase + SPEED) % 1536u);
delay(FRAME_MS);
}
Code walkthrough
The key functions of the sketch, and what each one does.
setup sketch.ino
Starts the serial port and prepares the strip with strip.begin. Then strip.clear and strip.show send an all-off frame, so the LEDs start dark instead of showing whatever they powered up with.
void setup() {
Serial.begin(115200);
Serial.println("Mokxi ESP32-C6: a rainbow on the RGB LED and seven more");
strip.begin();
strip.clear();
strip.show();
}loop sketch.ino
For each LED it asks ws2812_wheel for a color at phase plus the LED's number times SPREAD, scales it down with LEVEL, and stores it. After the loop strip.show sends everything. Then phase moves forward by SPEED and the sketch waits FRAME_MS.
void loop() {
for (uint16_t i = 0; i < LEDS; i++) {
uint8_t r;
uint8_t g;
uint8_t b;
ws2812_wheel((uint16_t)(phase + i * SPREAD), &r, &g, &b);
strip.setPixel(i, ws2812_scale(r, LEVEL), ws2812_scale(g, LEVEL),
ws2812_scale(b, LEVEL));
}
strip.show();
phase = (uint16_t)((phase + SPEED) % 1536u);
delay(FRAME_MS);
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- Only the board's own LED lights up. This project
Check the strip wiring: DIN to GPIO 8, VDD to 5V, VSS to GND. - The colors look wrong or flicker. This project
Make sure the ground is shared and the data wire goes to DIN, not the output side. - The first LED flickers, shows wrong colors, or the whole strip glitches. Addressable RGB LEDs
Join the grounds of the strip and the controller. Add a 300 to 500 ohm resistor in series with the data line. Put a 1000 uF capacitor across the strip's 5 V and GND. - The strip works at low brightness but dims, turns yellow, or resets when many LEDs go white. Addressable RGB LEDs
Each LED can draw about 60 mA at full white. Use a 5 V supply sized for the count, feed power in at several points, and lower the brightness in code. - A 5 V signal damages or confuses a pin. ESP32-C6-DevKitC-1
All ESP32-C6 GPIOs are 3.3 V and not 5 V tolerant. Level shift 5 V sensors. Do not feed 5 V into any GPIO. - The board will not boot or enter run mode as expected. ESP32-C6-DevKitC-1
GPIO 4, 5, 8, 9 and 15 are strapping pins read at reset. Do not hold them at odd levels at power up. GPIO 8 also drives the RGB LED.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.