RTOS开发的常见bug和调试手段

2021-08-27 00:00:00 优先级 执行 系统 抖动 调试

正文


裸机系统和RTOS系统
如今的嵌入式系统越发的复杂,不仅有一定的计算需求,还需要GUI实现人机交互,以及通过Ethernet、USB等通信接口与外部设备通信。在这样的应用场景下,使用前后台系统进行开发难度将会大大提升,而且之后每增加一个功能可能都会牵一发而动全身,系统的实时性难以保证。基于RTOS的系统开发方式可以很好地避免这些问题,确保系统实时性能的同时破解了系统的复杂度,也能更好的实现模块化,利于并行开发和项目后期的维护。
RTOS的主要工作是提供多任务处理,RTOS通过在任务之间快速切换,创造了并行执行的错觉。开发人员可以通过设置任务的优先级来确定系统的实时性。可以说,基于RTOS进行软件开发比前后台系统多了一个高层级的抽象。
对于从裸机开发到使用RTOS的嵌入式开发者来说,这有点像使用汇编语言编程转换到使用C语言编程的感觉。在更高的层次上可以使设计复杂的应用程序变得更容易,但是RTOS虽然降低了应用程序源代码的复杂性,但并没有降低应用程序本身固有的复杂性,RTOS的并发特性也使得应用程序难以验证和调试。例如,程序流在源代码中已经不明显,RTOS决定着在任何给定时刻执行哪个任务。

与前后台系统相比,基于RTOS系统开发更加困难的是RTOS的任务不是孤立存在的个体,任务之间的相互依赖会导致任务延迟运行的差异,细微的编码差别都可能会让产品出现难以捉摸或者性能上的问题。当作为一个系统一起执行时,一组看似简单的任务可能会产生复杂的运行时行为。

