Coming soon |
1. Introduction
An enhanced version of dynamic allocation is available with the STM32WBA: the Advanced Memory Manager. It eases dynamic allocations in a multitask/shared environment without adding much complexity.
The new features provided by AMM are the following:
- Support several Virtual Memories
- Minimum size warranty per Virtual Memory (QOS)
- Callback in case of memory allocation failure
2. Features
The Advanced Memory Manager comes on top of a Basic Memory Manager - Understand here anything capable of providing basic memory allocation features such as Alloc and Free – and add some new capabilities on top of it.
2.1. Basic Memory Manager and Heap
- The Basic Memory Manager (BMM)
- Can be anything that is capable to allocate/free memory
- Shall at least support the capability to merge into one single memory two continuous memories that has been freed (coalescence)
- Shall be provided by the user before any use of the AMM via the registration function
- The Heap
- Can either be a dedicated memory provided by the application, or the legacy default Heap provided by most application at link time
- Its size shall be at least equal to the sum of all Virtual Memories size
2.2. Virtual Memories
In a concurrent execution application, dynamic allocation can encounter some issues with heap sharing. For instance, a task may request a major part of the available heap leading to allocation failure for all other tasks requesting too much memory. To avoid that kind of issue, the Advanced Memory Manager introduces the concept of virtual memories and shared pool.
- The Virtual memory
- Dedicated user memory pool, ie: specific VM IDs.
- There to ensure to users the memory amount needed for minimal execution.
- The Shared pool
- Mutual memory pool, ie: Can be used by any virtual ID.
- Provide memory for an optimal execution.
- Its size corresponds to the BMM pool size minus the space required for the Virtual memories.
2.3. Retry callback
During program execution, users may encounter some memory allocation failure - Not enough memory available. Instead of setting up a polling mechanism, in an allocation request, the AMM offers the possibility to register a callback.
This callback inform the requester(in an asynchronous way) that some space has been freed - Either in the shared pool or in its dedicated virtual pool - and a new allocation request can be submitted.
In some cases, the memory can be freed from a different context than the one it has been allocated from. The Callback should not implement any active code and should be used only to set up a new allocation request from the main context.
2.3.1. Single callback case
2.3.2. Multiple callback case
3. Interface
Here comes a list of the available functions for AMM:
AMM_Init |
---|
Description
|
AMM_DeInit |
---|
|
AMM_Alloc |
---|
|
AMM_Free |
---|
|
AMM_BackgroundProcess |
---|
|
AMM_RegisterBasicMemoryManager |
---|
|
AMM_ProcessRequest |
---|
|
4. How to
The following chapters explain "how to" configure and use the Advanced Memory Manager.
4.1. Initialize the AMM
Before any use, AMM needs to be setup and there is few steps to do so.
4.1.1. Basic Memory Manager selection
First things first, you have to determine the Basic Memory Manager you are going to use.
As said above, it can be anything capable of allocation and free. The only mandatory point is coalescence.
In the following examples, the selected BMM will be the Memory manager utility - Already available in the current release under the memory manager folder- UTIL_MM_XXX ().
4.1.2. Basic Memory Manager registration
Once the BMM is identified, you have to register its functions to the AMM. To do so we need to create function wrappers since our BMM will not always fully match the expected function of the AMM register function:
- Definition:
static void AMM_WrapperInit (uint32_t * const p_PoolAddr, const uint32_t PoolSize); static uint32_t * AMM_WrapperAllocate (const uint32_t BufferSize); static void AMM_WrapperFree (uint32_t * const p_BufferAddr);
- Implementation:
static void AMM_WrapperInit (uint32_t * const p_PoolAddr, const uint32_t PoolSize) { UTIL_MM_Init ((uint8_t *)p_PoolAddr, ((size_t)PoolSize * sizeof(uint32_t))); } static uint32_t * AMM_WrapperAllocate (const uint32_t BufferSize) { return (uint32_t *)UTIL_MM_GetBuffer (((size_t)BufferSize * sizeof(uint32_t))); } static void AMM_WrapperFree (uint32_t * const p_BufferAddr) { UTIL_MM_ReleaseBuffer ((void *)p_BufferAddr); }
Once wrappers are defined, register function is the next function to implement - Definition is already done in the AMM header file. The AMM will call this function at its initialization so we have to provide pointer onto the newly declared wrappers:
- Implementation:
void AMM_RegisterBasicMemoryManager (AMM_BasicMemoryManagerFunctions_t * const p_BasicMemoryManagerFunctions) { /* Fulfill the function handle */ p_BasicMemoryManagerFunctions->Init = AMM_WrapperInit; p_BasicMemoryManagerFunctions->Allocate = AMM_WrapperAllocate; p_BasicMemoryManagerFunctions->Free = AMM_WrapperFree; }
With this steps over, the BMM will be linked up with the AMM and fully operational. Next step is the configuration of the AMM.
4.1.3. Configure the AMM
The Advanced memory manager configuration is done at initialization and the parameters are the following:
typedef struct AMM_InitParameters
{
/* Address of the pool of memory to manage */
uint32_t * p_PoolAddr;
/* Size of the pool with a multiple of 32bits.
ie: PoolSize = 4; TotalSize = PoolSize * 32bits
= 4 * 32bits
= 128 bits */
uint32_t PoolSize;
/* Number of Virtual Memory to create */
uint32_t VirtualMemoryNumber;
/* List of the Virtual Memory configurations */
AMM_VirtualMemoryConfig_t a_VirtualMemoryConfigList[];
}AMM_InitParameters_t;
The AMM configuration is a two steps procedure:
- Establish the Virtual Memory + Shared pool configurations (How many VMs, What size, etc)
- Adapt the pool size and location of the AMM according to the configuration firstly determined
- Virtual Memory and Shared pool configurations
-
- Virtual Memories configurations
- There are 3 characteristics to identify: The number of VMs, the proper size of each VM and their IDs.
- The Number of VMs
- To determine the number of needed Virtual Memories, you have to identify the number of process that need their own heap for their nominal operating. You shall consider one Virtual Memory for one of these process.
- The Size of each VMs
- The size of each Virtual Memory will be determined by the process needs. Each Virtual Memory shall be sized to the process nominal heap value. Do not forget that the Virtual Memory size is set on a 32bits basis.
- The ID of each VMs
- For each VM, you can define an unique ID. This will be used to access the proper Virtual Memory during memory operation.
- Shared Pool configuration
-
- Shared Pool Size
- Regarding the Shared Pool size, its size is up to you. The shared pool is designed to allow an optimal execution of each process that need a little bit of heap, once in a while, to perform better.
- The Shared Pool Size is not a proper parameter of AMM initialization. However, it must be defined to determine the whole AMM required pool space. This concept also ease the AMM comprehension and enhance its configuration - This leads to a better optimization of the required space.
- AMM pool configuration
- Both Virtual Memory configuration and Shared Pool configuration determine the required amount of memory for the AMM.
This AMM pool size can be represented as follow:
- Start Address
- The start address can either be a heap located address or a static buffer used as a memory pool.
- In this example, we are using a static allocated buffer.
static uint32_t AMM_Pool[CFG_AMM_POOL_SIZE];
- Pool Size
- The pool size is main point of all the AMM configuration.
4.2. Allocate memory
With and without callback
4.3. Free memory
TBD.
5. Example
5.1. Two virtual memories configuration
TBD.
6. Revisions