本文原名为 uC-OS III任务优先级不当引发的困扰
前言
为了使STM32的生态系统里OS多元化,stm32系列不仅支持FreeRTOS,也支持uc-OSIII,提供给客户更多选择,满足客户日益增长的需求。
这里使用stm32f429-eval平台,基于stm32cubef4中的Demostration例程,替换其中的FreeRTOS。例程中uc-OSIII系统里涉及的任务及其优先级配置如下表:
Demostration 是一个综合示例,包含了尽可能多的中间件,譬如GUI framework, STemwin,USB stack, FatFS, OS(FreeRTOS)等等。鉴于芯片内存大小限制,在stm32f429-eval 平台上,tcp/ipstack lwIP 并未集成进去。
Case 1 优先级设置不当引发ANR(application not response)
1.1 问题描述
在应用中,有一个videoplayer 和audioplayer 模块,其中有一个功能,从文件系统中向播放器添加文件、文件夹,这在emWinframework 中,通过控件CHOOSEFILE_Create实现,它是一个基于窗口的模式对话框。
然而,只要点击“+”按钮或者文件夹按钮后,弹出一个选择文件的对话框,再点击屏幕任何地方,系统都没有任何反应,界面也一直停留在这个对话框。
1.2 问题分析与定位
在uc-OSIII 中,触摸屏事件是通过软定时器实现的,软件定时器是通过一个任务实现的,而当定时器任务的优先级比GUI任务低时,当GUI任务处于就绪状态时,定时器任务得不到任何调度,那么任何触摸事件的更新消息无法产生,也无法发送给GUI任务,而GUI任务在等待触摸事件(GUI任务与触摸模块是通过信号量来同步的)。这样就出现了deadlock,一方(消费者)死等某个事件的产生,而另外一方(生产者)无法产生这个事件,系统就出现了无响应的现象。
1.3 问题解决方案
既然uc-OSIII 是抢占式调度模式(也支持round-robbin调度),那么将定时器任务优先级调整比GUI任务优先级高一级即可,问题予以解决。
Case 2 优先级设置不当引发调试模式下,程序崩溃
2.1 问题描述:
使用Keil5.20 版本编译、调试、下载程序时,如果程序处于运行模式,一切正常;然而如果置于调试模式,则程序100%crash。这种情形十分罕见,一般情况下是,运行模式往往程序会crash,调试模式下,程序可以正常运行。使用调试模式来troubleshootbug 的。
2.2 问题分析&解决
幸运的是,该问题100%复现。于是竭尽全力去找寻上一次对程序的修改导致了此问题,一步一步撤销修改,恢复成代码的初始状态。经过几番努力,力争追根溯源,想查明是哪一次的修改导致了问题。结果,依然一无所获。
于是,开始考虑从异常处理程序中着手,找到触发异常的那条指令,那个函数,那个任务。这里主要参考了ARM提供的应用笔记《apnt209.pdf》。调试时,通过FaultReport 知悉,此异常为busfault,而且BFARVALID和PRECISERR都置位了。按照ARM的指南,BFARVALID 对应的地址寄存器存储的是触发busfault 的指令地址,不过这次失效了,里面的地址不在ROM地址范围内。
本想咨询一下ARM的技术支持,如何解决这一问题。因为个人觉得,这个问题跟调试器有关,怀疑是自己对于IDE的某些参数配置不当才引起的。苦于没有任何间接的、直接的来自ARM官方的关于KeilMDK 技术支持。未遂。
心痛还得心药治,解铃还须系铃人。考虑系统存在诸多任务,于是考虑通过WBS方式,一一注释掉这些任务,看看究竟是哪个任务引起的。这样做的话,工作量比较大。退而求其次,既然调试时程序每次都crash,而且每次crash时,内核的寄存器参数的值都是一样的(幸运的是,该异常不是随机产生的),联想到Linux内核里有一个当前任务指针currenttask pointer,而uc-OSIII 中也有类似的数据结构(其他OS如FreeRTOS也有类似数据结构),即OSTCBCurPtr,将其置于watch窗口,发现其指向OSStatTaskTCB,于是在stat 任务相应
的任务处理函数设置断点,单步执行,这样居然程序可以正常运行!
进一步发现,在系统启动过程中,stat任务会统计每个任务占用CPU时间,比较耗费CPU,导致GUI 任务不能及时执行,从而诱发总线异常(busfault)。于是尝试将stat任务优先级调低,重新编译、下载、调试,一切OK!运行模式也OK.
OMG,原来是stat 任务优先级设置过高导致了bus fault !还是任务优先级安排不当导致的问题。