> 技术文档 > 【STM32】CUBEMX下FreeRTOS 任务栈管理与栈溢出检测(CMSIS_V2接口)

【STM32】CUBEMX下FreeRTOS 任务栈管理与栈溢出检测(CMSIS_V2接口)


一、FreeRTOS 中的栈管理机制

在 FreeRTOS 中,每个任务都会分配一个独立的栈空间用于保存局部变量、上下文等。

✅ 相关宏配置:
宏名称 含义 configMINIMAL_STACK_SIZE 最小任务栈大小(单位:words) uxTaskGetStackHighWaterMark() 获取当前任务历史上最小的剩余栈空间(越小越危险) uxTaskGetSystemState() 获取所有任务的栈使用情况 configCHECK_FOR_STACK_OVERFLOW 是否开启栈溢出检测(值为 1 或 2) configUSE_TRACE_FACILITY 开启任务信息追踪(如任务名、栈) configUSE_STATS_FORMATTING_FUNCTIONS 开启格式化任务状态打印支持

二、FreeRTOS 栈溢出检测机制

🧪 启用检测:

CUBEMX配置参数:
【STM32】CUBEMX下FreeRTOS 任务栈管理与栈溢出检测(CMSIS_V2接口)

#define configUSE_TRACE_FACILITY 1#define configUSE_STATS_FORMATTING_FUNCTIONS 1#define configCHECK_FOR_STACK_OVERFLOW 2

configCHECK_FOR_STACK_OVERFLOW :

  • 1:简单检测方法,只在任务切换时检查栈顶哨兵值是否被改写。
  • 2:更强的检测方法,除了栈顶哨兵值,还检查栈底向上是否越界。
🛠 栈溢出钩子函数(CUBEMX自动生成):
extern void MX_LWIP_Init(void);void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) *//* Hook prototypes */void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName);/* USER CODE BEGIN 4 */void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName){ /* Run time stack overflow checking is performed if configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is called if a stack overflow is detected. */ printf(\"\\r\\n\"); printf(\"=============================================================\\r\\n\"); printf(\"!!!!  STACK OVERFLOW DETECTED !!!!\\r\\n\"); printf(\"=============================================================\\r\\n\"); printf(\">>> Task causing overflow : %s\\r\\n\", pcTaskName); printf(\">>> Taking emergency action: system halted\\r\\n\"); printf(\"=============================================================\\r\\n\"); // 关闭中断,进入死循环 taskDISABLE_INTERRUPTS(); for (;;);}/* USER CODE END 4 */

三、如何查看任务的剩余栈空间

使用 uxTaskGetSystemState()usStackHighWaterMark 获取每个任务曾经最小剩余栈空间

🧾 自定义打印函数:
void printTaskStackInfo(void){ TaskStatus_t taskStatusArray[24]; UBaseType_t taskCount, i; taskCount = uxTaskGetSystemState(taskStatusArray, 24, NULL); qsort(taskStatusArray, taskCount, sizeof(TaskStatus_t), compareTaskName); printf(\"\\r\\n+------------------+------------------------+------------------+\\r\\n\"); printf(\"| %-16s | %-22s | %-16s |\\r\\n\", \"任务名\", \"剩余栈空间 (words)\", \"剩余栈空间 (bytes)\"); printf(\"+------------------+------------------------+------------------+\\r\\n\"); for (i = 0; i < taskCount; i++) { const char *name = taskStatusArray[i].pcTaskName; UBaseType_t highWater = taskStatusArray[i].usStackHighWaterMark; printf(\"| %-16s | %-22u | %-16u |\\r\\n\", name, highWater, highWater * sizeof(StackType_t)); } printf(\"+------------------+------------------------+------------------+\\r\\n\");}
  • 输出结果:
    【STM32】CUBEMX下FreeRTOS 任务栈管理与栈溢出检测(CMSIS_V2接口)

四、FreeRTOS 任务模板函数(带栈使用示例)

void myTask(void *argument){ while (1) { // 模拟工作 vTaskDelay(pdMS_TO_TICKS(1000)); // 检查自身栈剩余空间(单位:words) UBaseType_t stackLeft = uxTaskGetStackHighWaterMark(NULL); if (stackLeft < 50) // 阈值根据实际栈大小设定 { printf(\"⚠️ Warning: task \'%s\' low stack: %lu words\\r\\n\", pcTaskGetName(NULL), stackLeft); } }}

五、建议:如何设置合适的任务栈大小?

  1. 开发初期可以设得大一点,如 512 words
  2. 启动任务后运行一段时间,调用 printTaskStackInfo()
  3. 看实际 剩余栈空间,酌情缩小分配。
  4. 建议保留 安全边际(>50 words),避免任务创建失败或运行中溢出。