Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Managing heap sizes across Memory Manager module, FreeRTOS, and project settings

TL;DR and just want to get to the questions? See highlighted text below.

I am working with nRF52832 in SEGGER Embedded Studio, working with nRF5 SDK 16.0.0.  I use a SEGGER JLink Base unit for debug, and rely on the Debug Terminal in SES for debug messages.

There are multiple heaps being used in a code base I've inherited and I'm attempting to optimize and reduce RAM usage in the code.  I've noted three different heaps:

  • Project Settings > Runtime Memory Area: __HEAP_SIZE__ = 8192
  • FreeRTOS (using heap_4.c): configTOTAL_HEAP_SIZE = 20480
  • nRF mem_manager module (in mem_manager.c): TOTAL_MEMORY_SIZE  = 6400

The application code makes use of "malloc" and "free" in one 3rd party source module, other than than the heap is not explicitly (malloc, alloc, calloc, free) used in our application code as far as I'm aware.  We do make use of nrf_queues, Flash Data Storage module, mbedtls backend for aes_ccm, BLE services, FreeRTOS tasks, timer and queues, etc. (see configuration macros below). 

xPortGetFreeHeapSize returned 4504 immediately after performing some crypto functions using mbedTLS backend (with FreeRTOS debug printf'ing task disabled).

I couldn't get nrf_mem_diagnose() formatting to print nicely in debug terminal with FreeRTOS printf task enabled, but with a little manual editing, it appears the memory manager is using heap space, and it appears to be using all the chunks available:

+------------+------------+------------+------------+------------+------------+
| Block      | Size       | Total      | In Use     | Min Alloc  | Max Alloc  |
+------------+------------+------------+------------+------------+------------+
| Small      | 32         | 8          | 8          | 32         | 0          |
| Medium     | 64         | 8          | 8          | 64         | 0          |
| Large      | 128        | 8          | 8          | 128        | 0          |
| XLarge     | 256        | 2          | 2          | 256        | 0          |
| XXLarge    | 2048       | 2          | 2          | 2048       | 0          |

At first I thought any heap use would go through the memory manager, e.g. use of heap in FreeRTOS tasks would make use of memory manager, but looking at the map file, they are completely separate.  After seeing that, now I'm not sure which operations/code is using which heap and when, therefore I'm not able to easily figure out where I need to look when trying to optimize/reduce RAM usage.  For example, we receive data via our BLE service, memcpy the data from the service characteristic to another buffer in RAM, then notify our FreeRTOS task to operate on that RAM buffer, then the FreeRTOS task makes a call to mbedTLS backend, which calls mbedtls_free, which is the standard C free (I think), and so on. So my questions are:

  1. Can I trust that each of the modules are using the appropriate heap, is there overlap--where heap space is allocated in two different heaps for the same data?  Is there other mbedTLS/FreeRTOS/SoftDevice/nRF5 SDK configuration settings I can set so that I can combine the heaps to be a little bit more manageable/intuitive?  
  2. In the case where the application code uses explicit malloc/free, can the __HEAP_SIZE__ be adjusted to make sure there is just enough space available for only data?  Do I need to add a certain amount of bytes as overhead for other startup functions?
  3. Should nrf_crypto_aes API methods be used when performing encryption/decryption instead of accessing mbedtls_aes_ccm methods directly?
  4. If printf is used inside FreeRTOS tasks, which heap is used?
  5. If NRF_LOG_ENABLED is 1 (enabled) and calls such as NRF_LOG_DEBUG are used, which heap would it use--does it matter if its called within FreeRTOS task?
  6. printf seems to print to Debug Terminal window, should NRF_LOG_X calls also be printing to Debug Terminal or is there additional steps required to make that happen?

nRF configurations:

  • #define NRF_CRYPTO_ALLOCATOR 0
  • #define NRF_QUEUE_ENABLED 1
  • #define NRF_CRYPTO_BACKEND_MBEDTLS_ENABLED 1
  • #define NRF_CRYPTO_BACKEND_MBEDTLS_AES_CCM_ENABLED 1
  • #define NRF_CRYPTO_ALLOC(size) (nrf_malloc((uint32_t)(size)))
  • #define NRF_CRYPTO_FREE(p_buffer) (nrf_free((void *)(p_buffer)))
  • #define NRF_CRYPTO_ALLOC_ON_STACK 0
  • #define BLE_APP_ENABLED 1
  • #define NRF_SDH_ENABLED 1
  • #define NRF_LOG_ENABLED 0
  • #define NRF_SDH_BLE_LOG_ENABLED 1
  • #define NRF_SDH_LOG_ENABLED 1
  • #define NRF_SDH_SOC_LOG_ENABLED 1

FreeRTOS configuration:

  • #define configUSE_TIMERS 1
  • #define configSUPPORT_DYNAMIC_ALLOCATION 1
  • #define portUSING_MPU_WRAPPERS 0

mbedTLS configuration:

  • #define MBEDTLS_PLATFORM_MEMORY
  • #define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
  • #define MBEDTLS_PLATFORM_C
  • #define MBEDTLS_PLATFORM_STD_MEM_HDR <stdlib.h>
  • #define MBEDTLS_PLATFORM_STD_CALLOC calloc
  • #define MBEDTLS_PLATFORM_STD_FREE free
Related