The Anatomy of an ESP32 Bootup Crash
When developing complex IoT applications or motor control systems, the ESP32 family occasionally succumbs to fatal errors, resulting in the infamous "Guru Meditation Error" or Task Watchdog resets. To diagnose these post-mortem, engineers must configure the system to retain crash telemetry. Learning how to esp32 check for core dump on bootup is a critical skill for any embedded systems engineer, allowing you to extract the exact CPU state, stack trace, and memory registers immediately after a device recovers from a panic.
Unlike standard microcontrollers that simply restart and lose all context, the ESP32 architecture includes a dedicated panic handler. This handler can serialize the state of all FreeRTOS tasks and CPU registers into a structured binary format. However, the compatibility of this feature varies wildly depending on whether you are using the native ESP-IDF framework, the Arduino-ESP32 core, or specific silicon variants like the ESP32-S3 or ESP32-C3. This guide explores the structural requirements, API implementations, and cross-variant compatibility necessary to reliably capture and verify core dumps during the boot sequence.
Partition Table Compatibility: Flash vs. UART
Before you can check for a core dump on bootup, the ESP32 must be instructed on where to store it. The system supports two primary destinations: UART output (printed to the serial console during the crash) and SPI Flash storage. For automated bootup checks, Flash storage is mandatory. UART dumps are transient; if your device is deployed in the field or headless, a UART dump is lost the moment the device resets.
To store the dump in Flash, your partition table must explicitly define a coredump partition. If this partition is missing, the ESP-IDF panic handler will silently fail to write the dump to Flash, or worse, overwrite adjacent filesystem partitions like SPIFFS or LittleFS, leading to catastrophic data corruption.
Custom CSV Partition Mapping
When using the Arduino IDE or PlatformIO, you must supply a custom CSV partition table. A standard 4MB ESP32 flash layout optimized for OTA updates and core dump retention looks like this:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x140000,
app1, app, ota_1, 0x150000, 0x140000,
spiffs, data, spiffs, 0x290000, 0x150000,
coredump, data, coredump, 0x3E0000, 0x20000,
The coredump subtype is strictly recognized by the bootloader. A size of 0x20000 (128KB) is highly recommended for ESP32-S3 and dual-core ESP32 boards, as the dump includes the full RAM footprint of the crashing task and the FreeRTOS heap metadata. According to the official Espressif Core Dumps Guide, allocating less than 64KB can result in truncated dumps that fail decoding.
API Implementation: Checking the Dump via Code
Once the hardware resets and your setup() function begins, you need a programmatic way to verify if a dump was written. The method for doing this shifted significantly between ESP-IDF v4.4 and the modern v5.x architecture, which directly impacts Arduino-ESP32 v3.x compatibility.
Modern ESP-IDF v5.x / Arduino-ESP32 v3.x Approach
In modern toolchains, the legacy esp_core_dump_image_get() function has been deprecated in favor of direct partition interrogation. To perform an esp32 check for core dump on bootup, you must locate the coredump partition and read its header to verify the magic word and checksum.
#include <Arduino.h>
#include <esp_partition.h>
#include <esp_core_dump.h>
#include <esp_rom_crc.h>
void checkBootupCoreDump() {
const esp_partition_t* coredump_part = esp_partition_find_first(
ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL
);
if (!coredump_part) {
Serial.println("[Boot] No coredump partition found in table.");
return;
}
// Read the first 4 bytes to check for the Core Dump Magic Word
uint32_t magic_word = 0;
esp_err_t err = esp_partition_read(coredump_part, 0, &magic_word, sizeof(magic_word));
if (err == ESP_OK && magic_word == ESP_COREDUMP_MAGIC_WORD) {
Serial.println("[Boot] FATAL CRASH DETECTED: Valid Core Dump present.");
// Trigger cloud upload or BLE transmission of the partition data here
} else {
Serial.println("[Boot] Clean boot. No core dump present.");
}
}
void setup() {
Serial.begin(115200);
delay(1000);
checkBootupCoreDump();
// Normal application setup continues...
}
This approach guarantees compatibility across the latest Arduino-ESP32 releases, avoiding linker errors associated with deprecated IDF headers.
Cross-Variant Compatibility Matrix
Not all ESP32 silicon handles core dumps identically. The availability of RTC Fast Memory (which survives deep sleep and resets) and default flash architectures dictate how reliably a dump is written before the Brownout Detector (BOD) cuts power. Below is a compatibility matrix for checking dumps on bootup across the primary variants.
| Variant | Core Dump Support | RTC Fast Memory | Bootup Check API | Common Failure Mode |
|---|---|---|---|---|
| ESP32 (Dual Core) | Full (Flash/UART) | 8 KB | Partition Header Read | Brownout during Flash write corrupts SPIFFS |
| ESP32-S3 | Full (Flash/UART) | 8 KB | Partition Header Read | PSRAM heap dumps exceed 64KB partition limits |
| ESP32-C3 | Full (Flash/UART) | 2 KB | Partition Header Read | Single-core RISC-V watchdog resets bypass handler |
| ESP32-C6 | Full (Flash/UART) | 2 KB | Partition Header Read | Thread/Zigbee stack panics require custom IDF flags |
Decoding the Dump: Toolchain Requirements
Successfully executing an esp32 check for core dump on bootup is only half the battle. Once you verify the dump exists and extract the raw binary payload via SPIFFS, Wi-Fi, or MQTT, you must decode it. The binary dump is useless without the exact .elf file generated during the specific compilation that produced the crash.
Espressif provides the esp-coredump Python utility to parse these files. If you are using PlatformIO or ESP-IDF, you can run the following command locally, provided you have the raw dump saved as dump.bin and your firmware ELF file:
idf.py coredump-info -c dump.bin build/my_firmware.elf
Information Gain Tip: If you are deploying OTA updates, you must store the SHA256 hash of your firmware's ELF file in the NVS partition. When your bootup check detects a core dump, transmit the dump alongside the NVS-stored hash. Your backend server can then automatically pull the matching ELF file from your CI/CD pipeline to decode the stack trace accurately. Mismatched ELF files will result in garbage memory addresses and invalid line numbers.
Troubleshooting Bootloop Core Dump Failures
A frequent issue engineers face is a "bootloop" where the ESP32 crashes, attempts to write the core dump, fails, and resets infinitely. Understanding the ESP-IDF Core Dump API Reference helps isolate these hardware-level conflicts.
1. The Brownout Detector (BOD) Race Condition
If your crash is caused by a power sag (e.g., a motor kicking in and dropping the 3.3V rail below 2.4V), the BOD triggers a reset. The panic handler attempts to write to SPI Flash, but Flash writes require significant current and stable voltage. The write fails, and the chip resets. Solution: Add a large bulk capacitor (e.g., 470µF) on the 5V rail or disable the BOD in software (not recommended for production) using WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); to allow the dump to finish writing.
2. Interrupt Watchdog Timeouts
If a crash occurs inside an ISR (Interrupt Service Routine) or with interrupts disabled, the Flash SPI driver cannot operate because it relies on interrupts for DMA completion. The core dump will hang, triggering the Task Watchdog, resulting in a secondary crash. Solution: Ensure your menuconfig or sdkconfig sets CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y but acknowledges that ISR-level crashes may only be capturable via UART, not Flash.
3. Arduino IDE Default Partition Overwrites
When using the Arduino IDE, selecting "Default 4MB with spiffs" from the Tools menu will silently ignore your custom CSV file and overwrite the flash with a partition table lacking a coredump subtype. Always use PlatformIO or explicitly define a custom partitions.csv path in your platformio.ini or Arduino board manager configurations to guarantee the coredump sector remains intact across uploads.






