十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FreeRTOS学习(三十一)——调试与追踪

FreeRTOS学习(三十一)——调试与追踪 上一节学习了FreeRTOSConfig配置知道了很多FreeRTOS功能都需要先在FreeRTOSConfig.h中开启。程序真正运行以后我们经常会遇到一些比较头疼的问题任务为什么没有运行 程序为什么突然卡死 某个任务是不是一直占着CPU 任务栈到底够不够裸机程序中我们可能通过LED或者printf()判断程序运行到了哪里。但是FreeRTOS存在多个任务仅靠这种方式有时候很难定位问题。因此本节学习几个比较实用的FreeRTOS调试方法。本节学习目标能够查看任务当前状态、剩余栈空间和Heap空间并建立一个基本的FreeRTOS问题排查思路。一、先从任务状态开始排查假设创建了三个任务LEDTask SensorTask UartTask程序运行以后发现SensorTask好像不工作了。这时首先需要知道SensorTask现在到底是什么状态FreeRTOS中的任务可能处于Running Ready Blocked Suspended例如SensorTask正在vTaskDelay( pdMS_TO_TICKS(1000) );那么它暂时不运行其实很正常因为它现在处于Blocked所以任务没有运行不一定代表程序出错。二、使用vTaskList查看任务FreeRTOS提供vTaskList();可以把当前任务的信息输出到字符串中。首先在FreeRTOSConfig.h中根据所用版本配置相关功能例如#define configUSE_TRACE_FACILITY 1以及#define configUSE_STATS_FORMATTING_FUNCTIONS 1然后定义数组char TaskInfo[512];使用vTaskList(TaskInfo); printf(%s\r\n, TaskInfo);可能得到类似结果TaskName State Priority Stack Num LEDTask B 2 100 2 SensorTask R 3 80 3 IDLE R 0 110 1这样就可以直接看到每个任务的大致运行情况。三、任务状态字母是什么意思vTaskList()输出中常见X R B S其中X ↓ Running 正在运行R ↓ Ready 就绪B ↓ Blocked 阻塞S ↓ Suspended 挂起例如LEDTask B不一定有问题。它可能正在vTaskDelay();因此正常进入了阻塞态。但如果你原本认为LEDTask应该一直运行结果发现LEDTask S那就需要检查程序中是不是执行过vTaskSuspend();四、检查任务栈FreeRTOS程序出现莫名其妙HardFault 运行一段时间死机 局部变量异常一个非常重要的检查对象就是任务栈。前面学习过uxTaskGetStackHighWaterMark();例如UBaseType_t StackRemain; StackRemain uxTaskGetStackHighWaterMark( SensorTaskHandle );然后printf( Sensor Stack %lu\r\n, (unsigned long)StackRemain );这个值表示任务运行以来栈最紧张的时候 至少还剩多少栈空间。如果这个值已经非常小2 3 4就说明任务栈已经比较危险。五、检查Heap空间如果程序在xTaskCreate();或者xQueueCreate();时创建失败就应该检查Heap是不是不够了。可以使用xPortGetFreeHeapSize();例如printf( Free Heap %lu\r\n, (unsigned long)xPortGetFreeHeapSize() );还可以查看系统运行以来最紧张时剩余的HeapxPortGetMinimumEverFreeHeapSize();例如printf( Min Heap %lu\r\n, (unsigned long) xPortGetMinimumEverFreeHeapSize() );如果Free Heap非常小就要检查任务是不是创建太多 任务栈是不是设置太大 队列是不是设置太长 configTOTAL_HEAP_SIZE是不是太小六、不要忘记检查函数返回值这是初学FreeRTOS时非常容易忽略的问题。例如xTaskCreate( LEDTask, LED, 128, NULL, 2, NULL );很多人写完以后直接不管返回值。但是xTaskCreate();本身有返回值。可以这样写BaseType_t Result; Result xTaskCreate( LEDTask, LED, 128, NULL, 2, NULL ); if(Result ! pdPASS) { printf(LED Task Create Failed\r\n); }如果Heap不足导致任务创建失败就可以马上发现。同样xQueueCreate();创建以后也应该判断if(QueueHandle NULL) { printf(Queue Create Failed\r\n); }很多所谓的任务为什么不运行实际上任务从一开始就没有创建成功。七、检查任务是不是一直占用CPU假设写了void SensorTask(void *pvParameters) { while(1) { ReadSensor(); } }这里没有vTaskDelay();也没有等待队列 等待信号量 等待任务通知那么只要它处于最高可运行优先级就可能长时间占用CPU。如果另一个低优先级任务一直得不到运行机会就要检查高优先级任务是不是缺少阻塞操作。上一节学习的运行时间统计vTaskGetRunTimeStats();也可以帮助判断到底哪个任务占用了大量CPU。八、使用断点调试除了FreeRTOS自己的调试APISTM32开发中最直接的方法仍然是ST-Link Keil / STM32CubeIDE进行断点调试。例如怀疑任务没有进入void LEDTask(void *pvParameters) { while(1) { GPIO_ToggleBits( GPIOE, GPIO_Pin_3 ); vTaskDelay( pdMS_TO_TICKS(500) ); } }可以在GPIO_ToggleBits();位置设置断点。如果程序能够进入断点任务确实运行了。如果完全进不来↓ 检查任务是否创建成功 ↓ 检查任务是否被挂起 ↓ 检查更高优先级任务是否长期占用CPU这样比盲目修改代码有效得多。九、建立固定的排查顺序以后遇到某个任务不运行可以按照下面顺序检查任务创建成功了吗 ↓ 任务现在是什么状态 ↓ 是不是被挂起了 ↓ 是不是正在正常阻塞 ↓ 高优先级任务是否一直占CPU ↓ 任务栈是否不足 ↓ Heap是否不足 ↓ 是否出现HardFault等异常不要一看到LED不亮就直接怀疑FreeRTOS调度器出问题了。很多时候只是任务没创建成功 GPIO配置错误 任务处于阻塞状态 优先级设置不合理这些普通问题。十、总结这一节学习了FreeRTOS中几个非常实用的调试方法。查看任务信息可以使用vTaskList();检查任务剩余栈uxTaskGetStackHighWaterMark();检查当前剩余HeapxPortGetFreeHeapSize();检查历史最小剩余HeapxPortGetMinimumEverFreeHeapSize();同时创建任务时不要忽略xTaskCreate()的返回值。因此以后FreeRTOS程序出现问题不要只依赖LED printf去猜。更合理的思路是先看任务状态 ↓ 再看优先级和阻塞关系 ↓ 再检查Stack和Heap ↓ 最后结合断点定位具体代码掌握这些方法以后FreeRTOS出现的很多“莫名其妙的问题”实际上都可以一步一步定位出来。
返回列表