首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

破坏STM32中断机制引发的异常[转](3)

破坏STM32中断机制引发的异常[转](3)

所谓晚到中断是指在低优先级中断压栈的过程中又发生了高优先级的中断,那么这个压栈过程就算是这个高优先级中断的压栈,压栈之后执行高优先级中断。

    另外还有一种情况,在低优先级中断服务程序执行过程中发生了高优先级中断,高优先级中断会抢占低优先级中断,但此时低优先级中断已经执行了,已经使用寄存器了,至于使用了哪些寄存器就无法得知了,因此在这种情况下,为了使高优先级中断服务程序不破坏低优先级中断保存在这8个寄存器中的数据还需要由高优先级中断将这8个寄存器再次备份一次(其它寄存器由C编译器备份)。

XPSR寄存器最低9个bits保存的是当前的中断号,比如说tick中断的中断号是15,那么在tick中断服务程序运行时XPSR的最低9个bits的值就是15,如果程序没有进入中断那么该值为0。因此在图3、4、5所表述的中断中,在开始进入中断时XPSR寄存器最低9bits为0,中间中断运行、切换过程中XPSR寄存器最低9bits为当前中断的中断号,直到出中断时XPSR最低9bits才恢复为0。

原因分析
在前面“现象描述”中已经说过,这个小型嵌入式操作系统在ARM7内核的ADUC7024芯片上运行正常,在cortex内核的LM3S8962芯片上也运行正常,但在同为cortex内核的STM32F103VB芯片上就出问题了,程序运行一段时间就跑飞,死到异常中断服务程序HardFault_Handler里面,这说明触发了硬件异常。LM3S8962芯片和STM32F103VB芯片使用的是相同的芯片内核,最大不同之处在于芯片的外设,而这个小型嵌入式操作系统只使用了一个串口外设,这个串口的配置也看不出什么异常。另外的不同之处在于这两种芯片所采用的驱动库函数不同,由于库函数写的都比较高深莫测,还要结合硬件芯片资料对照着看,工作量比较大,所以不从库函数作为入口点定位此问题,直接从出现问题的HardFault_Handler函数出发定位此问题。
Cortex内核在进入异常服务程序HardFault_Handler之前一定是有一条指令触发了异常,硬件会将这条指令的地址存入LR寄存器中,这其中的细节请参考我写的另一篇文档“教你如何找到导致程序跑飞的指令”,这里就不详细介绍了。通过HardFault_Handler函数找到触发异常的指令在触发软中断服务程序的MDS_TaskSwiSched函数里,但在这个函数里也看不出有问题的指令,将断点打在这条“触发异常”的指令上,发现也不是每次都会引发异常,查看用到的相关寄存器也没有发现异常,这说明没有问题的指令+没有问题的数据在某些时候会概率性触发异常,这个问题就比较难解决了。找了一段时间也没找到问题原因,因为出现异常的地方几乎都是与中断相关的,后来就排查到了中断配置,一看中断配置,立刻豁然开朗,原因找到了。
原来STM32F103VB芯片的驱动库函数在设置tick中断时将tick中断的优先级配置为15,而其它中断优先级则默认为0,在cortex内核中0优先级高于15,这就说明tick中断的优先级是最低的。按照操作系统的实现方法,任务调度中断也就是tick中断必须是最低优先级的,因为操作系统在tick中断中实现任务上下文切换,如果tick中断优先级不是最低的话,那么它就可能会打断其它中断,这样tick中断的上下文切换就不是在任务与任务之间进行了,而是可能会在中断与任务之间进行了,这样中断执行到一半就切换出去了,中断就不会结束了,程序运行的结果必然会出问题。从这点来说,STM32F103VB芯片驱动库函数将tick中断优先级设置为最低并没有什么不妥。
但,cortex内核还提供了一个PendSV中断,这个中断是可以被延迟执行的软中断,将PendSV中断优先级设置为最低,操作系统就可以将定时产生的tick中断任务调度和由软件随机发起的任务调度都统一到PendSV中断服务程序里去完成。但STM32F103VB芯片驱动库中设置tick中断的函数将tick中断的优先级设置为最低,这样在tick中断触发PendSV中断时,PendSV中断就会打断tick中断的执行,发生任务调度,如果另有一个任务B也处于ready态,并且优先级比任务A还要高,那么在任务调度时就会将任务A的寄存器数值保存到任务A的栈中,又从任务B的栈中取回任务B的寄存器数值,返回到任务B去执行。问题就出现在这里,任务备份寄存器时都处于非中断状态,也就是说任务备份XPSR时XPSR最低的9bits一定是0,所以任务B栈中保存的XPSR的最低9bits一定是0,PendSV中断执行任务调度返回的XPSR是任务B保存的XPSR,最低9bits是0,而此时却是PendSV中断执行完毕需要返回到tick中断的情况,相当于图5中高优先级中断返回到低优先级中断的情况,这就要求XPSR最低9bits一定不是0,这样由于XPSR数值的冲突就出现了异常,程序进入了HardFault_Handler异常中断服务程序,导致了本文所描述的异常。
继承事业,薪火相传
返回列表