ESP Memory Usage Optimization

[中文]

Introduction

Due to the hardware resource constraints of embedded chips, running complex application code may lead to insufficient memory. Most of the default configuration items in ESP-IDF prioritize performance, but in actual products, a good balance between performance and memory usage can be achieved through appropriate memory configuration.

Warning

Some memory optimization methods listed in this document may reduce system performance and stability. Sufficient performance and stability testing should be conducted after optimization to ensure the application meets its requirements.

Obtaining Current Free Memory

Before optimizing memory usage, it is necessary to know the current memory consumption. For static memory usage, you can use the idf.py size and idf.py size-components commands to gather statistics memory usage. For runtime memory consumption, xPortGetFreeHeapSize() and xPortGetMinimumEverFreeHeapSize() functions can be used to obtain the current free memory and the minimum heap memory remaining since system startup, respectively. For more granular memory allocation, you can enable the CONFIG_FREERTOS_USE_TRACE_FACILITY and CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS options and then use the vTaskList() function to get the high watermark for each task stack.

Available Optimization Options

  1. Wi-Fi Memory Optimization

Wi-Fi performance is affected by many parameters, with trade-offs between them. Proper configuration can not only improve performance but also increase available memory and system stability. Configuration options vary significantly depending on the chip, so for Wi-Fi memory optimization and throughput, please refer to the relevant chip documentation under How to Improve Wi-Fi Performance.

  1. LwIP Memory Optimization

Since RAM is allocated dynamically from the heap, most of lwIP’s RAM usage is also dynamically allocated. Therefore, changing lwIP settings to reduce RAM usage might not affect idle RAM usage but can reduce peak RAM consumption. For LwIP memory optimization, see LwIP Minimum RAM Usage.

  1. Mbed TLS Memory Optimization

Mbed TLS is a C library used to implement cryptographic primitives, X.509 certificate handling, and SSL/TLS and DTLS protocols. When using the Mbed library for encryption and decryption, memory usage can be reduced by adjusting its configuration. For Mbed memory optimization, see Mbed Minimum RAM Usage.

  1. BLE Memory Optimization

Compared to Bluedroid, NimBLE uses less memory and a smaller firmware size. Additionally, you can disable certain features and reduce buffer sizes to achieve optimal memory usage. For scenarios where BLE is only used for provisioning, try the following configurations:

Reduce maximum connections and related parameters:

  • CONFIG_BT_NIMBLE_MAX_CONNECTIONS=1

  • CONFIG_BT_NIMBLE_MAX_BONDS=2

  • CONFIG_BT_NIMBLE_MAX_CCCDS=2

  • CONFIG_BT_NIMBLE_WHITELIST_SIZE=2

If there are no high-speed requirements, reduce buffer sizes and counts:

  • CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=12

  • CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=100

  • CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=4

  • CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=12

  • CONFIG_BT_NIMBLE_TRANSPORT_EVT_COUNT=5

  • CONFIG_BT_NIMBLE_TRANSPORT_EVT_DISCARD_COUNT=3

Disable unnecessary features:

  • CONFIG_BT_NIMBLE_ROLE_CENTRAL=n

  • CONFIG_BT_NIMBLE_ROLE_OBSERVER=n

  • CONFIG_BT_NIMBLE_SECURITY_ENABLE=n

  1. Other Configuration Optimizations

For performance and power-saving purposes, some functions are placed in IRAM by default. If needed, you can reconfigure these functions to be placed back into Flash:

  • CONFIG_SPI_SLAVE_ISR_IN_IRAM=n

  • CONFIG_ESP_WIFI_IRAM_OPT=n

  • CONFIG_ESP_WIFI_RX_IRAM_OPT=n

  • CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH=y

  • CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y

  • CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y

Reduce the length of some system queues:

  • CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=16

Enable nano format options:

  • NEWLIB_NANO_FORMAT=y

Disable unnecessary features:

  • CONFIG_WS_TRANSPORT=n

  1. Reduce Task Stack Sizes

In the default ESP-IDF configuration, Task Stack sizes include a large margin to accommodate different chips and allow users to add application code. Reducing Task Stack sizes can free up memory for dynamic allocation.

Common Task Stack configuration items:

  • CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE

  • CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE

  • CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE

  • CONFIG_ESP_TIMER_TASK_STACK_SIZE

  • CONFIG_FREERTOS_IDLE_TASK_STACKSIZE

  • CONFIG_LWIP_TCPIP_TASK_STACK_SIZE

