rtel wrote on Sunday, June 01, 2014:
There are two fairly common requests related to the memory allocation, both of which I think already have outstanding feature request tickets:
- Allowing static allocation.
Although not directly documented as such, there is actually already a mechanism for statically allocating the TCB and statck used by a task, but not for allocating the memory used by queues/semaphores/mutexes/etc.
It would be easy enough to add in a mechanism for statically allocating the memory for these other objects too - but there are a couple of issues that must be accounted for - firstly an unwelcome increase in the code size, and secondly increasing the complexity for end users (the more options and choices the more complex and confusing).
If static allocation is required for reasons of safety critical qualification then it is actually quite feasible to qualify heap_1.c, which cannot suffer non-determinism or memory fragmentation, so does not suffer the issues that safety critical systems try and avoid. It is really just a statically allocated array.
- Allow the heap to span multiple memory regions.
First a note about using the linker variables to dimension the heap rather than the configTOTAL_HEAP_SIZE constant. I am definitely not in favour of that as it is not portable even between different GCC projects, let along to the other 17 or so compilers for which there are official FreeRTOS ports. Also these linker variables are used by the standard library malloc and free, and I want to draw a clear distinction between the two methods (the standard library allocation and FreeRTOS allocation).
If you need a fixed size heap because your application just creates all the RTOS objects up front, then never deletes anything (which is the normal case), then the xPortGetFreeHeapSize() and xPortGetMinimumEverFreeHeapSize() functions can be used to see how much heap was actually used, then the configTOTAL_HEAP_SIZE variable can be adjusted accordingly.
It should also be noted that FreeRTOS keeps memory allocation in the portable layer as it is recognised than different embedded projects have very different memory allocation requirements. It is therefore always possible to just add in your own version of pvPortMalloc and vPortFree to do whatever you want, however…
…heap_4.c is the favoured memory allocation for all applications except the most trivial or the most safety critical. heap_4.c in effect keeps a linked list of free memory blocks, with the list jumping over the blocks that are allocated to the application. At initialisation time heap_4.c just creates one block that covers the entire memory region on the assumption there is only one contiguous heap. There is no reasons why heap_4.c could not be extended such that at initialisation time a linked list is set up whereby the first block covers the entire first contiguous heap areas, with the block pointing to the
second contiguous heap areas, with that block pointing to the next, and so on for however many heap areas there were.
Only the initialisation code would need to change. The code that allocates and frees memory would not need to change because to it the gaps in the memory that are actually gaps between separate heap areas would just look like gaps that were created by memory actually being allocated to the application.
The user could initialise such a heap scheme by passing in an array of structures, with each structure defining the start address and size of each available heap area. The function to do so could just be added to the heap_4.c implementation. Users with just a single array of memory (as per the current scheme) could ignore the new function, the more advanced users with complex memory maps could call the new function as a first step - before they create any RTOS primitives (tasks, queues, event groups, etc.).
One disadvantage of this scheme is that there is no way of telling the allocation function from which heap area it should allocate the RAM if there is more than one heap area in use. This is actually quite important as often one heap area will be in fast internal static RAM, which is a good place to store task stacks, and another heap area might be in a huge external RAM which may be much slower and not so suitable for use as a stack. Ideally when allocating you would want to say from which memory (fast or slow) the allocated block should come, and it might be best to ensure any changes cover that option too - although that could introduce incompatibilities…