src/platforms/esp/32/ARCHITECTURE.md
The ESP32 platform implementation supports 9+ ESP32 variants (ESP32 classic, S2, S3, C3, C6, H2, P4, etc.) with 6 different LED output driver types, all organized into a clean hierarchical structure.
src/platforms/esp/32/
├── core/ # Core platform infrastructure
│ ├── fastled_esp32.h # Master aggregator (driver dispatcher)
│ ├── led_sysdefs_esp32.h # System defines
│ ├── fastpin_esp32.h # Pin mappings (all variants)
│ ├── fastspi_esp32.h # Hardware SPI abstraction
│ ├── clock_cycles.h # Timing utilities
│ ├── esp_log_control.h # Logging control
│ ├── delay.h # Xtensa delay
│ ├── delay_riscv.h # RISC-V delay
│ ├── delaycycles.h # Xtensa cycle-accurate delay
│ └── delaycycles_riscv.h # RISC-V cycle-accurate delay
│
├── drivers/ # LED output drivers (organized by type)
│ ├── rmt/ # RMT (Remote Control Module)
│ │ ├── clockless_rmt_esp32.h # RMT dispatcher
│ │ ├── rmt_4/ # ESP-IDF 4.x implementation (8 files)
│ │ └── rmt_5/ # ESP-IDF 5.x implementation (13 files)
│ │
│ ├── i2s/ # I2S parallel output
│ │ ├── clockless_i2s_esp32.h # I2S driver
│ │ ├── clockless_i2s_esp32s3.* # S3 variant
│ │ └── i2s_esp32dev.* # I2S helpers
│ │
│ ├── lcd_cam/ # LCD_CAM drivers (S3/P4 only)
│ │ ├── clockless_lcd_i80_esp32.* # I80 interface
│ │ ├── clockless_lcd_rgb_esp32.* # RGB interface
│ │ ├── lcd_driver_*.h # Helper files (6 files)
│ │ └── implementation_notes.md # Implementation docs
│ │
│ ├── parlio/ # Parallel IO (P4 only)
│ │ ├── clockless_parlio_esp32p4.* # PARLIO driver
│ │ └── parlio_driver*.h # Helper files
│ │
│ ├── spi/ # Hardware SPI (clocked LEDs)
│ │ ├── spi_hw_1_esp32.cpp # 1-lane SPI
│ │ ├── spi_hw_2_esp32.cpp # 2-lane SPI
│ │ ├── spi_hw_4_esp32.cpp # 4-lane SPI
│ │ ├── spi_hw_8_esp32.cpp # 8-lane SPI (P4 only)
│ │ ├── spi_platform_esp32.cpp # Platform abstraction
│ │ ├── spi_output_template.h # SPI output template
│ │ └── spi_device_proxy.h # SPI device proxy
│ │
│ └── spi_ws2812/ # Clockless SPI (WS2812 over SPI)
│ ├── clockless_spi_esp32.h # WS2812-over-SPI driver
│ └── strip_spi.* # SPI strip implementation
│
├── interrupts/ # Architecture-specific ISRs
│ ├── xtensa_lx6.hpp # ESP32 classic
│ ├── xtensa_lx7.hpp # ESP32-S2/S3
│ ├── riscv.hpp # ESP32-C3/C6/H2/P4
│ ├── riscv.cpp # RISC-V implementation
│ └── INVESTIGATE.md # Research notes
│
├── audio/ # Audio processing subsystem
├── ota/ # OTA update support
│
└── [Root-level files] # Platform abstraction
├── interrupt.h # Interrupt control interface
├── interrupt.cpp # Interrupt control implementation
├── isr_esp32.cpp # ISR API implementation (IDF 5.0+)
└── clockless_block_esp32.h # Experimental (not in production)
The ESP32 platform uses a dispatcher pattern to select the appropriate LED output driver at compile time:
User Code (Arduino/Platform IO sketch)
↓
FastLED.h
↓
platforms/esp/32/core/fastled_esp32.h (Master Aggregator)
↓
├─→ drivers/rmt/clockless_rmt_esp32.h (Default driver)
│ ↓
│ ├─→ rmt_4/ (ESP-IDF 4.x - legacy)
│ │ ├── idf4_clockless_rmt_esp32.h (ChannelManager-based)
│ │ └── channel_engine_rmt4.h / channel_engine_rmt4.cpp
│ │
│ └─→ rmt_5/ (ESP-IDF 5.x - default, DMA-backed)
│ ├── idf5_clockless.h (ChannelManager-based)
│ ├── idf5_rmt.h / idf5_rmt.cpp
│ ├── strip_rmt.h / strip_rmt.cpp
│ └── rmt5_* worker pool implementation (7 files)
│
├─→ drivers/i2s/clockless_i2s_esp32.h (Parallel output)
│ ↓
│ ├─→ clockless_i2s_esp32s3.h (ESP32-S3 variant)
│ └─→ i2s_esp32dev.h (ESP32 classic)
│
├─→ drivers/lcd_cam/clockless_lcd_i80_esp32.h (S3/P4 high-bandwidth)
│ ↓
│ └─→ lcd_driver_i80.h / lcd_driver_i80_impl.h
│
├─→ drivers/lcd_cam/clockless_lcd_rgb_esp32.h (P4 RGB interface)
│ ↓
│ └─→ lcd_driver_rgb.h / lcd_driver_rgb_impl.h
│
├─→ drivers/parlio/clockless_parlio_esp32p4.h (P4 only)
│ ↓
│ └─→ parlio_engine.h / parlio_engine.cpp.hpp
│
└─→ drivers/spi_ws2812/clockless_spi_esp32.h (WS2812 over SPI)
↓
└─→ strip_spi.h / strip_spi.cpp
The ESP32 platform supports 9+ chip variants using inline conditional compilation rather than separate directories:
90% of code is target-agnostic - Most driver code works identically across all ESP32 variants. Only pin definitions, interrupt handlers, and peripheral availability differ.
Example: Pin mappings (core/fastpin_esp32.h):
#if CONFIG_IDF_TARGET_ESP32
// ESP32 classic pin definitions
#define NUM_DIGITAL_PINS 40
#define FASTLED_HAS_CLOCKLESS 1
#elif CONFIG_IDF_TARGET_ESP32S3
// ESP32-S3 pin definitions
#define NUM_DIGITAL_PINS 49
#define FASTLED_HAS_CLOCKLESS 1
#define FASTLED_ESP32_S3_USB_JTAG_WORKAROUND 1 // S3-specific
#elif CONFIG_IDF_TARGET_ESP32C3
// ESP32-C3 pin definitions (RISC-V)
#define NUM_DIGITAL_PINS 22
#define FASTLED_HAS_CLOCKLESS 1
#define FASTLED_RISCV 1
// ... etc for 9+ targets
#endif
Architectural differences (Xtensa vs RISC-V) are handled in two ways:
Timing functions: Separate files for Xtensa and RISC-V
core/delay.h / core/delay_riscv.hcore/delaycycles.h / core/delaycycles_riscv.hInterrupt handlers: Dedicated interrupts/ directory
interrupts/xtensa_lx6.hpp - ESP32 classic (LX6 core)interrupts/xtensa_lx7.hpp - ESP32-S2/S3 (LX7 core)interrupts/riscv.hpp - ESP32-C3/C6/H2/P4 (RISC-V)The RMT driver has completely separate implementations for ESP-IDF 4.x vs 5.x due to incompatible APIs:
// drivers/rmt/clockless_rmt_esp32.h
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
// ESP-IDF 4.x path
#include "rmt_4/idf4_clockless_rmt_esp32.h"
#else
// ESP-IDF 5.x path
#include "rmt_5/idf5_clockless.h" // ChannelManager-based
#endif
Incompatible APIs: ESP-IDF 5.x completely redesigned the RMT peripheral API. The two implementations cannot coexist.
Different architectures:
led_strip driverCannot be merged: Attempting to unify them would create unmaintainable #ifdef spaghetti.
Drivers are selected via preprocessor macros, evaluated in core/fastled_esp32.h:
// Priority order (first match wins):
#if defined(FASTLED_ESP32_I2S) && FASTLED_ESP32_I2S
#include "../drivers/i2s/clockless_i2s_esp32.h" // I2S parallel
#elif defined(FASTLED_ESP32_LCD_I80) && FASTLED_ESP32_LCD_I80
#include "../drivers/lcd_cam/clockless_lcd_i80_esp32.h" // LCD I80 (S3/P4)
#elif defined(FASTLED_ESP32_LCD_RGB) && FASTLED_ESP32_LCD_RGB
#include "../drivers/lcd_cam/clockless_lcd_rgb_esp32.h" // LCD RGB (P4)
#elif defined(FASTLED_ESP32_PARLIO) && FASTLED_ESP32_PARLIO
#include "../drivers/parlio/clockless_parlio_esp32p4.h" // PARLIO (P4)
#elif defined(FASTLED_ESP32_HAS_CLOCKLESS_SPI)
#include "../drivers/spi_ws2812/clockless_spi_esp32.h" // Clockless SPI
#elif defined(FASTLED_ESP32_HAS_RMT)
#include "../drivers/rmt/clockless_rmt_esp32.h" // RMT (default)
#endif
Some features are detected at runtime:
The ESP32 platform has two completely different SPI subsystems:
drivers/spi/)Purpose: Drive clocked LED chipsets (APA102, SK9822, LPD8806, etc.)
Key features:
Files:
spi_hw_1_esp32.cpp - 1-lane SPIspi_hw_2_esp32.cpp - 2-lane SPI (dual)spi_hw_4_esp32.cpp - 4-lane SPI (quad)spi_hw_8_esp32.cpp - 8-lane SPI (octal, ESP32-P4 only)spi_platform_esp32.cpp - Platform abstractionspi_output_template.h - Template for SPI outputspi_device_proxy.h - SPI device proxyWhen to use: LEDs with clock lines (APA102, SK9822, LPD8806, etc.)
drivers/spi_ws2812/)Purpose: Emulate WS2812 timing protocol using SPI peripheral as a timing hack
Key features:
Files:
clockless_spi_esp32.h - WS2812-over-SPI driverstrip_spi.h / strip_spi.cpp - SPI strip implementationWhen to use: WS2812-style LEDs when RMT channels are exhausted
Limitations: Fixed timing (cannot support SK6812, APA106, etc. due to SPI constraints)
Decision: Use inline #ifdef CONFIG_IDF_TARGET_* within files rather than separate directories per target.
Rationale:
When might this change?: If target-specific code exceeds 100 lines per file, consider extracting to target-specific files.
Decision: Handle Arduino vs ESP-IDF differences inline with minimal #ifdef ARDUINO.
Rationale:
#include <Arduino.h> vs #include "esp_system.h")When might this change?: If Arduino-specific code becomes substantial (e.g., >50 lines per file).
Decision: Completely separate implementations for ESP-IDF 4.x and 5.x.
Rationale:
Not subject to change: This separation is permanent due to API incompatibility.
Decision: RMT5 V2 uses persistent worker pool + ephemeral controllers.
Rationale:
FastLED.show() callsFiles:
rmt5_worker_base.h - Base worker interfacermt5_worker.h / rmt5_worker.cpp - Persistent workerrmt5_worker_oneshot.h / rmt5_worker_oneshot.cpp - One-shot workerrmt5_worker_pool.h / rmt5_worker_pool.cpp - Worker pool managerrmt5_controller_lowlevel.h / rmt5_controller_lowlevel.cpp - ControllerDecision: Lightweight logging via core/esp_log_control.h to avoid heavy vfprintf dependency.
Rationale:
esp_log pulls in 10-20KB of printf/vfprintf codeSKETCH_HAS_LOTS_OF_MEMORY is trueFASTLED_ESP32_MINIMAL_ERROR_HANDLING skips logging entirelyDecision: Move architecture-specific interrupt handlers to interrupts/ directory.
Rationale:
The LCD_CAM driver family includes two variants using different peripherals:
LCD_I80_vs_RGB_MIGRATION_GUIDE.md for migration detailsTotal: ~71 files organized into logical hierarchy
#include <FastLED.h> // Top-level include (finds ESP32 automatically)
core/fastled_esp32.h)#include "../drivers/rmt/clockless_rmt_esp32.h" // RMT dispatcher
#include "../drivers/i2s/clockless_i2s_esp32.h" // I2S driver
#include "../drivers/spi_ws2812/clockless_spi_esp32.h" // Clockless SPI
drivers/rmt/clockless_rmt_esp32.h)#include "rmt_4/idf4_clockless_rmt_esp32.h" // Relative (same parent)
#include "rmt_5/idf5_clockless.h" // Relative (same parent)
src/fastspi.h)#include "platforms/esp/32/drivers/spi/spi_device_proxy.h" // Absolute from src/
#include "platforms/esp/32/drivers/spi/spi_output_template.h"
#include "platforms/esp/32/fastled_esp32.h" // ❌ Old path
#include "platforms/esp/32/clockless_rmt_esp32.h" // ❌ Old path
#include "platforms/esp/32/core/fastled_esp32.h" // ✅ New path
#include "platforms/esp/32/drivers/rmt/clockless_rmt_esp32.h" // ✅ New path
Migration: All includes were updated during the refactoring. User code remains unchanged (uses #include <FastLED.h>).
drivers/common/src/platforms/esp/32/README.md - Driver selection, build flagssrc/platforms/esp/32/drivers/rmt/rmt_5/RMT_RESEARCH.md - RMT5 internalssrc/platforms/esp/32/drivers/lcd_cam/implementation_notes.md - LCD_CAM detailssrc/platforms/esp/32/drivers/lcd_cam/RGB_LCD_RESEARCH.md - RGB LCD peripheral analysissrc/platforms/esp/32/drivers/lcd_cam/LCD_I80_vs_RGB_MIGRATION_GUIDE.md - I80→RGB migrationsrc/platforms/esp/32/drivers/lcd_cam/LCD_RGB_RELEASE_NOTES.md - Feature announcementsrc/platforms/esp/32/ESP32-P4_PARLIO_DESIGN.md - PARLIO architecturesrc/platforms/esp/32/interrupts/INVESTIGATE.md - ISR implementation notesThe ESP32 platform architecture uses a hierarchical structure with:
This organization makes it straightforward for developers to:
Version: 1.1 Last Updated: 2025-11-05 Status: Complete (Post-Refactoring + LCD_RGB Documentation)