Integration log for FastLED
Integration Log
The branch with the this driver is located at
https://github.com/FastLED/FastLED/tree/esp32s3-i2s
How to test in FastLED
clone fastled, switch to the esp32s3-i2s branch and open up the repo in VSCode
git clone https://github.com/fastled/fastled
cd fastled
git checkout esp32s3-i2s
./install # Optional, but it provides VSCode with intellisense definitions
code . # launch vscode
VSCODE: Click the upload button (the esp32s3-i2s branch already set to i2s demo for esp32s3)
the example will now load
First Pass Results
First pass required a fix. This has been applied, see below.
FastLED compiles with IDF 5.4 so it might be newer than you are on.
Manually tested yet? No.
ESP32-S3 I2S Compilation Issues and Fixes
Issue Description
The ESP32-S3 Blink example compilation was failing with the following error:
src/third_party/yves/I2SClockLessLedDriver/src/I2SClockLessLedDriver.h:685:35: error: 'gdma_channel_alloc_config_t::<unnamed struct>' has no non-static data member named 'isr_cache_safe'
Root Cause
The newer ESP-IDF version (used by the platform) has removed the isr_cache_safe field from the gdma_channel_alloc_config_t structure. The third-party I2S driver code was still trying to initialize this deprecated field.
Fix Applied
File: src/third_party/yves/I2SClockLessLedDriver/src/I2SClockLessLedDriver.h
Line: 685
Before:
gdma_channel_alloc_config_t dma_chan_config = {
.sibling_chan = NULL,
.direction = GDMA_CHANNEL_DIRECTION_TX,
.flags = {
.reserve_sibling = 0,
.isr_cache_safe= true}};
After:
gdma_channel_alloc_config_t dma_chan_config = {
.sibling_chan = NULL,
.direction = GDMA_CHANNEL_DIRECTION_TX,
.flags = {
.reserve_sibling = 0}};
Result
After removing the unsupported isr_cache_safe field, the ESP32-S3 Blink example compiles successfully. The compilation completes with only deprecation warnings (expected with newer ESP-IDF versions) but no errors.
Additional Warnings (Non-blocking)
The following warnings remain but do not prevent compilation:
- Deprecated
driver/periph_ctrl.hheader usage MINmacro redefinition warning- Deprecated
gdma_new_channelfunction (should usegdma_new_ahb_channelorgdma_new_axi_channel) - Narrowing conversion warning in ISR handler
These warnings indicate areas for future improvement but do not block current functionality.
I've got a WS2812 matrix sitting around and an S3 so I can test this locally on that board.
I'm assuming I can do esp32dev, what about the wemos boards? Sorry if this is already in the readme.
FYI
https://github.com/FastLED/FastLED/blob/master/src/fl/rectangular_draw_buffer.h
This could be handy to upstream
🚨 Critical issue: Cannot reflash XIAO ESP32S3 after initial flash.
-
Sketch: https://github.com/FastLED/FastLED/blob/esp32s3-i2s/examples/Esp32S3I2SDemo/Esp32S3I2SDemo.h#L204
-
Two units tested
-
Two units bricked and unrecoverable
Attempts to recover:
- Hold down the reset button until
Looking for upload port...appears, then release - Hold down the reset & boot button until
Looking for upload port...appears, then release
Bricked Devices
Windows gives the error message mentioned above. When I plug/unplug devices from my Windows box then windows is will indicate that the device is not functioning correctly after about 6 seconds with the error message above.
⚠️ Stdout not functioning
The second attempt recompiled the test program https://github.com/FastLED/FastLED/blob/d85e74c921ce12e6bf1ff47eaf92a1698bb036d7/examples/Esp32S3I2SDemo/Esp32S3I2SDemo.h#L204 with a print test using the EVERY_N_MILLISECONDS(1000) macro
Result: Could not connect to stdout port.
* Executing task: C:\Users\niteris\.platformio\penv\Scripts\platformio.exe run --target upload
Processing dev (board: seeed_xiao_esp32s3; platform: https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip; framework: arduino)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CCACHE is not available. Skipping CCACHE configuration.
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/seeed_xiao_esp32s3.html
PLATFORM: Espressif 32 (54.3.20) > Seeed Studio XIAO ESP32S3
HARDWARE: ESP32S3 240MHz, 320KB RAM, 8MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, esp-bridge, esp-builtin, esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES:
- framework-arduinoespressif32 @ 3.2.0
- framework-arduinoespressif32-libs @ 5.4.0+sha.2f7dcd862a
- tool-clangtidy @ 1.190100.0 (19.1.0)
- tool-esptoolpy @ 4.8.9
- tool-mkfatfs @ 2.0.1
- tool-mklittlefs @ 3.2.0
- tool-mkspiffs @ 2.230.0 (2.30)
- tool-openocd-esp32 @ 2.1100.20220706 (11.0)
- tool-riscv32-esp-elf-gdb @ 14.2.0+20240403
- tool-xtensa-esp-elf-gdb @ 14.2.0+20240403
- toolchain-riscv32-esp @ 14.2.0+20241119
- toolchain-xtensa-esp-elf @ 14.2.0+20241119
Converting dev.ino
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 42 compatible libraries
Scanning dependencies...
Dependency Graph
|-- FastLED @ 3.10.2
Building in debug mode
Compiling .pio\build\dev\src\dev.ino.cpp.o
Retrieving maximum program size .pio\build\dev\firmware.elf
Checking size .pio\build\dev\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM: [= ] 11.0% (used 36008 bytes from 327680 bytes)
Flash: [= ] 11.4% (used 358974 bytes from 3145728 bytes)
Configuring upload protocol...
AVAILABLE: cmsis-dap, esp-bridge, esp-builtin, esp-prog, espota, esptool, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa
CURRENT: upload_protocol = esptool
Looking for upload port...
Auto-detected: COM4
Uploading .pio\build\dev\firmware.bin
esptool.py v4.8.9
Serial port COM4
A fatal error occurred: Could not open COM4, the port is busy or doesn't exist.
(could not open port 'COM4': OSError(22, 'The semaphore timeout period has expired.', None, 121))
#ifdef ESP32
/// The Yves ESP32_S3 I2S driver is a driver that uses the I2S peripheral on the ESP32-S3 to drive leds.
/// Originally from: https://github.com/hpwit/I2SClockLessLedDriveresp32s3
///
///
/// This is an advanced driver. It has certain ramifications.
/// - Once flashed, the ESP32-S3 might NOT want to be reprogrammed again. To get around
/// this hold the reset button and release when the flash tool is looking for an
/// an upload port.
/// - Put a delay in the setup function. This is to make it easier to flash the device during developement.
/// - Serial output will mess up the DMA controller. I'm not sure why this is happening
/// but just be aware of it. If your device suddenly stops working, remove the printfs and see if that fixes the problem.
///
/// Is RGBW supported? Yes.
///
/// Is Overclocking supported? Yes. Use this to bend the timeings to support other WS281X variants. Fun fact, just overclock the
/// chipset until the LED starts working.
///
/// What about the new WS2812-5VB leds? Yes, they have 250us timing.
///
/// Why use this?
/// Raw YVes driver needs a perfect parallel rectacngle buffer for operation. In this code we've provided FastLED
/// type bindings.
///
// ArduinoIDE
// Should already be enabled.
//
// PLATFORMIO BUILD FLAGS:
// Define your platformio.ini like so:
//
// PlatformIO
// [env:esp32s3]
// platform = https://github.com/pioarduino/platform-espressif32/releases/download/54.03.20/platform-espressif32.zip
// framework = arduino
// board = seeed_xiao_esp32s3
#define FASTLED_USES_ESP32S3_I2S // Must define this before including FastLED.h
#include <Arduino.h>
#include "FastLED.h"
#include "fl/assert.h"
#define NUMSTRIPS 16
#define NUM_LEDS_PER_STRIP 256
#define NUM_LEDS (NUM_LEDS_PER_STRIP * NUMSTRIPS)
// Note that you can use less strips than this.
#define EXAMPLE_PIN_NUM_DATA0 19 // B0
#define EXAMPLE_PIN_NUM_DATA1 45 // B1
#define EXAMPLE_PIN_NUM_DATA2 21 // B2
#define EXAMPLE_PIN_NUM_DATA3 6 // B3
#define EXAMPLE_PIN_NUM_DATA4 7 // B4
#define EXAMPLE_PIN_NUM_DATA5 8 // G0
#define EXAMPLE_PIN_NUM_DATA6 9 // G1
#define EXAMPLE_PIN_NUM_DATA7 10 // G2
#define EXAMPLE_PIN_NUM_DATA8 11 // G3
#define EXAMPLE_PIN_NUM_DATA9 12 // G4
#define EXAMPLE_PIN_NUM_DATA10 13 // G5
#define EXAMPLE_PIN_NUM_DATA11 14 // R0
#define EXAMPLE_PIN_NUM_DATA12 15 // R1
#define EXAMPLE_PIN_NUM_DATA13 16 // R2
#define EXAMPLE_PIN_NUM_DATA14 17 // R3
#define EXAMPLE_PIN_NUM_DATA15 18 // R4
// Users say you can use a lot less strips. Experiment around and find out!
// Please comment at reddit.com/r/fastled and let us know if you have problems.
// Or send us a picture of your Triumps!
int PINS[] = {
EXAMPLE_PIN_NUM_DATA0,
EXAMPLE_PIN_NUM_DATA1,
EXAMPLE_PIN_NUM_DATA2,
EXAMPLE_PIN_NUM_DATA3,
EXAMPLE_PIN_NUM_DATA4,
EXAMPLE_PIN_NUM_DATA5,
EXAMPLE_PIN_NUM_DATA6,
EXAMPLE_PIN_NUM_DATA7,
EXAMPLE_PIN_NUM_DATA8,
EXAMPLE_PIN_NUM_DATA9,
EXAMPLE_PIN_NUM_DATA10,
EXAMPLE_PIN_NUM_DATA11,
EXAMPLE_PIN_NUM_DATA12,
EXAMPLE_PIN_NUM_DATA13,
EXAMPLE_PIN_NUM_DATA14,
EXAMPLE_PIN_NUM_DATA15
};
CRGB leds[NUM_LEDS];
void setup_i2s() {
// Note, in this case we are using contingious memory for the leds. But this is not required.
// Each strip can be a different size and the FastLED api will upscale the smaller strips to the largest strip.
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA0, GRB>(
leds + (0 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA1, GRB>(
leds + (1 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA2, GRB>(
leds + (2 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA3, GRB>(
leds + (3 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA4, GRB>(
leds + (4 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA5, GRB>(
leds + (5 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA6, GRB>(
leds + (6 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA7, GRB>(
leds + (7 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA8, GRB>(
leds + (8 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA9, GRB>(
leds + (9 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA10, GRB>(
leds + (10 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA11, GRB>(
leds + (11 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA12, GRB>(
leds + (12 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA13, GRB>(
leds + (13 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA14, GRB>(
leds + (14 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
FastLED.addLeds<WS2812, EXAMPLE_PIN_NUM_DATA15, GRB>(
leds + (15 * NUM_LEDS_PER_STRIP), NUM_LEDS_PER_STRIP
);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(57600);
// This is used so that you can see if PSRAM is enabled. If not, we will crash in setup() or in loop().
log_d("Total heap: %d", ESP.getHeapSize());
log_d("Free heap: %d", ESP.getFreeHeap());
log_d("Total PSRAM: %d", ESP.getPsramSize()); // If this prints out 0, then PSRAM is not enabled.
log_d("Free PSRAM: %d", ESP.getFreePsram());
log_d("waiting 6 seconds before startup");
delay(6000); // The long reset time here is to make it easier to flash the device during the development process.
setup_i2s();
FastLED.setBrightness(16);
}
void fill_rainbow(CRGB* all_leds) {
static int s_offset = 0;
for (int j = 0; j < NUMSTRIPS; j++) {
for (int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
int idx = (i + s_offset) % NUM_LEDS_PER_STRIP + NUM_LEDS_PER_STRIP * j;
all_leds[idx] = CHSV(i, 255, 255);
}
}
s_offset++;
}
void loop() {
fill_rainbow(leds);
FastLED.show();
}
#else // ESP32
// Non-ESP32 platform - provide minimal example for compilation testing
#include "FastLED.h"
#define NUM_LEDS 16
#define DATA_PIN 3
CRGB leds[NUM_LEDS];
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
}
void loop() {
fill_rainbow(leds, NUM_LEDS, 0, 7);
FastLED.show();
delay(50);
EVERY_N_MILLISECONDS(1000) {
Serial.println("Stdout works.");
}
}
#endif // ESP32