FreeRTOS Task Sizing Guide
This guide covers how to calculate worst-case stack depth for FreeRTOS tasks, choose the right heap allocation scheme, and detect stack overflow before it corrupts memory silently.
Why task stack sizing matters
FreeRTOS allocates each task a fixed stack at creation time. Overflow doesn't always crash immediately — it silently corrupts adjacent memory, producing bugs that are hard to reproduce and nearly impossible to bisect.
Step 1 — Estimate worst-case stack depth
For each task, trace the deepest call chain:
- Start from the task function entry point
- Add the stack frame of every nested call (local variables + return address + saved registers)
- Add the ISR epilogue overhead if the task can be preempted mid-call
- Add a 20–30% safety margin
Use uxTaskGetStackHighWaterMark() in development to measure actual peak usage and validate your estimate.
Step 2 — Choose the right heap scheme
| Scheme | Allocates | Frees | Use when |
|---|---|---|---|
| heap_1 | ✓ | ✗ | Static allocation only, no vTaskDelete |
| heap_2 | ✓ | ✓ (no coalesce) | Fixed-size blocks, no fragmentation risk |
| heap_3 | Wraps malloc/free | ✓ | Porting existing code |
| heap_4 | ✓ | ✓ + coalesce | General use — most common choice |
| heap_5 | ✓ | ✓ + non-contiguous | Multiple RAM regions |
heap_4 is the right default for most embedded Linux-free FreeRTOS projects.
Step 3 — Enable overflow detection
Add to FreeRTOSConfig.h:
#define configCHECK_FOR_STACK_OVERFLOW 2
Implement the hook:
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
(void)xTask;
/* Log pcTaskName, halt, or reset */
configASSERT(0);
}
Mode 2 checks the stack watermark pattern on every context switch — small overhead, catches most overflows.
Common mistakes
- Sizing for happy path only — recursive calls,
printf/sprintf, and floating-point operations all consume more stack than they look - Forgetting ISR stack sharing — on Cortex-M, ISRs use the MSP, not the task stack; account for this separately
- Using
heap_3in production — it re-entersmalloc, which is not thread-safe without the mutex wrapper