FreeRTOS常见错误排查
1,栈溢出问题
每个TASK(任务)都有着自己独立维护的栈空间,而栈空间在任务被创建时就已经设定,任务当前使用栈空间大小对于开发者来说至关重要。在RTOS中提供了多种跟踪辅助调试栈相关问题的工具。
1,栈空间高水线函数
高水线通常被用在检测河流水位高度场景,高水线具有预警指示旱涝自然灾害发生可能性。同理,本节介绍的高水位函数同样能提供开发者参考的栈使用“水位”预警信息。
unsigned portBASE_TYPE uxTaskGetStackHighWaterMark( xTaskHandle xTask );
**传入参数xTask:**被查询任务的句柄----API 函数xTaskCreate()的参数pxCreatedTask
**函数返回值:**xTask从执行开始的运行历史中,栈空间最小余量,也就是该任务能使用栈空间的最长深度,这个值接近0时候,表明改任务离溢出不远了。
2,栈溢出检测参数调用钩子函数
HOOK(钩子)函数可以说是操作系统必有的一类函数,像Windows、Linux以及我前面讲述过的UCOS嵌入式实时操作系统都有这类钩子函数。是操作系统消息处理机制的程序段,通过系统调用,把它挂入系统。本节关注的是栈溢出钩子函数,具体介绍参考以下内容。
https://www.jianshu.com/p/6c5cfc0a3e9a
configCHECK_FOR_STACK_OVERFLOW
赋值1情况下:内核会在任务交换的时刻,任务的上下文在栈内全部保存完成后,检测栈指针指向是否超出了任务栈有效范围,溢出则钩子函数会被调用;
赋值2情况下:此方法在1上进行些许改进。当任务被创建后,任务栈空间被预置一个标记,通过这个标记是否被覆盖掉来判断是否发生了数据溢出事件。通常是使用栈内最后20字节来储存标记数据,不断检测这20字节内容来判断栈空间使用是否超出预期。
##2,其他常见错误##
###1,在TaskA中创建一个TaskB
任务在创建的时候就需要在内存堆中分配空间,许多Task在定义堆空间的时候可能就只够当前任务所有信息保存。
若开发者在不明白当前任务堆空间使用状态下,强行创建新任务,或者一些队列和信号量,这样无疑会导致溢出或者TaskA任务无法被创建。
此外,vTaskStartScheduler()被调用是他还会自动生成一个空闲任务,这个任务具有最小优先级。如在调用调度器时发生上述堆内存分配过小,此时空闲任务无法被创建,TaskA任务创建失败。所以,在调用vTaskStartScheduler()后加上一条空循环[for(;?]可以使这种错误更加容易调试。
###2,在中断中调用OS的危险API函数###
除了具有后缀为“FromISR”函数名的API函数,千万不要在中断服务程序中调用其他API。
###3,中断函数出现崩溃###
① 检查中断程序是否发生溢出。
② 中断服务程序语法书写是否正确,具体可能由宏使用,接口传值。
③ 中断若存在优先级,最好从最高优先级中断开始盘查。
###4,启动第一个任务后,调度器就崩溃了###
在第一个任务就崩溃,可能与两个地方有关:1 第一个任务内存分配过小,解决方案见上。2 调度器自身设置存在问题,如在ARM7使用调度器前,需要将调度器设定为管理模式(Supervisor mode),排查某些不能启动调度器的设置参数。
###5,调度器在挂载下调用OS的API###
RTOS分别提供了vTaskSuspendAll()和xTaskResumeAll()两个接口来使得调度器挂起和唤醒。所以在Pend期间千万不用尝试调用其他API。
###6,在调度器启动前程序就崩溃了###
同调度器挂起一样,在调度器未调用启动前就调用其他API,这样可能对导致程序崩溃。同时如果在中断中需要上下文切换操作的(读写队列或者信号量),那么这个中断在调度器启动前不能使能!
调度器在启动前依然可以使用创建任务,队列和信号量的API。