Use Cases ¶
Bare-metal “allow locks”: libC functions called in Thread and Handler mode ¶
This use case allows libc functions to be safely called from both the main context and interrupt context. It requires:
stm32_lock.hand the lock glue file matching the selected compiler (GCC:GCC/newlib_lock_glue.c, ARMCC:ARM/armlib_lock_glue.c, IAR:IAR/dlib_lock_glue.c).STM32_THREAD_SAFE_BAREMETAL_ALLOW_LOCKS=1defined in the build configuration.
Example (
malloc
/
free
from ISR and main):
/* Allocation size (bytes) */
#define ALLOCATE_SIZE 100
/* HAL tick hook (called from TIM6 ISR): toggles malloc/free in ISR context */
void HAL_IncTick(void)
{
static uint32_t *address = NULL;
if (address == NULL)
{
address = (uint32_t *)malloc(ALLOCATE_SIZE);
if (address == NULL)
{
Error_Handler();
}
}
else
{
free(address);
address = NULL;
}
}
/* Main context: toggles malloc/free in an infinite loop */
void app_allocatefree_task_entry(void)
{
static uint32_t *address_task = NULL;
for (;;)
{
if (address_task == NULL)
{
address_task = (uint32_t *)malloc(ALLOCATE_SIZE);
if (address_task == NULL)
{
Error_Handler();
}
}
else
{
free(address_task);
address_task = NULL;
}
}
}
FreeRTOS “allow locks”: libc functions called in tasks (Thread mode) and Handler mode ¶
This use case protects libc calls across tasks and allows ISR usage within critical sections using
taskENTER_CRITICAL
/
taskENTER_CRITICAL_FROM_ISR. ISR sections must remain short. It requires:
stm32_lock.hand the lock glue file matching the selected compiler (GCC:GCC/newlib_lock_glue.c, ARMCC:ARM/armlib_lock_glue.c, IAR:IAR/dlib_lock_glue.c).STM32_THREAD_SAFE_FREERTOS_ALLOW_LOCKS=1andconfigUSE_NEWLIB_REENTRANT=1defined.
Implication: standard libc calls across tasks are protected; ISR usage is allowed within critical sections, but high-priority interrupts may not be masked.
Example (tasks allocate/free, HAL tick toggles
malloc
in ISR):
/* Sizes and limits */
#define ALLOCATE_SIZE 100
#define MAXENTRY_ALLOCATE 20
#define MEM_GUARD 0x55
/* Optional protection (simple mutex) for shared data access */
static SemaphoreHandle_t mutex;
#define PROTECT_INIT() do { mutex = xSemaphoreCreateMutex(); } while (0)
#define PROTECT_ENTER() do { xSemaphoreTake(mutex, portMAX_DELAY); } while (0)
#define PROTECT_EXIT() do { xSemaphoreGive(mutex); } while (0)
/* Shared table */
static volatile uint32_t allocate_table[MAXENTRY_ALLOCATE];
/* HAL tick ISR: toggle malloc/free with a small bound */
void HAL_IncTick(void)
{
static uint32_t *p = NULL;
if (p == NULL)
{
p = (uint32_t *)malloc(ALLOCATE_SIZE);
if (p == NULL)
{
Error_Handler();
}
}
else
{
free(p);
p = NULL;
}
}
/* Allocate task: fills entries */
static void app_allocate_task(void *arg)
{
(void)arg;
for (;;)
{
for (uint32_t i = 0; i < MAXENTRY_ALLOCATE; i++)
{
uint32_t *addr;
PROTECT_ENTER();
addr = (uint32_t *)allocate_table[i];
PROTECT_EXIT();
if (addr == NULL)
{
addr = (uint32_t *)malloc(ALLOCATE_SIZE);
if (addr == NULL)
{
Error_Handler();
}
*addr = MEM_GUARD; /* Touch. */
PROTECT_ENTER();
allocate_table[i] = (uint32_t)addr;
PROTECT_EXIT();
}
}
}
}
/* Free task: drains entries */
static void app_free_task(void *arg)
{
(void)arg;
for (;;)
{
for (int i = (int)MAXENTRY_ALLOCATE - 1; i >= 0; i--)
{
uint32_t *addr;
PROTECT_ENTER();
addr = (uint32_t *)allocate_table[i];
allocate_table[i] = 0;
PROTECT_EXIT();
free(addr);
}
vTaskDelay(2);
}
}