Choosing your RTOS heap implementation

So, how do you go about choosing which heap implementation to use? First, you need to ensure that you're able to use dynamic allocation (many standards for safety-critical applications disallow it). If you don't need to free allocated memory, then heap_1.c is a potential option (as is avoiding a heap entirely).

From a coding perspective, the main difference between using heap_1 and static allocation is when the checks for memory availability are performed. When using the *CreateStatic variants, you'll be notified at link time that you don't have enough memory to support the newly created primitive. This requires a few extra lines of code each time a primitive is created (to allocate buffers used by the primitive). When using heap_1, as long as checks are performed (see Chapter 7, The FreeRTOS Scheduler) to determine task creation success, then the checking will be performed at runtime. Many applications that are appropriate for the heap_1 implementation will also create all required tasks before starting the scheduler. Using dynamic memory allocation in this way isn't much different from static allocation; it simply moves the checking from link time to runtime, while reducing the amount of code required to create each RTOS primitive.

If you're working on an application that only requires one datatype to be freed, heap_2 might be an option. If you choose to go down this route, you'll need to be very careful to document this limitation for future maintainers of the code. Failure to understand the limited use case of heap_2 can easily result in memory fragmentation. In the worst-case scenario, fragmentation might potentially occur after the application has been running for an extended period of time and might not occur until the final code has been released and the hardware is fielded.

When dynamic memory is used, then heap_3, heap_4, or heap_5 can be used. As mentioned earlier, heap_3 simply wraps whatever C runtime implementation of malloc and free is available, to make it thread safe so it can be used by multiple tasks. This means that its behavior is going to be dependent on the underlying runtime implementation. If your system has RAM in several different, noncontiguous memory locations (for example, internal and external RAM) then heap_5 can be used to combine all of these locations into one heap; otherwise, heap_4 provides the same allocation, freeing, and adjacent block collation capabilities as heap_5. These are the two general-purpose heap implementations. Since they include code that will collate free blocks, it is possible that they will run for different periods of time when freeing memory. In general, it is best to avoid calls to vPortMalloc and vPortFree in code that requires a high degree of determinism. In heap_4 and heap_5, calls to vPortFree will have the most amount of timing variability, since this is when adjacent block collation occurs.

In general, avoiding dynamic allocation will help to provide more robust code with less effort—memory leaks and fragmentation are impossible if memory is never freed. On the other end of the spectrum, if your application makes use of standard library functions, such as printf and string manipulation, you'll likely need to replace the versions of malloc and free that were included with thread-safe implementations. Let's take a quick look at what's involved in making sure other parts of the application don't end up using a heap implementation that isn't thread safe.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.107.90