Malloc is a function provided by the C standard library which is used to dynamically allocate memory. It uses a low-level memory management function, called sbrk, to determine if the heap has available space. Silicon Labs provides a simple implementation of sbrk, designed for compatibility between all projects. Due to this, it can exhibit a strange behavior where calls to malloc will not return a NULL, even if the heap is full. If an application requires dynamic memory allocation, sbrk will need to be modified to prevent this issue.
For bare-metal applications:
A sample sbrk implementation, which should work with most MCU projects, is provided below. This implementation checks the MSP to determine how much stack space is available. To add this implementation to a project, open “retargetio.c”, which is usually found in the folder “hal-efr32”. Find the sbrk implementation within that file and replace it with the one found below.
#include <sys/stat.h>
extern char _end; /**< Defined by the linker */
caddr_t _sbrk(int incr)
{
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &_end;
}
prev_heap_end = heap_end;
if ((heap_end + incr) > (char*) __get_MSP()) {
//errno = ENOMEM;
return ((void*)-1); // error - no more memory
}
heap_end += incr;
return (caddr_t) prev_heap_end;
}
This example may not work for every example application since different applications configure memory differently. For example, the Bluetooth stack puts the stack at the beginning of RAM, so the MSP can not be used to determine the end of the heap. For this setup, you will need to use an sbrk implementation like the one below. This implementation uses "__HeapLimit", which is defined by the linker, to determine where the heap ends.
#include <sys/stat.h>
extern char _end; /**< Defined by the linker */
extern char __HeapLimit; /**< Defined by the linker */
caddr_t _sbrk(int incr)
{
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0) {
heap_end = &_end;
}
prev_heap_end = heap_end;
if ((heap_end + incr) > (char*) &__HeapLimit) {
//errno = ENOMEM;
return ((void*)-1); // error - no more memory
}
heap_end += incr;
return (caddr_t) prev_heap_end;
}
In general, keep your application's memory layout in mind when using malloc, and modify sbrk to fit.
For RTOS applications:
The above implementations of sbrk can be used in a multi-threaded environment, but with the caveat that they are not thread-safe. This can be circumvented by wrapping calls to memory management functions in critical sections. Additionally, most RTOSes will provide implementations of dynamic memory allocation. For example, MicirumOS provides a memory management API that can be used instead of the standard library implementations.
32-bit Knowledge Base
Malloc and sbrk
Malloc is a function provided by the C standard library which is used to dynamically allocate memory. It uses a low-level memory management function, called sbrk, to determine if the heap has available space. Silicon Labs provides a simple implementation of sbrk, designed for compatibility between all projects. Due to this, it can exhibit a strange behavior where calls to malloc will not return a NULL, even if the heap is full. If an application requires dynamic memory allocation, sbrk will need to be modified to prevent this issue.
For bare-metal applications:
A sample sbrk implementation, which should work with most MCU projects, is provided below. This implementation checks the MSP to determine how much stack space is available. To add this implementation to a project, open “retargetio.c”, which is usually found in the folder “hal-efr32”. Find the sbrk implementation within that file and replace it with the one found below.
This example may not work for every example application since different applications configure memory differently. For example, the Bluetooth stack puts the stack at the beginning of RAM, so the MSP can not be used to determine the end of the heap. For this setup, you will need to use an sbrk implementation like the one below. This implementation uses "__HeapLimit", which is defined by the linker, to determine where the heap ends.
In general, keep your application's memory layout in mind when using malloc, and modify sbrk to fit.
For RTOS applications:
The above implementations of sbrk can be used in a multi-threaded environment, but with the caveat that they are not thread-safe. This can be circumvented by wrapping calls to memory management functions in critical sections. Additionally, most RTOSes will provide implementations of dynamic memory allocation. For example, MicirumOS provides a memory management API that can be used instead of the standard library implementations.