Mastering FreeRTOS Task Scheduling on STM32
When transitioning from a simple super-loop (while(1)) architecture to a Real-Time Operating System (RTOS), understanding the scheduler’s behavior is vital for predictable and crash-free execution.
In this article, we dissect how FreeRTOS manages task context switching on ARM Cortex-M4 cores (STM32F4/G4 series) and how to avoid classic concurrency pitfalls.
The Cortex-M PendSV Exception
FreeRTOS relies on the PendSV (Pended Service Call) exception to perform context switches safely. Unlike hardware ISRs that must execute with minimal latency, PendSV is configured with the lowest interrupt priority.
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
static SemaphoreHandle_t xSensorMutex = NULL;
void vSensorTask(void *pvParameters) {
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = pdMS_TO_TICKS(10); // 100 Hz
for (;;) {
if (xSemaphoreTake(xSensorMutex, portMAX_DELAY) == pdTRUE) {
// Read I2C sensor data
read_imu_registers();
xSemaphoreGive(xSensorMutex);
}
// Deterministic rate execution
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
Priority Inversion & Mutex Inheritance
Priority inversion occurs when a low-priority task holds a shared resource needed by a high-priority task, while a medium-priority task preempts the low-priority task.
Solution: Priority Inheritance Mutexes
Always use FreeRTOS Mutexes (xSemaphoreCreateMutex()) rather than binary semaphores for shared resources because mutexes implement automatic priority inheritance.
void app_main_init(void) {
xSensorMutex = xSemaphoreCreateMutex();
configASSERT(xSensorMutex != NULL);
xTaskCreate(vSensorTask, "IMU_Task", 256, NULL, 3, NULL);
xTaskCreate(vTelemetryTask, "Radio_Task", 512, NULL, 2, NULL);
}
Stack Sizing Guidelines
| Task Name | Recommended Stack (Words) | Critical Operations |
|---|---|---|
Sensor_Task | 256 words (1024 B) | I2C/SPI DMA triggers |
Network_Task | 512 words (2048 B) | Packet framing & CRC32 |
CLI_Task | 192 words (768 B) | UART string parsing |
Always enable configCHECK_FOR_STACK_OVERFLOW = 2 during development to catch stack overflows before they reach production hardware.
Habib Rahman
@habibrahmanFirmware & Embedded Systems Engineer. Exploring bare-metal C, FreeRTOS, Linux kernel, and hardware telemetry.