When deciding which functions to move to Flash, follow these guidelines to avoid runtime crashes.
Functions that MUST stay in IRAM
- ISRs and functions called from ISRs.
- SPI Flash operations (
spi_flash_*). - Functions running before Flash cache initialization.
- FreeRTOS scheduler-critical functions.
- Cache error handlers.
- RTC/Sleep functions.
- Functions with the
IRAM_ATTR attribute in source code.
Functions that CAN be moved to Flash
- Initialization functions (called once at startup).
- Logging functions (unless used in ISR context).
- Memory management (if not used in ISR).
- Non-critical library functions.
- Configuration/setup routines.
Identifying Candidates
- Check Memory Map: Examine
.pio/build/<env>/firmware.map after a build. - Use objdump: Use the appropriate toolchain for your chip to inspect symbols:
- RISC-V (C2, C3, C6, H2):
riscv32-esp-elf-objdump -t <path_to_lib> - Xtensa (ESP32, S2, S3):
xtensa-esp32-elf-objdump -t <path_to_lib>
# For RISC-V Chips (C2, C3, C6, H2)
riscv32-esp-elf-objdump -t ~/.platformio/packages/framework-arduinoespressif32-libs/esp32c2/lib/libfreertos.a | grep xTaskGetTickCount
# For Xtensa Chips (ESP32, S2, S3)
xtensa-esp32-elf-objdump -t ~/.platformio/packages/framework-arduinoespressif32-libs/esp32/lib/libfreertos.a | grep xTaskGetTickCount