ESP32-S3-EYE: Tensor arena too small, CORRUPT HEAP when using PSRAM

Tensor arena is too small for the exported model on ESP32-S3-EYE. The default arena size (492352 bytes) causes a StoreProhibited crash immediately because the model tries to allocate a persistent buffer of 323200 bytes that doesn’t fit. When the arena is moved to PSRAM using heap_caps_malloc, a CORRUPT HEAP crash occurs instead.

Project ID: 1041663

Context/Use case:
Real-time forest fire detection using the ESP32-S3-EYE camera module. The camera captures frames and runs image classification inference continuously. The model uses 160x160 RGB input with 2 output classes (fire / no fire).

Steps Taken:

  1. Exported Arduino library from Edge Impulse and flashed the esp32_camera example sketch to ESP32-S3-EYE
  2. Observed crash: ERR: Failed to allocate persistent buffer of size 576, does not fit in tensor arena and reached EI_MAX_OVERFLOW_BUFFER_COUNT followed by Guru Meditation Error: Core 1 panic'ed (StoreProhibited)
  3. Confirmed PSRAM is available and working: PSRAM size: 8388608, Free PSRAM: 8384768
  4. Increased kTensorArenaSize in tflite_learn_1041663_8_compiled.cpp to 700000 — crash changed, now shows ERR: Failed to allocate persistent buffer of size 323200 repeatedly until PSRAM runs out (arena was being allocated fresh each loop without being freed)
  5. Added if (!tensor_arena) guard to prevent re-allocation each loop, and changed allocation to heap_caps_malloc(kTensorArenaSize, MALLOC_CAP_SPIRAM) with #include "esp_heap_caps.h" at top of file
  6. Increased kTensorArenaSize to 1500000 — arena allocates successfully in PSRAM (ptr valid, free PSRAM confirms allocation) but crashes with CORRUPT HEAP: Bad head at 0x3c29e104. Expected 0xabba1234 got 0x00000000
  7. Tried increasing EI_CLASSIFIER_TFLITE_LARGEST_ARENA_SIZE in model_metadata.h to 1500000 — no effect on kTensorArenaSize
  8. Tried increasing EI_MAX_OVERFLOW_BUFFER_COUNT to 64 in both ei_classifier_porting.h and tflite_learn_1041663_8_compiled.cpp — no resolution

Expected Outcome:
The model initializes successfully, camera captures frames, and inference runs continuously producing fire/no fire classification results.

Actual Outcome:
Either a StoreProhibited crash when arena is too small, or a CORRUPT HEAP crash when arena is placed in PSRAM. The device reboots in an infinite loop in both cases.

Reproducibility:

  • Always

Environment:

  • Platform: ESP32-S3-EYE (8MB PSRAM, OV2640 camera)
  • Build Environment: Arduino IDE 1.8.19, ESP32 Arduino Core 3.3.10
  • OS Version: Windows 10
  • Edge Impulse Version: Check EI_STUDIO_VERSION in model_metadata.h
  • Project Version: Deploy version 6
  • Custom Blocks / Impulse Configuration: Image classification, 160x160 RGB input, 2 classes (fire, no fire), EON compiled model, INT8 quantization, no anomaly detection

Logs:

Default arena size crash:

ERR: Failed to allocate persistent buffer of size 576, does not fit in tensor arena and reached EI_MAX_OVERFLOW_BUFFER_COUNT
Guru Meditation Error: Core 1 panic'ed (StoreProhibited). Exception was unhandled.
EXCVADDR: 0x00000000

After moving arena to PSRAM with 1500000 bytes:

Arena size requested: 1500000, ptr: 0x3c12e108, free PSRAM: 6627168
CORRUPT HEAP: Bad head at 0x3c29e104. Expected 0xabba1234 got 0x00000000
assert failed: multi_heap_free multi_heap_poisoning.c:279 (head != NULL)

