Built-in project · ESP32-C3-DevKitM-1
Plasma panel on an ESP32-C3
Three sine waves drift across a 16x16 WS2812B matrix, 256 LEDs on one wire from an ESP32-C3. The whole build, an ESP32-C3 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.
AdvancedRuns in your browser. Free, and no account needed.
Click to open it in the editor
The circuit itself, running here on the simulator. Press what can be pressed; click anything else to open it in the editor.
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
sketch.ino · ESP32-C3-DevKitM-1
// Plasma: a 16x16 WS2812B panel, 256 LEDs on one wire.
//
// Wiring, panel to board:
// DIN -> GPIO 5 VDD -> 5 V VSS -> GND
//
// The panel is serpentine: the first row runs left to right, the second right
// to left, and so on, which is how almost all of them are built and why the
// part has a `serpentine` property. `setPanel` does that arithmetic, so the
// sketch thinks in x and y.
//
// A plasma is three sine waves added together: one across, one down, and one
// along the diagonal, each drifting at its own rate. The sum picks a hue. There
// is no floating point in this runtime and none is wanted: a 256-entry table
// of one cycle, indexed by an 8-bit angle that wraps by itself, is both faster
// and exactly periodic.
//
// # What a frame costs, and why it is ten a second
//
// 256 LEDs is 6144 bits, and each one is a pulse the driver times with a
// counted loop, so a frame takes about 7.7 ms of the board's own time. The
// plasma arithmetic is a few thousand instructions and disappears next to it.
// Interrupts are held off for the duration: a stretched pulse is not this
// protocol any more, and the panel would drop the whole frame rather than show
// half of it.
//
// The frame rate is set by the simulator rather than by the chip. Those 6144
// bits are 12 288 edges on the wire, and the Mokxi kernel costs about two
// microseconds to carry one of them through the WS2812B's decoder, so a frame
// the board would finish in 7.7 ms takes the simulator some 30 ms of real time.
// A real ESP32-C3 would run this panel at fifty frames a second without
// noticing. Ten is what the browser can carry while the clock on the toolbar
// still reads close to 1.00x, and even then it dips: a 16x16 panel is the most
// expensive thing in the parts bin to simulate, edge for edge.
#include "mokxi_ws2812.h"
const uint8_t DIN_PIN = 5;
const uint8_t SIDE = 16;
const uint16_t LEDS = (uint16_t)SIDE * SIDE;
uint8_t pixels[LEDS * 3];
Ws2812 panel(DIN_PIN, pixels, LEDS);
/** One cycle of a sine, 0..255 in and 0..255 out. The angle wraps by itself. */
static const uint8_t SIN8[256] = {
128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162,
165, 167, 170, 173, 176, 179, 182, 185, 188, 190, 193, 196,
198, 201, 203, 206, 208, 211, 213, 215, 218, 220, 222, 224,
226, 228, 230, 232, 234, 235, 237, 238, 240, 241, 243, 244,
245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254,
254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253,
253, 252, 251, 250, 250, 249, 248, 246, 245, 244, 243, 241,
240, 238, 237, 235, 234, 232, 230, 228, 226, 224, 222, 220,
218, 215, 213, 211, 208, 206, 203, 201, 198, 196, 193, 190,
188, 185, 182, 179, 176, 173, 170, 167, 165, 162, 158, 155,
152, 149, 146, 143, 140, 137, 134, 131, 128, 124, 121, 118,
115, 112, 109, 106, 103, 100, 97, 93, 90, 88, 85, 82,
79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49,
47, 44, 42, 40, 37, 35, 33, 31, 29, 27, 25, 23,
21, 20, 18, 17, 15, 14, 12, 11, 10, 9, 7, 6,
5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5,
5, 6, 7, 9, 10, 11, 12, 14, 15, 17, 18, 20,
21, 23, 25, 27, 29, 31, 33, 35, 37, 40, 42, 44,
47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76,
79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112,
115, 118, 121, 124,
};
static inline uint8_t sin8(uint8_t angle) { return SIN8[angle]; }
uint16_t t = 0;
// Bright enough to read on the canvas, dim enough that a real panel would not
// need its own supply.
const uint8_t LEVEL = 96;
const int FRAME_MS = 100;
void setup() {
Serial.begin(115200);
Serial.println("Mokxi ESP32-C3: plasma on a 16x16 WS2812B panel");
panel.begin();
panel.clear();
panel.show();
}
void loop() {
for (uint8_t y = 0; y < SIDE; y++) {
for (uint8_t x = 0; x < SIDE; x++) {
// Three waves: across, down, and along the diagonal, each drifting.
uint16_t v = (uint16_t)sin8((uint8_t)(x * 14u + t));
v = (uint16_t)(v + sin8((uint8_t)(y * 12u - t * 2u)));
v = (uint16_t)(v + sin8((uint8_t)((x + y) * 9u + t / 2u)));
// 0..765 into the 1536 steps of the wheel, twice round the cube.
uint16_t hue = (uint16_t)((v * 2u) % 1536u);
uint8_t r;
uint8_t g;
uint8_t b;
ws2812_wheel(hue, &r, &g, &b);
panel.setPanel(x, y, SIDE, true, ws2812_scale(r, LEVEL), ws2812_scale(g, LEVEL),
ws2812_scale(b, LEVEL));
}
}
panel.show();
t = (uint16_t)(t + 3u);
delay(FRAME_MS);
}
Parts list
3 parts, plus the jumper wires. Every one is in the editor's parts bin.
How it is wired
3 connections, pin by pin, read from the circuit itself. Each line is one set of pins joined together, by a jumper wire or a breadboard strip.
- Ground: ESP32-C3-DevKitM-1 pin GND; Addressable RGB LEDs pin VSS
- ESP32-C3-DevKitM-1 pin 5; Addressable RGB LEDs pin DIN
- ESP32-C3-DevKitM-1 pin 5V; Addressable RGB LEDs pin VDD
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.