Optimization Example and Result Statistics

Testing the bleprph_wifi_coex example demonstrates the effect of memory optimization by comparing memory usage before and after Wi-Fi and BLE connections.

  1. Hardware and Software Environment

  1. Configuration Changes

  • CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y

  • CONFIG_EXAMPLE_ESP_PING_COUNT=5

  • CONFIG_BT_ENABLED=y

  • CONFIG_BT_NIMBLE_ENABLED=y

  • CONFIG_BT_NIMBLE_MAX_BONDS=2

  • CONFIG_BT_NIMBLE_MAX_CCCDS=2

  • CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=2048

  • CONFIG_BT_NIMBLE_ROLE_CENTRAL=n

  • CONFIG_BT_NIMBLE_ROLE_OBSERVER=n

  • CONFIG_BT_NIMBLE_SECURITY_ENABLE=n

  • CONFIG_BT_NIMBLE_MSYS_1_BLOCK_COUNT=12

  • CONFIG_BT_NIMBLE_MSYS_1_BLOCK_SIZE=100

  • CONFIG_BT_NIMBLE_MSYS_2_BLOCK_COUNT=4

  • CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=12

  • CONFIG_BT_NIMBLE_TRANSPORT_EVT_COUNT=5

  • CONFIG_BT_NIMBLE_TRANSPORT_EVT_DISCARD_COUNT=3

  • CONFIG_BT_NIMBLE_50_FEATURE_SUPPORT=n

  • CONFIG_BT_NIMBLE_WHITELIST_SIZE=2

  • CONFIG_BT_LE_CONTROLLER_TASK_STACK_SIZE=2048

  • CONFIG_ESP_COEX_SW_COEXIST_ENABLE=n

  • CONFIG_ESP_EVENT_POST_FROM_ISR=n

  • CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=n

  • CONFIG_RINGBUF_PLACE_FUNCTIONS_INTO_FLASH=y

  • CONFIG_RINGBUF_PLACE_ISR_FUNCTIONS_INTO_FLASH=y

  • CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=16

  • CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=1536

  • CONFIG_ESP_TIMER_TASK_STACK_SIZE=2048

  • CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=3

  • CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=6

  • CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=6

  • CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=n

  • CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=n

  • CONFIG_ESP_WIFI_IRAM_OPT=n

  • CONFIG_ESP_WIFI_RX_IRAM_OPT=n

  • CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n

  • CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n

  • CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT=y

  • CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=0

  • CONFIG_ESP_WIFI_ENTERPRISE_SUPPORT=n

  • CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=768

  • CONFIG_FREERTOS_USE_TRACE_FACILITY=y

  • CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y

  • CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y

  • CONFIG_LWIP_L2_TO_L3_COPY=y

  • CONFIG_LWIP_MAX_SOCKETS=8

  • CONFIG_LWIP_SO_LINGER=y

  • CONFIG_LWIP_SO_RCVBUF=y

  • CONFIG_LWIP_NETBUF_RECVINFO=y

  • CONFIG_LWIP_GARP_TMR_INTERVAL=30

  • CONFIG_LWIP_MLDV6_TMR_INTERVAL=30

  • CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=16

  • CONFIG_LWIP_DHCP_RESTORE_LAST_IP=y

  • CONFIG_LWIP_DHCPS=n

  • CONFIG_LWIP_IPV6_NUM_ADDRESSES=6

  • CONFIG_LWIP_IPV6_FORWARD=y

  • CONFIG_LWIP_TCP_SND_BUF_DEFAULT=6144

  • CONFIG_LWIP_TCP_SACK_OUT=y

  • CONFIG_LWIP_MAX_UDP_PCBS=24

  • CONFIG_LWIP_UDP_RECVMBOX_SIZE=12

  • CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=2048

  • CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=6

  • CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=8

  • CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=6288

  • CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=2048

  • CONFIG_MBEDTLS_DYNAMIC_BUFFER=y

  • CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA=y

  • CONFIG_MBEDTLS_SSL_KEEP_PEER_CERTIFICATE=n

  • CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n

  • CONFIG_NEWLIB_TIME_SYSCALL_USE_HRT=y

  1. Optimization Results

The table below shows the system’s available memory before and after optimization. The results indicate that approximately 60 KB of memory can be saved through configuration optimization.

Available Memory

Before Optimization

After Optimization

Difference

Current Available (bytes)

33,232

95,040

61,808

Minimum Available (bytes)

25,804

91,252

65,448