STM32创建FreeRTOS互斥量后HAL Tick停滞问题求助
问题:创建FreeRTOS互斥量后HAL Tick计时器停止增长
环境信息
- 开发环境:STM32CubeIDE 1.11.2
- 代码生成工具:CubeMX 6.7.0
- 测试平台:Nucleo-F767ZI
复现步骤
- 在STM32CubeIDE中新建默认配置的STM32项目;
- 在MX视角打开ioc文件,添加CMSIS_V2接口的FreeRTOS支持;
- 在
main.c的osKernelInitialize()后添加以下代码:
osMutexId_t mutex = osMutexNew(0); HAL_Delay(100);
现象
代码卡在HAL_Delay()中,SysTick_Handler不再被调用,HAL_GetTick()始终返回固定值(测试中为10)。已尝试使用CMSIS及FreeRTOS原生互斥量函数、更换SysTick时基、更换Nucleo开发板,问题均未解决。
问题分析与解决
核心原因
在操作系统内核未启动的阶段调用了FreeRTOS互斥量创建函数osMutexNew(),会触发FreeRTOS内部的临界区操作,但此时内核调度器尚未启动,SysTick的调度定时器逻辑被破坏,最终导致HAL Tick停止更新。
osKernelInitialize()仅完成内核初始化,调度器并未启动,FreeRTOS的核心调度逻辑(包括SysTick接管)还未进入正常工作状态。此时调用内核对象创建函数会打乱系统定时器的正常执行流程,而后续的HAL_Delay()依赖SysTick计时,自然会卡住。
解决方法
将互斥量创建及HAL_Delay()的调用移到内核启动之后(即osKernelStart()执行完毕后),或者直接在CubeMX预留的内核对象创建块中操作,避免在osKernelInitialize()和osKernelStart()之间调用依赖调度的API。
方案一:移至内核启动后
修改main.c代码如下:
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Init scheduler */ osKernelInitialize(); /* Create the mutexes */ /* USER CODE BEGIN RTOS_MUTEX */ /* 可在此块创建互斥量,但不要调用HAL_Delay */ /* USER CODE END RTOS_MUTEX */ /* Create the thread(s) */ /* USER CODE BEGIN RTOS_THREADS */ /* USER CODE END RTOS_THREADS */ /* Start scheduler */ osKernelStart(); /* USER CODE BEGIN 3 */ // 内核启动后执行以下操作 osMutexId_t mutex = osMutexNew(0); HAL_Delay(100); /* USER CODE END 3 */ while (1) { } }
方案二:在预留块中创建互斥量(推荐)
直接在CubeMX生成的RTOS_MUTEX注释块中创建互斥量,确保调度器启动前完成对象初始化,之后在任务中调用HAL_Delay():
/* Create the mutexes */ /* USER CODE BEGIN RTOS_MUTEX */ osMutexId_t mutex = osMutexNew(0); /* USER CODE END RTOS_MUTEX */ /* Create the thread(s) */ /* USER CODE BEGIN RTOS_THREADS */ osThreadNew(TaskFunction, NULL, &TaskAttributes); /* USER CODE END RTOS_THREADS */ // 任务函数示例 void TaskFunction(void *argument) { for(;;) { HAL_Delay(100); osDelay(100); // 推荐使用FreeRTOS原生延时API } }
补充说明
- FreeRTOS内核对象(互斥量、队列、线程等)建议在调度器启动前创建,CubeMX预留的
RTOS_MUTEX、RTOS_THREADS块就是为此设计的。 HAL_Delay()依赖SysTick,而FreeRTOS启动后会接管SysTick作为调度定时器,因此不能在调度器未启动时调用HAL_Delay(),推荐在任务中使用FreeRTOS原生的osDelay()或vTaskDelay()。
内容的提问来源于stack exchange,提问作者Gwen
相关产品推荐
相关产品推荐