RTOS系统常见的bug
1、线程饥饿
在嵌入式多任务系统中,一些任务可能会执行缓慢,或者甚至得不到执行,常见的原因是由于优先级顺序设置不正确导致。高优先级的任务使用了太多的CPU时间,低优先级的任务可能就没有足够的时间执行,这就是所谓的线程饥饿。将受影响的任务的优先级提高,确实可以改善问题,但违背了使用优先级的意义。相反,高优先级应该保留给可预测、循环执行、且循环周期较短的任务。对于高优先级、CPU占用时间长的任务应该拆分为多个任务,缩小时间关键代码,通过任务同步机制,将占用CPU时间多的工作交给中或低优先级任务处理。
2、抖动
周期性执行的任务,随机发生的延迟时间叫做抖动。虽然轻微的抖动很难避免,但是抖动太严重就会导致性能变差,间歇性的数据丢失。例如,每隔5ms调整电机的控制参数,如果控制任务的抖动过大就会使得控制性能就变差。除了线程饥饿会导致抖动之外,RTOS系统配置也会有影响,例如系统节拍定时器节拍频率。理想情况下,两个节拍之间的时间应该比系统中频繁任务的周期时间短得多。
3、优先级反转
具有固定优先级调度程序的 RTOS 的核心思想是,应该在具有较低优先级的任务之前安排高优先级任务执行。但是当两个或多个任务需要协调使用全局数据区等共享资源或外围设备时,可能会导致低优先级的任务先执行,优先级反转的问题就发生了。出现优先级反转的现象是系统可能暂时失去响应,导致随机崩溃。使用RTOS优先级继承机制,如互斥信号量,可以降低优先级反转带来的影响,但要完全消除需要在设计时避免。
4、死锁
任务突然停止执行,但当前并没有更高优先级任务在执行,这时可能就发生了死锁。当两个或多个应用程序任务阻塞在一起等待对方时,导致任务都无法继续进行,就会发生死锁。只能在设计时避免死锁的发生,例如所有的任务都按照固定的顺序使用共享资源,或者同一时间任务不持有多个共享资源,使用超时机制,以及服务器任务专门用于共享资源的访问等。
5、内存泄漏
通常不建议在嵌入式软件中进行动态内存分配,但有时会出于各种原因需要进行动态内存分配。问题在于,如果使用它,则必须确保一旦内存块不再使用时,释放每个已分配的内存块。如果在某些情况下遗漏了释放操作就会出现内存泄漏,并终耗尽内存导致严重错误。
RTOS调试手段
上面列举了多任务系统设计开发时比较典型的几种bug,它们都有一个特点,就是通过阅读源代码或者传统的调试手段很难发现这一类的问题。通常对RTOS系统设计有着丰富经验的开发者,通过测试和基础的调试获得的信息也能够定位到问题所在,即便如此,分析问题的效率也十分低下。
1、IDE的RTOS调试插件和RTOS自身调试特性
RTOS可能会自带一些调试功能,用于观察系统任务的情况,比如任务优先级,当前的任务状态和堆栈使用情况等。下图是FreeRTOS通过开启调试功能后调用vTaskList() API函数获取的任务状态信息。使用一个精度比系统节拍高得多的定时器,FreeRTOS还可以分析任务的执行时间信息。
一些IDE中支持RTOS内核识别调试插件,例如IAR EWARM支持μC/OS、FreeRTOS、embOS、ThreadX等在内的众多RTOS。Eclipse中的Code Confidence Tools for FreeRTOS。下图是IAR EWARM的μC/OS-III调试插件显示的内核和任务的各项信息,例如堆栈使用,CPU使用率等。
2、RTOS跟踪和可视化分析工具
可以发现不论是RTOS自带的一些调试功能,还是IDE提供的调试插件,虽然能显示系统中任务的一些信息,但如果要作为一个bug分析工具,其功能还是非常有限。我们只能知道暂停运行的这一刻任务的信息,并不清楚任务的状态是何时及何原因而改变,更不清楚各个任务之间的交互关系。
更进一步,虽然设计的系统没有明显的问题,但是出于低功耗和性能调优的原因需要优化系统的设计,减少不必要的任务切换,降低消息或者信息的阻塞时间等,现有的这些工具和方法已经显得力不从心。这说明之前的开发工具已经跟不上现在的需求了,这需要从更高层级的系统视图,观测和跟踪系统的运行。
现在很多的RTOS都自带跟踪接口,例如FreeRTOS、μC/OS-III都提供了跟踪接口,可以支持Tracealyzer和SystemView等RTOS可视化分析工具。Linux系统可用LTTng内核事件跟踪组件。借助这些可视化的OS事件记录和分析工具,可以极大提升bug的查找效率,还能快速验证系统设计是否如期,性能是否达标。
以Tracealyzer为例,它可以实时记录RTOS运行时的各种系统事件,例如任务的调度,任务与任务之间、任务与中断之间的通信等,以此分析出系统在运行期间的行为,并通过图形或文件可视化提供给开发人员直观的查看,可以很快的发现传统调试中难以捕捉的系统层级的行为。以前面提到的RTOS系统常见的bug之一的优先级反转为例,使用Tracealyzer的执行实例视图,开发者立刻就能发现问题。
再比如抖动的问题,Tracealyzer通过记录任务执行的时间,在以时间为坐标的图上很快可以发现抖动很大的执行实例,假如这是对抖动敏感的任务,这可能就是导致系统问题的原因了。
对于任务与任务、任务与及中断之间的通信,Tracealyzer能够绘制完整的通信流图,如果系统中数据流出现问题,在此图中一眼就能识别。
事件记录以时间戳排序,文本方式记录了运行期间系统产生的各系统事件(如任务调度、通信、动态内存分配)和用户自定义事件(类似于printf功能,可以被记录并显示在各对应的视图中)。
除了Tracealyzer以外,RTOS跟踪和分析工具还有SEGGER公司推出的SystemView。该工具也提供了多个视图,包括时间轴,显示任务和中断的执行记录,事件记录和CPU负载等。
它们的工作方式也都相似,有一个用于事件跟踪的库,需要与项目一起构建,在目标系统中运行。在运行期间记录RTOS的各个事件并存储到位于RAM的事件缓存中,待系统停止运行后读取出来加载到位于PC端的分析软件中,通过各种视图窗口显示出来。这种工作方式一般称为快照模式。
快照模式受限于芯片可用的RAM空间,一般记录的时间比较短。需要长时间记录,则可以使用数据流模式,通过调试接口和调试器(J-Link)或者串口等通信接口,实时的将数据传输到PC端的分析软件,实现长时间的实时跟踪和分析,只有电脑的硬盘空间足够,记录就可以一直持续。
以上只是简单展示了RTOS分析工具的用途,它可以弥补现有的开发工具不足以满足基于RTOS的嵌入式软件的开发,对于bug的查找很有帮助。对于想要深入学习RTOS的工作机制的开发者,这也是一个很好的辅助工具。不过Tracealyzer和SystemView是商用软件,商用时需要付费,但SystemView用于教育和评估是完全免费的。另外之前Micrium公司开发的μC/Probe,现在已经可以免费使用,能用于μC/OS-III和FreeRTOS的系统信息观察,虽然没有记录和跟踪的功能,但是它提供了类似工业组态软件的图形控制,功能也很强。

素材源于:麦克泰技术

版权归原作者所有。仅供技术的传播和学习讨论,如涉及作品版权问题,请联系我进行删除。

相关文章