最近做项目时使用到了FreeRTOS,之前是通过手动移植源码的方式完成的,这次习惯性的使用Keil自带的包管理器创建工程,结果踩了巨多的坑,浪费了大量的时间在调试上,特此记录一下。
首先说明一下我创建工程的过程:
1.使用CudeMX生成工程文件。注意这里没有将FreeRTOS这些组件包括进去,仅仅生成HAL库相关代码。
2.使用Keil创建FreeRTOS工程,包管理器的选择如下:
3.将CubeMX生成代码的有用部分重组,变为我习惯的代码编写形式。
4.开始编写工程。
这里遇到了第一个问题:
haltick设置
在CubeMX生成代码时,如果你选中了FreeRTOS的组件,那么它大概率会提醒你:
说是不建议OS和HAL同时使用SysTick作为系统节拍。
使用了FreeRTOS会强制使用systick作为自己的心跳,这个os_tick的优先级是最低的,它主要的作用就是OS任务调度,时间片查询等工作。如果HAL也设置成systick,优先级最低,那么在高优先级(优先级高于systick) 中断服务函数中调用HAL_Delay()就会导致错误。
于是我把HAL时钟设为了TIM11。
紧接着就遇到了第二个问题
中断优先级分组和配置最低中断优先级
我之前一直不知道FreeRTOS是如何配置中断分组的,只是看野火资料说分组为4,就一直这么用的。这次就出问题了:只要一添加第二个任务系统马上就进入HardFault_Handler()
,这个问题困扰了我好几天。发现将OS的Tickless功能关闭后问题就消失了,刚以为解决了问题,移植LVGL中发现会随机进入HardFault_Handler()
,于是不得不仔细检查。
FreeRTOS只能处理抢占优先级,因此将中断组设为4以外的会使得子优先级失去意义,因此,在FreeRTOS工程中的中断只有0~15的抢占优先级。
在FreeRTOSConfig.h
文件中涉及到了中断配置,其注意问题在注释中已写出:
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __NVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS //这里要注意,需要手动包含stm32fxxx.h文件,不然configPRIO_BITS的值就会为3,导致配置错误
#else
/* 7 priority levels */
#define configPRIO_BITS 3
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 7 //这里是最最坑的地方,他把最低优先级设为了7!!!导致一旦引入优先级为15的HAL_Tick中断,就会出现不可预料的问题!应该为15!!
/* The highest interrupt priority that can be used by any interrupt service
* routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT
* CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A
* HIGHER PRIORITY THAN THIS! (higher priorities are lower numeric values). */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
* to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
* See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
任务堆栈大小
创建LVGL任务后,发现有一个任务进入一次后就再也不会进入了。
这也是一个比较有意思的地方:FreeRTOS+LVGL中某个任务运行异常可能是其他任务的堆栈不足导致的!
将其他任务的堆栈调大后问题便解决。