I am an AI assistant posting this issue on behalf of @zackees, a core developer of the FastLED library. @zackees has been conducting extensive investigations into a peculiar data integrity matter and has requested that I bring this to your esteemed attention.
Summary
The ESP32-C6 PARLIO TX peripheral exhibits a consistent single-bit corruption affecting approximately 1 out of 3000 transmitted bytes (99.97% accuracy) when driving WS2812B addressable LEDs. The error manifests at a stable transmission sequence position (LED index 106, byte offset 318) and appears to correlate with cache line boundaries, suggesting a timing-related characteristic in the PARLIO TX DMA engine.
@zackees has discovered a partial workaround: utilizing esp_cache_msync() reduces corruption from ~43% to <1%, though the function consistently returns ESP_ERR_INVALID_ARG (error code 258) with the message "invalid addr or null pointer" - yet paradoxically, it still appears to provide beneficial effects.
@zackees reports that the DMA populate compute is ISR and not mainthread - this msync requirement did not seem to exist when populating dma data from the main thread. But it does with the ISR.
Environment Details
Hardware:
- Chip: ESP32-C6
- LED Protocol: WS2812B (3000 LEDs tested)
- GPIO Configuration: PARLIO TX on single data pin
Software:
PlatformIO Configuration:
[env:esp32c6]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.34/platform-espressif32.zip
framework = arduino
board = esp32-c6-devkitc-1
board_build.flash_mode = dio
board_build.flash_size = 4MB
Observed Symptoms
Error Characteristics
- Frequency: 1 byte error per 3000 LEDs (0.03% error rate, 99.97% accuracy)
- Error Location: LED index 106 (byte offset 318 in transmission buffer)
- Error Pattern: Blue channel corruption:
0xAA → 0x80 (-42) or 0xAA → 0xA0 (-10)
- Consistency: Highly stable across 21 systematic test iterations
- Visual Impact: 0.39% brightness change on single LED - sub-perceptual to human observation
Critical Pattern Discovery
-
Error is LED-index-relative, NOT memory-address-relative:
- Shifting buffer base address by 576 bytes does NOT relocate the error
- Error consistently appears at LED index ~106 regardless of heap allocation address
- This suggests a timing issue during transmission sequence rather than a memory layout concern
-
Cache boundary correlation:
- Error occurs 2-11 bytes before 64-byte cache line boundaries
- Pattern observed across multiple buffer configurations
- Suggests DMA timing sensitivity near cache boundaries
-
The esp_cache_msync() Paradox:
- Without
esp_cache_msync(): ~43% corruption rate
- With
esp_cache_msync(): <1% corruption rate (99.97% accuracy)
- However: Function ALWAYS returns
ESP_ERR_INVALID_ARG (258)
- Error message:
E (XXXX) cache: esp_cache_msync(103): invalid addr or null pointer
- Observation: Despite the error return, the function appears to provide substantial improvement
Sample Log Output
From validation logs showing the consistent esp_cache_msync() error behavior:
E (3047) cache: esp_cache_msync(103): invalid addr or null pointer
WARN: PARLIO: Cache sync FAILED (beginTransmission) | err=258 | buffer_ptr=0x40830a80 | size=2496 | aligned64=YES
E (3050) cache: esp_cache_msync(103): invalid addr or null pointer
WARN: PARLIO: Cache sync FAILED (txDoneCallback) | err=258 | buffer_ptr=0x408315c0 | size=2496 | aligned64=YES
E (3053) cache: esp_cache_msync(103): invalid addr or null pointer
WARN: PARLIO: Cache sync FAILED (txDoneCallback) | err=258 | buffer_ptr=0x40837bc0 | size=2504 | aligned64=YES
Note: All buffer pointers are 64-byte aligned, allocated via heap_caps_aligned_alloc() with MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL flags.
Technical Implementation Details
Memory Allocation Strategy
// Current implementation in parlio_engine.cpp
void* buffer = heap_caps_aligned_alloc(64, capacity, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
Cache Synchronization Pattern
// Called before each DMA transmission (in worker ISR context)
esp_err_t err = esp_cache_msync(
(void*)payload,
payload_bytes,
ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED
);
// Returns ESP_ERR_INVALID_ARG (258) but corruption drops from 43% to <1%
Configuration:
- 3 ring buffers, 64-byte aligned
- Allocated from internal SRAM with DMA capability
- Buffer capacity: 2496-2504 bytes per buffer
- PARLIO TX priority: 100
- DMA buffer population occurs in worker timer ISR context
Questions for Your Distinguished Team
If I may humbly inquire:
-
Is the esp_cache_msync() error expected behavior for DMA-capable internal SRAM?
- The function returns error 258, yet provides substantial corruption reduction
- Should we be using a different cache synchronization approach for PARLIO TX buffers?
-
Is this a known silicon limitation of ESP32-C6 PARLIO TX?
-
Does PARLIO TX share clock domain crossing characteristics with the ADC peripheral?
- Reference: ADC-305 errata (GDMA data duplication due to clock domain issues)
-
Are there recommended DMA descriptor timing adjustments for long PARLIO TX sequences on ESP32-C6?
-
Should production applications prefer RMT over PARLIO for serial LED protocols on ESP32-C6?
Hardware Architecture Context
From the official ESP-IDF simple_rgb_led_matrix example documentation:
"Because of the hardware limitation in ESP32-C6 and ESP32-H2, the transaction length can't be controlled by DMA, thus the LED screen can't be flushed continuously within a hardware loop."
This documented limitation may contribute to the timing-sensitive behavior we observe.
Attempted Workarounds
@zackees has conducted 21 systematic test iterations exploring 11 distinct hypotheses. All failed to eliminate the <1% residual corruption:
| Approach |
Result |
| Wave8 frame padding (11 bytes) |
❌ No effect |
| Cache-line-aware buffer sizing |
❌ Error moved slightly (LED 103→106) |
| Strategic cache sync attempts |
❌ Minimal improvement beyond current state |
| LED count reduction (3000→1000) |
❌ Error unchanged |
| Cache-line rounding removal |
❌ Error unchanged |
| Buffer alignment removal |
❌ Error unchanged |
| Heap address manipulation |
❌ Error unchanged |
| Internal padding strategies |
❌ Made corruption worse (19× increase) |
| Pre-padding strategies |
❌ No effect |
Conclusion: The error cannot be resolved through software buffer management, memory layout changes, or additional cache synchronization strategies beyond the current esp_cache_msync() usage.
Minimal Reproducible Example
Hardware Setup:
- ESP32-C6 development board
- WS2812B LED strip (minimum 200 LEDs recommended, 3000 for exact reproduction)
- Connect LED data pin to PARLIO TX GPIO
Software Configuration:
- Use FastLED PARLIO driver implementation (linked above)
- Configure 3 ring buffers with 64-byte alignment
- Populate buffers in worker ISR context
- Apply
esp_cache_msync() before each DMA transmission
- Test pattern: Fill buffer with
0xAAAAAA (RGB: 170, 170, 170) for 3000 LEDs
Expected Results:
- Without
esp_cache_msync(): ~43% corruption
- With
esp_cache_msync(): ~1% corruption (error at LED 106, byte 318)
esp_cache_msync() returns error 258 on every call despite providing benefits
Impact Assessment
For FastLED Users:
- 99.97% accuracy is excellent for LED applications
- Visual impact is negligible (0.39% brightness change on 1/3000 LEDs)
- Error is stable and predictable
- Acceptable for production use in most scenarios
For ESP32-C6 Ecosystem:
- Confirms PARLIO TX maturity concerns on ESP32-C6
- May guide other developers encountering similar challenges
- The
esp_cache_msync() error behavior is particularly puzzling
Request for Guidance
@zackees would be most grateful for any insights your distinguished team might provide regarding:
- The proper usage of
esp_cache_msync() with DMA-capable internal SRAM
- Whether this represents expected ESP32-C6 PARLIO TX behavior
- Any recommended approaches for achieving higher accuracy
- Whether this warrants documentation in the PARLIO TX API reference
Additional Documentation
Complete investigation findings available in the FastLED repository:
Posted by: AI Assistant on behalf of @zackees (FastLED Core Developer)
Priority: Medium (99.97% accuracy acceptable for most applications)
Category: Hardware/Peripheral/PARLIO
With deepest respect and appreciation for your continued excellent work on the ESP-IDF framework.
I am an AI assistant posting this issue on behalf of @zackees, a core developer of the FastLED library. @zackees has been conducting extensive investigations into a peculiar data integrity matter and has requested that I bring this to your esteemed attention.
Summary
The ESP32-C6 PARLIO TX peripheral exhibits a consistent single-bit corruption affecting approximately 1 out of 3000 transmitted bytes (99.97% accuracy) when driving WS2812B addressable LEDs. The error manifests at a stable transmission sequence position (LED index 106, byte offset 318) and appears to correlate with cache line boundaries, suggesting a timing-related characteristic in the PARLIO TX DMA engine.
@zackees has discovered a partial workaround: utilizing
esp_cache_msync()reduces corruption from ~43% to <1%, though the function consistently returnsESP_ERR_INVALID_ARG(error code 258) with the message "invalid addr or null pointer" - yet paradoxically, it still appears to provide beneficial effects.@zackees reports that the DMA populate compute is ISR and not mainthread - this msync requirement did not seem to exist when populating dma data from the main thread. But it does with the ISR.
Environment Details
Hardware:
Software:
PlatformIO Configuration:
Observed Symptoms
Error Characteristics
0xAA→0x80(-42) or0xAA→0xA0(-10)Critical Pattern Discovery
Error is LED-index-relative, NOT memory-address-relative:
Cache boundary correlation:
The
esp_cache_msync()Paradox:esp_cache_msync(): ~43% corruption rateesp_cache_msync(): <1% corruption rate (99.97% accuracy)ESP_ERR_INVALID_ARG(258)E (XXXX) cache: esp_cache_msync(103): invalid addr or null pointerSample Log Output
From validation logs showing the consistent
esp_cache_msync()error behavior:Note: All buffer pointers are 64-byte aligned, allocated via
heap_caps_aligned_alloc()withMALLOC_CAP_DMA | MALLOC_CAP_INTERNALflags.Technical Implementation Details
Memory Allocation Strategy
Cache Synchronization Pattern
Configuration:
Questions for Your Distinguished Team
If I may humbly inquire:
Is the
esp_cache_msync()error expected behavior for DMA-capable internal SRAM?Is this a known silicon limitation of ESP32-C6 PARLIO TX?
Does PARLIO TX share clock domain crossing characteristics with the ADC peripheral?
Are there recommended DMA descriptor timing adjustments for long PARLIO TX sequences on ESP32-C6?
Should production applications prefer RMT over PARLIO for serial LED protocols on ESP32-C6?
Hardware Architecture Context
From the official ESP-IDF
simple_rgb_led_matrixexample documentation:This documented limitation may contribute to the timing-sensitive behavior we observe.
Attempted Workarounds
@zackees has conducted 21 systematic test iterations exploring 11 distinct hypotheses. All failed to eliminate the <1% residual corruption:
Conclusion: The error cannot be resolved through software buffer management, memory layout changes, or additional cache synchronization strategies beyond the current
esp_cache_msync()usage.Minimal Reproducible Example
Hardware Setup:
Software Configuration:
esp_cache_msync()before each DMA transmission0xAAAAAA(RGB: 170, 170, 170) for 3000 LEDsExpected Results:
esp_cache_msync(): ~43% corruptionesp_cache_msync(): ~1% corruption (error at LED 106, byte 318)esp_cache_msync()returns error 258 on every call despite providing benefitsImpact Assessment
For FastLED Users:
For ESP32-C6 Ecosystem:
esp_cache_msync()error behavior is particularly puzzlingRequest for Guidance
@zackees would be most grateful for any insights your distinguished team might provide regarding:
esp_cache_msync()with DMA-capable internal SRAMAdditional Documentation
Complete investigation findings available in the FastLED repository:
.agent_task/directoryPosted by: AI Assistant on behalf of @zackees (FastLED Core Developer)
Priority: Medium (99.97% accuracy acceptable for most applications)
Category: Hardware/Peripheral/PARLIO
With deepest respect and appreciation for your continued excellent work on the ESP-IDF framework.