Using FreeRTOS with newlib and newlib-nano

For reliable applications, I avoid using functions of the standard libraries. They are banned for most safety related applications anyway. I do not use or avoid malloc(), printf() and all the other variants, for many reasons including the ones listed in “Why I don’t like printf()“. Instead, I’m using smaller variants (see “XFormat“). Or I’m using only the thread-safe FreeRTOS heap memory allocation which exist for many good reasons.

Things get problematic if malloc() still is pulled in, either because it is used by a middleware (e.g. TCP/IP stack) or if using C++. Dave Nadler posted a detailed article (http://www.nadler.com/embedded/newlibAndFreeRTOS.html) about how to use newlib and newlib-nano with FreeRTOS.

FreeRTOS Newlib Memory Allocation Scheme

FreeRTOS Newlib Memory Allocation Scheme

The problem with malloc() is not only that it can lead to heap fragmentation and a failure of the program at runtime. In many libraries, it is not reentrant or thread-safe (see https://stackoverflow.com/questions/855763/is-malloc-thread-safe). Using malloc() from a thread or from an interrupt is most likely a very dangerous thing!

Heap_3

Avoid using malloc() is a good approach. But things get difficult if malloc() is used in libraries or middleware stacks. Many USB and TCP/IP stacks use malloc().

Using two different heap implementations (one for FreeRTOS, the other for the middleware) does not make much sense. FreeRTOS offers a thread-safe wrapper to malloc()(wrapper to the newlib malloc() (heap_4.c):

FreeRTOS Thread Safe Malloc Wrapper

FreeRTOS Thread Safe Malloc Wrapper

But that wrapper is effective if the application uses the FreeRTOS API functions pvPortMalloc() and vPortFree(). So what I ended up is changing the middleware sources to use  pvPortMalloc() and vPortFree() instead.

But what if it is not possible to change the library sources? The GNU gcov (coverage) library is one example. This usually is only available as binary library, and rebuilding the GNU library is a challenge on its own (see “GNU Libs with Debug Information: Rebuilding the GNU ARM Libraries“). Even worse: if using C++, then very likely it is using malloc() and variants in the background.

configUSE_NEWLIB_REENTRANT

FreeRTOS offers the configUSE_NEWLIB_REENTRANT setting:

configUSE_NEWLIB_REENTRANT

configUSE_NEWLIB_REENTRANT

With this turned on, FreeRTOS uses a newlib reentrant structure (see this FreeRTOS discussion). This requires several hooks implemented, for details please read Dave’s article.

Newlib FreeRTOS Heap Implementation

The solution is a new FreeRTOS heap allocation scheme:

FreeRTOS Newlib Memory Allocation Scheme

💡 At the time of writing this article, the settings above are available in the implementation on GitHub, but not in the 06-May-2017 SourceForge release.

Heap Base, Limit and Size

With using the new Scheme 6, obviously the normal FreeRTOS heap size setting is not used (configTOTAL_HEAP_SIZE).

The Heap 6 implementation with using newlib needs three symbols defined by the linker:

  • Heap Base (default __HeapBase): start address of heap
  • Heap Limit (default __HeapLimit): end address of heap
  • Heap size (default __heap_size): size of the heap memory in bytes

The symbol settings are available in the FreeRTOS Processor Expert component:

Linker Heap Symbols

Linker Heap Symbols

The real symbol names depend on your system and linker file. Processor Expert projects for example use __heap_size:

__heap_size = 0x00; /* required amount of heap */
__heap_size

__heap_size

The heap size is configured in the CPU settings:

Heap Size in Processor Expert Settings

Heap Size in Processor Expert Settings

Freescale/NXP Kinetis SDK projects use HEAP_SIZE:

HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400;
HEAP_SIZE

HEAP_SIZE

The two other symbols are for the start and the end of the heap, by default __HeapBase and __HeapLimit. Typically they are like this in the linker file (example from Kinetis Design Studio):

 /* User_heap_stack section, used to check that there is enough RAM left */
 ._user_heap_stack :
 {
   . = ALIGN(4);
   PROVIDE ( end = . );
   PROVIDE ( _end = . );
   PROVIDE ( __end__ = . );
   __heap_addr = .;
   __HeapBase = .;
   . = . + __heap_size;
   __HeapLimit = .;
   . = . + __stack_size;
   . = ALIGN(4);
 } > m_data

MCUXpresso IDE does this:

 .heap : ALIGN(4)
 {
 _pvHeapStart = .;
 . += 0xa000;
 . = ALIGN(4);
 _pvHeapLimit = .;
 } > SRAM_UPPER

As shown above, there is no defined symbol for the HEAP_SIZE. This can be added to the MCUXpresso IDE:

  1. Have a folder named ‘linkscripts’ in the project root
  2. Add a file named ‘user.ldt’
  3. Add the following content to the file:
    HEAP_SIZE = ${HEAP_SIZE};
HEAP_SIZE Symbol with Managed Linker Scripts in MCUXpresso IDE

HEAP_SIZE Symbol with Managed Linker Scripts in MCUXpresso IDE

Otherwise, check your linker file for the correct symbols. If not, you have to add them.

With this, you can use FreeRTOS with newlib memory allocation in a safe and reentrant way :-).

Summary

Using newlib and newlib-nano and its memory allocation routines are problematic, especially to use it in a reentrant and thread-safe way. Malloc() can get used as a side effect with calling functions like printf(), strtok() and others in the ‘black box’ of newlib. If you have to use things of newlib or newlib-nano, then make sure you use configUSE_NEWLIB_REENTRANT with the heap_useNewlib.c from Dave Nadler.

I have integrated Dave’s work into FreeRTOS, including a port to Processor Expert. If you want to check out the implementation, see https://github.com/ErichStyger/McuOnEclipse_PEx/tree/master/Drivers/freeRTOS.

💡 Many thanks to Dave Nadler for investigating and searching for a solution and give it back to the community!

Happy Mallocing 🙂

Links

Advertisements

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s