FreeRTOS Deep Dive · Part 8 of 8

Debugging & Trace with Tracealyzer

FreeRTOS STM32 Advanced Source Code
FreeRTOS Part 8
FreeRTOS Deep Dive — Part 8
Debugging & Trace with Tracealyzer
50:40
Part 8 / 8
50:40
Advanced
FreeRTOS v10 · STM32F4
01

Overview

RTOS bugs are hard to debug with printf — the scheduler hides timing issues that only appear under load. This part covers FreeRTOS's built-in trace facilities, per-task CPU usage with runtime stats, and how to use Tracealyzer to visually identify priority inversion, starvation, and missed deadlines.

  • Enable runtime stats to measure per-task CPU usage as a percentage
  • Use vTaskList() to dump all task states and watermarks to UART
  • Integrate Percepio Tracealyzer for visual timeline debugging
  • Identify priority inversion, starvation, and CPU hogs from trace recordings
02

Debug Tools

📋
vTaskList()
Dumps a table of all tasks: name, state, priority, stack watermark, and number. Print over UART from a monitor task.
configUSE_TRACE_FACILITY = 1
📊
Runtime Stats
Measures CPU time consumed per task. Requires a 10–100× faster free-running counter. Shows % CPU per task.
configGENERATE_RUN_TIME_STATS = 1
🔬
Tracealyzer
Records timestamped FreeRTOS API events. Visualises task execution, preemptions, and CPU load on a timeline.
Percepio FreeRTOS+Trace
03

Code

01
Runtime stats + vTaskList UART dump
debug_monitor.c
C
#define configUSE_TRACE_FACILITY         1
#define configGENERATE_RUN_TIME_STATS    1
#define configUSE_STATS_FORMATTING_FUNCS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() TIM2_Init()
#define portGET_RUN_TIME_COUNTER_VALUE()         TIM2->CNT

static char buf[1024];

void vDebugTask(void *pv) {
    while(1) {
        uart_puts("
== Tasks ==
");
        vTaskList(buf); uart_puts(buf);
        uart_puts("
== CPU ==
");
        vTaskGetRunTimeStats(buf); uart_puts(buf);
        uart_printf("
Free heap: %u
",xPortGetFreeHeapSize());
        vTaskDelay(pdMS_TO_TICKS(15000));
    }
}

void TIM2_Init(void) {
    __HAL_RCC_TIM2_CLK_ENABLE();
    TIM2->PSC = (HAL_RCC_GetPCLK1Freq()/1000000UL)-1;
    TIM2->ARR = 0xFFFFFFFF; TIM2->CR1 = TIM_CR1_CEN;
}
💡
Runtime counter must be faster than the tick
Set your timer to run at least 10× the tick frequency. At a 1kHz tick, a 1MHz TIM2 gives microsecond resolution and is a solid default.

Continue the Series

Work through all 8 parts of the FreeRTOS Deep Dive to master real-time embedded systems programming.