This report has been generated by Claud with my supervision. I'm not an expert with microcontrollers or Mozzi in anyway, so feel free to ignore the proposed "fix". Thanks!
Board: diymore ESP32-S3 DevKitC-1 N16R8
16MB Flash (QIO), 8MB PSRAM (OPI, AP_3v3)
Versions:
Platform: pioarduino espressif32 @ 53.3.13
framework-arduinoespressif32 @ 3.1.3 (IDF 5.3.0)
Mozzi @ 2.0.3+sha.a621383 (sensorium/Mozzi master)
PlatformIO + VSCode
Mozzi config:
cpp#define MOZZI_AUDIO_MODE MOZZI_OUTPUT_I2S_DAC
#define MOZZI_I2S_PIN_BCK 4
#define MOZZI_I2S_PIN_WS 5
#define MOZZI_I2S_PIN_DATA 6
#define MOZZI_AUDIO_RATE 32768
What happens
Build and upload succeed, but no audio. Serial output:
E (5) gdma: gdma_register_tx_event_callbacks(464): user context not in internal RAM
E (48) i2s_common: i2s_init_dma_intr(734): Register tx callback failed
E (48) i2s_std: i2s_channel_init_std_mode(236): initialize dma interrupt failed
E (50) i2s_common: i2s_channel_enable(1090): the channel has already enabled or not initialized
[OK] Mozzi started — 440 Hz sine on I2S
E (69) i2s_common: i2s_channel_write(1211): The channel is not enabled
What we tried
Debugging was done with help from Claude (Anthropic) and GitHub Copilot Chat.
Adding MOZZI_I2S_FORMAT_LSBJ and MOZZI_I2S_PORT I2S_NUM_0 — no effect
Downgrading to IDF4 — Mozzi v2 unconditionally includes driver/i2s_std.h which doesn't exist in IDF4, so that path is a dead end
Adding a manual i2s_channel_enable() call — doesn't help because the channel never initialised successfully in the first place
Root cause
With PSRAM enabled, malloc() on ESP32-S3 prefers external PSRAM by default. When Mozzi calls i2s_new_channel(), the IDF5 I2S driver internally allocates DMA structures via malloc() — and those land in PSRAM. The GDMA driver requires its context to be in internal DRAM, so it immediately rejects them. Everything downstream then fails silently, including startMozzi() which doesn't check the return values from the IDF5 init calls.
Suggested fix
In internal/MozziGuts_impl_ESP32.hpp, any allocations passed to GDMA should use:
cppheap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
instead of standard malloc(), to ensure they land in internal RAM regardless of PSRAM configuration.
This report has been generated by Claud with my supervision. I'm not an expert with microcontrollers or Mozzi in anyway, so feel free to ignore the proposed "fix". Thanks!
Board: diymore ESP32-S3 DevKitC-1 N16R8
16MB Flash (QIO), 8MB PSRAM (OPI, AP_3v3)
Versions:
Platform: pioarduino espressif32 @ 53.3.13
framework-arduinoespressif32 @ 3.1.3 (IDF 5.3.0)
Mozzi @ 2.0.3+sha.a621383 (sensorium/Mozzi master)
PlatformIO + VSCode
Mozzi config:
cpp#define MOZZI_AUDIO_MODE MOZZI_OUTPUT_I2S_DAC
#define MOZZI_I2S_PIN_BCK 4
#define MOZZI_I2S_PIN_WS 5
#define MOZZI_I2S_PIN_DATA 6
#define MOZZI_AUDIO_RATE 32768
What happens
Build and upload succeed, but no audio. Serial output:
E (5) gdma: gdma_register_tx_event_callbacks(464): user context not in internal RAM
E (48) i2s_common: i2s_init_dma_intr(734): Register tx callback failed
E (48) i2s_std: i2s_channel_init_std_mode(236): initialize dma interrupt failed
E (50) i2s_common: i2s_channel_enable(1090): the channel has already enabled or not initialized
[OK] Mozzi started — 440 Hz sine on I2S
E (69) i2s_common: i2s_channel_write(1211): The channel is not enabled
What we tried
Debugging was done with help from Claude (Anthropic) and GitHub Copilot Chat.
Adding MOZZI_I2S_FORMAT_LSBJ and MOZZI_I2S_PORT I2S_NUM_0 — no effect
Downgrading to IDF4 — Mozzi v2 unconditionally includes driver/i2s_std.h which doesn't exist in IDF4, so that path is a dead end
Adding a manual i2s_channel_enable() call — doesn't help because the channel never initialised successfully in the first place
Root cause
With PSRAM enabled, malloc() on ESP32-S3 prefers external PSRAM by default. When Mozzi calls i2s_new_channel(), the IDF5 I2S driver internally allocates DMA structures via malloc() — and those land in PSRAM. The GDMA driver requires its context to be in internal DRAM, so it immediately rejects them. Everything downstream then fails silently, including startMozzi() which doesn't check the return values from the IDF5 init calls.
Suggested fix
In internal/MozziGuts_impl_ESP32.hpp, any allocations passed to GDMA should use:
cppheap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
instead of standard malloc(), to ensure they land in internal RAM regardless of PSRAM configuration.