Summary
On ESP-IDF v6.1, M5.begin() (or any M5GFX::init()) panics during SPI bus
initialisation and the board boot-loops. The cause is that IDF 6.1 added a new field to
spi_bus_config_t, and lgfx::v1::spi::init() fills that struct with memset(&buscfg, ~0u, ...),
so the new field is left as 0xFFFFFFFF.
IDF 6.0.x and 5.x do not have the field, which is why the existing build matrix does not show this.
Environment
|
|
| ESP-IDF |
v6.1 (commit fff9895c82d744c7237be8847347bdd1b07c6643) |
| M5GFX |
0.2.28 (from the component registry) |
| M5Unified |
0.2.21 (from the component registry) |
| Board |
M5Stack Cardputer Adv (ESP32-S3FN8, no PSRAM) |
| Toolchain |
xtensa-esp-elf-gcc 15.2.0 (crosstool-NG esp-15.2.0_20251204) |
| Project type |
plain ESP-IDF component, no Arduino |
| Host |
macOS arm64 |
Symptom
The project builds cleanly (0 errors, 0 warnings). At runtime it boot-loops — 282 resets in 15
seconds — with:
E (160) gdma: gdma_config_transfer(425): invalid max_data_burst_size: 4294967295
E (160) spi_common: alloc_dma_chan(319): config gdma tx transfer failed
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
EXCVADDR: 0x00000004
Decoded backtrace:
m5::M5Unified::begin() M5Unified.hpp:363
lgfx::v1::LGFX_Device::init() LGFXBase.hpp:1423
m5gfx::M5GFX::init_impl(bool, bool) M5GFX.cpp:1111
m5gfx::M5GFX::autodetect(bool, board_t) M5GFX.cpp:1826
lgfx::v1::Bus_SPI::init() Bus_SPI.cpp:418
lgfx::v1::spi::init(int, int, int, int, int) lgfx/v1/platforms/esp32/common.cpp:859
spi_bus_initialize() esp-idf/components/esp_driver_spi/src/gpspi/spi_common.c:1016
spicommon_dma_chan_free() esp-idf/components/esp_driver_spi/src/gpspi/spi_common.c:489 <-- panic
Root cause
src/lgfx/v1/platforms/esp32/common.cpp:841:
spi_bus_config_t buscfg;
memset(&buscfg, ~0u, sizeof(spi_bus_config_t)); // sets every *_io_num to -1
buscfg.mosi_io_num = spi_mosi;
...
buscfg.intr_flags = 0;
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0))
buscfg.data_io_default_level = 0;
#endif
IDF 6.1 added:
uint32_t dma_burst_size; ///< DMA data burst size in bytes. Only used when DMA is enabled.
/// Set to 0 to use driver default.
(components/esp_driver_spi/include/driver/spi_common.h)
After the memset it holds 0xFFFFFFFF, which is neither 0 nor a chip-supported burst size, so
resolve_dma_burst_size() rejects it, alloc_dma_chan() fails, and the unwind path panics.
Field presence, checked against the release tags:
| ESP-IDF |
dma_burst_size in spi_bus_config_t |
| v6.1 |
present |
| v6.0.3 |
absent |
| v6.0 |
absent |
| v5.5.5 |
absent |
.github/workflows/IDFBuild.yml covers 6.0.2 (where the field does not exist) and is build-only, so
neither half of the matrix can surface this: adding a struct field needs no source change to compile.
Confirmation
Same binary, one line added after buscfg.intr_flags = 0;:
#if defined (ESP_IDF_VERSION_VAL)
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 1, 0))
buscfg.dma_burst_size = 0;
#endif
#endif
|
boots in 15 s |
panics |
| unpatched |
282 |
282 |
| one line added |
1 |
0 |
With the line added, everything works: getBoard() returns board_M5CardputerADV, the 240x135
display paints, and both speaker and mic report enabled.
Suggested fix
The minimal change is the version-guarded assignment above, next to the existing
data_io_default_level / isr_cpu_id guards.
More robustly, memset(&buscfg, ~0u, ...) is fragile against upstream struct growth: any new
non-pin field IDF adds silently arrives as 0xFFFFFFFF. Zero-initialising and then setting the
*_io_num fields to -1 explicitly would make future IDF releases default-correct instead of
default-wrong.
Related, on the ESP-IDF side
spi_bus_initialize() panics in its own error path rather than returning the error that
alloc_dma_chan() already produced — spicommon_dma_chan_free() dereferences a DMA context that was
never fully allocated (EXCVADDR: 0x00000004). An invalid dma_burst_size should surface as a
failed return, not a LoadProhibited. That is arguably a separate ESP-IDF issue; happy to file it
there as well if useful.
Summary
On ESP-IDF v6.1,
M5.begin()(or anyM5GFX::init()) panics during SPI businitialisation and the board boot-loops. The cause is that IDF 6.1 added a new field to
spi_bus_config_t, andlgfx::v1::spi::init()fills that struct withmemset(&buscfg, ~0u, ...),so the new field is left as
0xFFFFFFFF.IDF 6.0.x and 5.x do not have the field, which is why the existing build matrix does not show this.
Environment
fff9895c82d744c7237be8847347bdd1b07c6643)xtensa-esp-elf-gcc15.2.0 (crosstool-NG esp-15.2.0_20251204)Symptom
The project builds cleanly (0 errors, 0 warnings). At runtime it boot-loops — 282 resets in 15
seconds — with:
Decoded backtrace:
Root cause
src/lgfx/v1/platforms/esp32/common.cpp:841:IDF 6.1 added:
(
components/esp_driver_spi/include/driver/spi_common.h)After the
memsetit holds0xFFFFFFFF, which is neither0nor a chip-supported burst size, soresolve_dma_burst_size()rejects it,alloc_dma_chan()fails, and the unwind path panics.Field presence, checked against the release tags:
dma_burst_sizeinspi_bus_config_t.github/workflows/IDFBuild.ymlcovers 6.0.2 (where the field does not exist) and is build-only, soneither half of the matrix can surface this: adding a struct field needs no source change to compile.
Confirmation
Same binary, one line added after
buscfg.intr_flags = 0;:With the line added, everything works:
getBoard()returnsboard_M5CardputerADV, the 240x135display paints, and both speaker and mic report enabled.
Suggested fix
The minimal change is the version-guarded assignment above, next to the existing
data_io_default_level/isr_cpu_idguards.More robustly,
memset(&buscfg, ~0u, ...)is fragile against upstream struct growth: any newnon-pin field IDF adds silently arrives as
0xFFFFFFFF. Zero-initialising and then setting the*_io_numfields to-1explicitly would make future IDF releases default-correct instead ofdefault-wrong.
Related, on the ESP-IDF side
spi_bus_initialize()panics in its own error path rather than returning the error thatalloc_dma_chan()already produced —spicommon_dma_chan_free()dereferences a DMA context that wasnever fully allocated (
EXCVADDR: 0x00000004). An invaliddma_burst_sizeshould surface as afailed return, not a
LoadProhibited. That is arguably a separate ESP-IDF issue; happy to file itthere as well if useful.