Favoring External Allocations
Recently someone reached out to me with the following problem:
I am trying to add udp support to my project, and I’m getting
ESP_ERR_NO_MEM
for the first time (from esp wifi init). I am using more freertos memory now, which must be bumping into esp-idf’s memory.I can’t find ANYTHING in
menuconfig
that allows me to control heap size or allocations.
Internal vs External Memory
The ESP32 has a fixed amount of SRAM. Depending on your project and settings, a portion of that memory is applied to your heap and can be used by your code. It is also utilized by various features of IDF. One big user of internal memory is the allocation of task stacks. Every FreeRTOS task you start needs memory allocated for stack space. This can quickly exhaust your internal memory, especially if you are using other high-memory-using features such as WiFi and Bluetooth.
Many ESP32 chips support external PSRAM. This allows you to significantly increase the amount of RAM available to your application code and tasks. An additional benefit of external RAM is that you can move some IDF allocations from internal RAM to external RAM.
The H2, C2, C3, C6 chips do not support PSRAM.
A Limited Resource
As your product codebase grows in complexity you may find yourself running low on internal memory. As mentioned above, there are lots of IDF features that pull from this memory pool behind the scenes. This includes things like WiFi, Bluetooth and even peripherals like SPI and UART. Many of these things are configurable in menuconfig
but, if you’ve never run low on internal memory, you’ve probably never paid much attention to them.
Some IDF features can be configured to use external memory which is usually much more plentiful. Some, however, do not give you that level of control. They are only able to use internal memory. If you use enough of these features and have enough tasks and memory usage you will find yourself low on internal memory and getting the dreaded ESP_ERR_NO_MEM
error.
Favoring External RAM Allocations
A simple, fast way to free up internal memory is to more heavily favor external allocations over internal memory allocations. By default, when you enable external RAM, the CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL
menuconfig setting is set to 16KB. This means that any allocation below 16KB will, if possible, be taken from internal RAM. This will happen until the internal RAM is exhausted at which point the allocations will switch to external RAM.
Obviously internal RAM will be more performant than external RAM so this isn’t necessarily a bad default. However, if you find yourself running low on internal memory this is a super easy dial to turn to move more things to external RAM, thus freeing up internal RAM.
This is especially important when you have a lot of FreeRTOS tasks as they, by default, always use internal memory.
Simply change the setting to something much lower and profile your memory usage again. Instead of using your external memory as a “backup” to internal memory, it allows you to use it more proactively to help maintain internal memory at a health level.
Setting for controlling the balance of where memory is allocated from
Other Internal Memory-Saving Options
The Espressif documentation actually has an entire page dedicated to ways you can free up internal memory. At some point we may cover these in more detail. When to use them and what the tradeoffs are. But for now, I’ll leave it as an exercise to the reader to review the options presented.
Conclusion
Internal memory is a precious, limited resource. As your project grows in complexity you may run into a hard limit. If your device has external PSRAM available, more heavily favoring external allocations is one of the easiest ways to regain a significant chunk of internal memory.
Did you find this tip helpful? Join the community and get more content just like it in the weekly Production ESP32 newsletter. Concise, actionable content right in your inbox.
Comments powered by Disqus.