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

Heap Size in Processor Expert

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

4 thoughts on “Using FreeRTOS with newlib and newlib-nano

  1. Hello, Erich

    This article is very interesting. Congratulations! A question: How can I implement heap 6 and newlib nano in a SDK project without Processor Expert in MCUXpresso? I noticed that MCUXpresso adopts heap 4, by default.

    Like

      • Thanks for the tips, Erich

        I just installed the FreeRTOS version you recommended. What is the version of this FreeRTOS? That is not explicit in the directory name. Is it a custom version?

        KDS SDK 2.0 FreeRTOS version is 8.2.3 and MCUXpresso SDK 2.2 FreeRTOS version is 9.0.0. In none of them, there is a heap_6.c file.

        Also, I haven’t found heap_6.c file in your FreeRTOS. I suppose I have to take heap_useNewlib.c file and rename it as heap_6.c and so add it to the project and remove heap_4.c, which is usually the default heap file used by SDK. Please correct me if I’m wrong…

        Thanks,

        Marco Coelho

        Like

      • Hi Marco,
        it is the version 9.0.0 with some of the upcoming features present on the ‘bleeding edge’ version from on https://sourceforge.net/p/freertos/code/HEAD/tree/, plus my extensions to support Segger SystemView and Percepio Tracealizer.
        And yes, what you are looking for is not heap_6.c, but heap_useNewlib.c. The name of the file does not matter at all. All what you need to make sure is to link only one version of the heap, I’m doing this with the configUSE_HEAP_SCHEME macro.

        I hope this helps,
        Erich

        Like

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