🛠 Piloter un ruban WS2812 sans bloquer le CPU : WS2812Serial et OctoWS2811
Objectives
The Teensy is THE reference for lighting installations. Two PJRC libraries compete advantageously: WS2812Serial (up to 8 non-blocking instances, each on a UART port used as a DMA waveform generator) and OctoWS2811 (DMA refresh at a video rate of 30 Hz — and on the Teensy 4.0, "supports use of any number of digital pins", so we are no longer limited to the 8 pins of the Teensy 3.x). This tutorial uses WS2812Serial: your sketch continues to run at full speed while the DMA sends the frames.
Hardware
- 1 Teensy 4.0 + WS2812B strip (e.g., 60 LEDs/m)
- DEDICATED 5 V power supply for the strip (60 white LEDs at full brightness ≈ 3.6 A: USB is not enough) — common grounds with the Teensy
- 300–470 Ω resistor in series on the data line, 1000 µF / 6.3 V capacitor across the strip terminals
- Library: https://github.com/PaulStoffregen/WS2812Serial
Complete Code
// Arc-en-ciel défilant, envoi par DMA non bloquant.
#include <WS2812Serial.h>
const uint32_t NUM_LEDS = 60;
byte drawingBuffer[NUM_LEDS * 3]; // RGB, un octet par canal
// Broche 1 sur T4 = TX de Serial1. Serial1/3/4/6/7/8 → jusqu'à 8 instances.
WS2812Serial myLEDs(NUM_LEDS, drawingBuffer, 1, 20, WS2812_SERIAL_DEFAULT);
void setup { myLEDs.begin; }
void loop {
static uint8_t hue = 0;
for (uint32_t i = 0; i < NUM_LEDS; i++) { // remplissage du buffer
uint8_t h = hue + (i * 256 / NUM_LEDS);
uint8_t r = (h < 85) ? 255 - h * 3 : (h < 170) ? (h - 85) * 3 : 0;
uint8_t g = (h < 85) ? h * 3 : (h < 170) ? 255 : 255 - (h - 170) * 3;
uint8_t b = (h < 85) ? 0 : (h < 170) ? 255 - (h - 85) * 3 : (h - 170) * 3;
drawingBuffer[i * 3 + 0] = g; // le WS2812 veut de l'ordre GRB
drawingBuffer[i * 3 + 1] = r;
drawingBuffer[i * 3 + 2] = b;
}
myLEDs.show(false); // false = retour immédiat : le DMA envoie
hue += 4; // l'animation tourne à pleine vitesse CPU
delay(20);
}
Expected Verification
The rainbow scrolls at 50 frames/s. Non-blocking test: add a counter Serial.println(millis) in loop — it scrolls normally WHILE the LED frames are being sent, proving that the DMA works on its own. For a massive installation (HUB75 RGB 32x16 panels up to 128x64), look instead at SmartMatrix + the SmartLED v5 shield; for strips driven at a 30 Hz video rate, OctoWS2811.
Common Errors
- Powering the strip from the Teensy's 5 V: a few LEDs work, but a whole strip causes the voltage to drop and restarts the board — use a dedicated external power supply, with grounds connected.
- Forgetting the GRB order: the buffer draws in RGB, but the WS2812 frame is GRB — red and green are swapped, this is the trap.
- Confusing the libraries: WS2812Serial occupies one UART per instance (max 8); OctoWS2811 uses dedicated GPIO pins with continuous DMA video refresh.
- Data on a pin that is not the TX of an eligible UART: check the pin/UART mapping (Serial1/3/4/6/7/8 on the 4.0).
- Frame cut off by blocking code elsewhere: with show(false), do not rewrite the drawingBuffer while the DMA is reading — wait or use double-buffering.
- Data cable too long without a resistor: random glitches on the first LEDs — the series resistor on the Teensy side is your friend.
Other tutorials for this board
- Premiers pas sur le Teensy 4.0 : Teensyduino, Loader et premier Blink
- GPIO et PWM sous 3,3 V : les règles d'or du Teensy 4.0
- Entrées analogiques et capteur de température interne : le ADC et ses limites
- Contrôleur MIDI USB : un potard qui joue du piano (MIDIx4/MIDIx16)
- Comprendre la mémoire : 2 Mo de flash, 1 Mo de RAM TCM/DMA, EEPROM émulée et LittleFS
- Deux ports USB simultanés : périphérique 480 Mbit/s ET hôte USB sur les pastilles
Code examples for this board
clignotante.inoArduinotouche-capacitive.inoArduinoanalogique-12-bits.inoArduinomidi-piano.inoArduinopwm-respiration.inoArduinoservo-angle.inoArduino