The RTOS kernel needs RAM each time a task, queue, mutex, software timer, semaphore or event group is created. The RAM can be automatically dynamically allocated from the RTOS heap within the RTOS API object creation functions, or it can be provided by the application writer.
If RTOS objects are created dynamically then the standard C library malloc() and free() functions can sometimes be used for the purpose, but ...
One embedded / real time system can have very different RAM and timing requirements to another - so a single RAM allocation algorithm will only ever be appropriate for a subset of applications.
To get around this problem, FreeRTOS keeps the memory allocation API in its portable layer. The portable layer is outside of the source files that implement the core RTOS functionality, allowing an application specific implementation appropriate for the real time system being developed to be provided. When the RTOS kernel requires RAM, instead of calling malloc(), it instead calls pvPortMalloc(). When RAM is being freed, instead of calling free(), the RTOS kernel calls vPortFree().
FreeRTOS offers several heap management schemes that range in complexity and features. It is also possible to provide your own heap implementation, and even to use two heap implementations simultaneously. Using two heap implementations simultaneously permits task stacks and other RTOS objects to be placed in fast internal RAM, and application data to be placed in slower external RAM.
Each provided implementation is contained in a separate source file (heap_1.c, heap_2.c, heap_3.c, heap_4.c and heap_5.c respectively) which are located in the Source/Portable/MemMang directory of the main RTOS source code download. Other implementations can be added as needed. Exactly one of these source files should be included in a project at a time [the heap defined by these portable layer functions will be used by the RTOS kernel even if the application that is using the RTOS opts to use its own heap implementation].
Following below:
The implementation simply subdivides a single array into smaller blocks as RAM is requested. The total size of the array (the total size of the heap) is set by configTOTAL_HEAP_SIZE - which is defined in FreeRTOSConfig.h. The configAPPLICATION_ALLOCATED_HEAP FreeRTOSConfig.h configuration constant is provided to allow the heap to be placed at a specific address in memory.
The xPortGetFreeHeapSize() API function returns the total amount of heap space that remains unallocated, allowing the configTOTAL_HEAP_SIZE setting to be optimised.
The heap_1 implementation:
The total amount of available heap space is set by configTOTAL_HEAP_SIZE - which is defined in FreeRTOSConfig.h. The configAPPLICATION_ALLOCATED_HEAP FreeRTOSConfig.h configuration constant is provided to allow the heap to be placed at a specific address in memory.
The xPortGetFreeHeapSize() API function returns the total amount of heap space that remains unallocated, (allowing the configTOTAL_HEAP_SIZE setting to be optimised), but does not provided information on how the unallocated memory is fragmented into smaller blocks.
This implementation:
This implementation:
The total amount of available heap space is set by configTOTAL_HEAP_SIZE - which is defined in FreeRTOSConfig.h. The configAPPLICATION_ALLOCATED_HEAP FreeRTOSConfig.h configuration constant is provided to allow the heap to be placed at a specific address in memory.
The xPortGetFreeHeapSize() API function returns the total amount of heap space that remains unallocated when the function is called, and the xPortGetMinimumEverFreeHeapSize() API function returns lowest amount of free heap space that has existed system the FreeRTOS application booted. Neither function provides information on how the unallocated memory is fragmented into smaller blocks.
This implementation:
Heap_5 is initialised by calling vPortDefineHeapRegions(), and cannot be used until after vPortDefineHeapRegions() has executed. Creating an RTOS object (task, queue, semaphore, etc.) will implicitly call pvPortMalloc() so it is essential that, when using heap_5, vPortDefineHeapRegions() is called before the creation of any such object.
vPortDefineHeapRegions() takes a single parameter. The parameter is an array of HeapRegion_t structures. HeapRegion_t is defined in portable.h as typedef struct HeapRegion { /* Start address of a block of memory that will be part of the heap.*/ uint8_t *pucStartAddress; /* Size of the block of memory. */ size_t xSizeInBytes; } HeapRegion_t; The HeapRegion_t type definition
The array is terminated using a NULL zero sized region definition, and the
memory regions defined in the array must appear in address order, from
low address to high address. The following source code snippets provide an
example. The
MSVC Win32 simulator demo
also uses heap_5 so can be used as a reference.
/* Allocate two blocks of RAM for use by the heap. The first is a block of 0x10000 bytes starting from address 0x80000000, and the second a block of 0xa0000 bytes starting from address 0x90000000. The block starting at 0x80000000 has the lower start address so appears in the array fist. */ const HeapRegion_t xHeapRegions[] = { { ( uint8_t * ) 0x80000000UL, 0x10000 }, { ( uint8_t * ) 0x90000000UL, 0xa0000 }, { NULL, 0 } /* Terminates the array. */ }; /* Pass the array into vPortDefineHeapRegions(). */ vPortDefineHeapRegions( xHeapRegions ); Initialising heap_5 after defining the memory blocks to be used by the heap
The xPortGetFreeHeapSize() API function returns the total amount of heap space
that remains unallocated when the function is called, and the xPortGetMinimumEverFreeHeapSize()
API function returns lowest amount of free heap space that has existed system the
FreeRTOS application booted. Neither function provides information on how the unallocated
memory is fragmented into smaller blocks.