ESP32 Memory Management, Neopixels, and RGBPanels

Slides: http://marc.merlins.org/linux/talks/ESP32_Memory/

Linux.conf.au 2020 Supercon 2024

Marc MERLIN

marc@merlins.org

http://instagram.com/ledtranceguy

I made a 64x64 neopixel array, 4096 pixels in 3 byte color, 12KB. Everything worked except one demo that crashed and I couldn’t find the bug in

ESP32, it was all fine when I started

I wanted to re-use all my code written for FastLED::NeoMatrix, on top of SmartMatrix

Commercial Time: Framebuffer::GFX and SmartMatrix::GFX

Once I had Framebuffer::GFX, I wrote other driver frontends

Commercial Time: FastLED_SPITFT::GFX

My new 96x64 RGBPanel outfit uses RGBPanels, which require multiple pre-computed bitmap planes that are used for DMA

Then I switched to RGBPanels, they need a lot more RAM

RGBPanels 96x64 and TFTs at 320x240 blew up memory on ESP32

ESP32, 520KB of RAM, really?

https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/mem_alloc.html

You really get 2x 160KB (not quite, even)

https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/mem_alloc.html

IRAM and non contiguous RAM

I (252) heap_init: Initializing. RAM available for dynamic allocation:

I (259) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM

I (265) heap_init: At 3FFB2EC8 len 0002D138 (180 KiB): DRAM

I (272) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM

I (278) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM

I (284) heap_init: At 4008944C len 00016BB4 (90 KiB): IRAM

https://github.com/espressif/esp-idf/issues/3497 “Statically allocated DRAM is limited to 160KB”

Global Arrays can barely access 160KB

https://github.com/espressif/arduino-esp32/issues/2567 “Compiler/linker should do a better job handling global arrays instead of crashing at runtime before setup() runs”

Your program may compile, but crash at runtime

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)

0x40088960: invoke_abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/panic.c line 140

0x40088b63: abort at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/panic.c line 149

0x40082b72: start_cpu0_default at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/cpu_start.c line 381

0x40082d04: call_start_cpu0 at /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/esp32/cpu_start.c line 213

https://github.com/espressif/arduino-esp32/issues/2567#issuecomment-475057527

Only 8KB of stack

Converting arrays to malloc

The most annoying parts are: having to change working code, checking for malloc success, and dealing with multi dimensional arrays.

Converting arrays to mallocs()

Dot *gDot; // Creates an object named gDot of type Dot class

//Dot gDot[MAX_SHELLS];

Dot *gSparks; // Creates an array object named gSparks of type Dot class

//Dot gSparks[MAX_SHELLS*MAX_SPARKS];

void fireworks_setup() {

gDot = (Dot *) malloc(MAX_SHELLS * sizeof(Dot));

gSparks = (Dot *) malloc(MAX_SHELLS * MAX_SPARKS * sizeof(Dot));

while (gDot == NULL || gSparks == NULL) {

Serial.println("fireworks_setup malloc failed");

}

memset(gDot, 0, MAX_SHELLS * sizeof(Dot));

memset(gSparks, 0, MAX_SHELLS * MAX_SPARKS * sizeof(Dot));

}

// gSparks[a][b].Move();

gSparks[a*MAX_SPARKS+b].Move();

If you don’t want to rewrite multi dimensional arrays, you can use a malloc loop

Multi dimensional arrays with malloc and memory saved

There is a more tedious way to allocate 2 dimentional arrays so that tempMatrix[i][j] still works

for (uint16_t i=0; i < MATRIX_WIDTH+1; i++) {

tempMatrix[i] = (uint8_t *) malloc(MATRIX_HEIGHT+1);

while (tempMatrix[i] == NULL) { Serial.println("tempMatrix[i] malloc failed"); }

memset(tempMatrix[i], 0, MATRIX_HEIGHT+1);

}

Before, with arrays

32-bit Memory Available: 179392 bytes total, 86640 bytes largest free block

8-bit Accessible Memory Available: 92752 bytes total, 36576 bytes largest free block

After malloc cleanup, 39KB of static memory saved

32-bit Memory Available: 212344 bytes total, 86640 bytes largest free block

8-bit Accessible Memory Available: 125704 bytes total, 64624 bytes largest free block

Converting arrays to malloc: the gift that keeps on giving

But how about ESP32 S2 and S3

My future (circa 2020) isn’t on ESP32 anymore

https://github.com/marcmerlin/FastLED_RPIRGBPanel_GFX

Not even remotely related, powering my house from my Tesla

Q&A

Marc Merlin marc@merlins.org

http://instagram.com/ledtranceguy

Slides:

http://marc.merlins.org/linux/talks/ESP32_Memory/