Additional Information:
The board has 8MB PSRAM which is confirmed working. The issue appears to be that CMSIS-NN optimized kernels used on ESP32-S3 write scratch buffers expecting internal RAM alignment/access patterns, causing heap corruption when the arena is placed in PSRAM. The ei_calloc calls inside AllocatePersistentBufferImpl for overflow buffers may also need to use PSRAM. What is the officially supported method to use PSRAM for the tensor arena with EON compiled models on ESP32-S3?

Hello @johndrew first of all welcome to the Edge Impulse community!

Are you using the TensorFlow Lite model optimization during the Deployment?

image

let me know if changing the EON compiled model to TensorFlow Lite make your model to run properly in the hardware.

Thanks!

Hi,

I ran into a very similar Tensor Arena sizing problem while working with an Edge Impulse model on an ESP32-S3.

In my case, I initially tried the EON compiler as well, but I encountered reliability and memory-management problems on the ESP32-S3. That is actually what led me to switch to the standard TensorFlow Lite Micro deployment.

After switching to TensorFlow Lite, I found another issue: the Tensor Arena size generated by Edge Impulse was smaller than the actual arena usage measured at runtime.

For my test model, Edge Impulse generated:

519232 bytes

but the actual TensorFlow Lite Micro arena usage measured on the ESP32-S3 was:

536044 bytes

So the generated value was already below what the model actually needed.

I initially had to experiment manually with larger Arena values, which is why I ended up creating a small diagnostic tool for ESP32-S3 + Edge Impulse projects.

The tool temporarily overrides the model’s Tensor Arena with a larger diagnostic Arena, runs the model once, reads:

MicroInterpreter::arena_used_bytes()

after AllocateTensors() succeeds, and then automatically calculates three suggested final Arena sizes.

For my model, the output is:

Edge Impulse arena : 519232 bytes
Measured usage (M) : 536044 bytes

WARNING: The arena generated by Edge Impulse is smaller
than the measured arena usage.

SMALL  : 552428 bytes  (+16 KiB)
MEDIUM : 568812 bytes  (+32 KiB)  <-- RECOMMENDED
LARGE  : 601580 bytes  (+64 KiB)

Recommended value: 568812 bytes

The diagnostic uses a temporary large Arena only for the measurement. Once the actual requirement has been measured, the selected value is written back into the Edge Impulse model header and the original Edge Impulse tflite_micro.h file is restored.

One important difference with your current setup is that my tool is specifically for the standard TensorFlow Lite / TensorFlow Lite Micro deployment, not for an EON-compiled model.

So it will not diagnose the EON + PSRAM CORRUPT HEAP issue directly.

However, since you are already seeing problems after moving the EON Arena to PSRAM, one possible test would be to export the same model again using:

Arduino library → TensorFlow Lite → Quantized (int8)

and first determine the actual Tensor Arena requirement using the standard TFLite Micro runtime, without manually moving the Arena to PSRAM.

That is essentially the path I ended up taking after having problems with EON on the ESP32-S3.

I published the diagnostic tool and the complete procedure here:

It is mainly intended for hobbyists and beginners who run into AllocateTensors(), run_classifier() or undersized Tensor Arena problems with Edge Impulse on ESP32-S3.

It may be interesting to try your 160x160 RGB fire/no-fire model with the TensorFlow Lite INT8 export and see what arena_used_bytes() reports. That would at least establish the real TFLite Micro memory requirement independently of the EON/PSRAM corruption issue.

I would also be interested to know whether the Edge Impulse team recommends an officially supported way of placing an EON Tensor Arena in ESP32-S3 PSRAM, since that is a separate issue from the Tensor Arena sizing problem.

Hi @johndrew
Arena size mismatch is a known issue, it is also mentioned in the docs:

You don’t need to manually place the arena to PSRAM, ESP-IDF takes care of that already with wrapped malloc/calloc.

Increased kTensorArenaSize in tflite_learn_1041663_8_compiled.cpp to 700000

that might have not been enough still? What is the original size there? Can you bump this up a bit more?

1 Like