什么?中断禁用失效了?
1. 前言
道友们,在嵌入式的开发中我们不管是RTOS或NO-RTOS的开发,都无法避免“多线程”的应用场景,高优先级的任务或中断打断低优先级的任务或中断,此时为了要保证共享数据的安全性,往往我们都会采用临界区保护的措施来保护我们的共享数据。临界区保护的实现可以是互斥锁、开关中断等。对于开关中断的方式包括开关全局中断、控制中断优先级两种方式。OK,这不是之前在项目中因为使用控制中断优先级做临界区保护的方式导致代码出现了问题,因此写这篇文章记录一下。
2. 问题现象
该项目中使用的是TI的AM2634芯片。下面我逐步来介绍该问题是怎么发生的。
① 首先如下图所示,我们代码中在操作共享数据的前后增加了临界区保护的操作,该操作里的内容是通过修改中断优先级寄存器来达到禁用制定的中断目的。
如下图所示,临界区保护操作的就是这个寄存器,将需要禁用的中断对应的bit写0。我们这里禁用的是二类中断(受OS管控)。
执行完这个临界区保护(开始)的操作后,操作系统会在它的上下文中记录我们此时已经执行了禁用二类中断的操作,然后我们再看下面这个流程图。当我们的二类中断触发的时候,会先执行Os_Isr_Entry这个函数,在这个函数中OS会进行一系列的检查以及其它的操作,然后再去执行我们注册的中断服务函数。那么这个检查里面就涉及到中断禁用的检查,再OS的设定中,我们既然已经禁用了二类中断后,就不该再触发新的二类中断了,因此它会进入ErrorHook(故障回调函数)。
好了,说到这里问题的根本原因就是我们既然禁用了中断后,为什么中断还是触发了?
3. 问题原因
当问题复现的时候,我查看了这个寄存器,可看到我们其实已经写成功了,写之前的值是0xFF,我们禁用了优先级8以上的中断,因此写入0x7F,所以代码中的操作其实没有问题。
既然不是我们代码的问题,那么这个问题是什么呢?OK,直接来说最后的问题结论,这个寄存器再操作之后其实不是马上生效的,我们将值写入这个寄存器到中断被禁用这之间还有一个"生效时间",这就导致了为什么我们在操作完这个寄存器后中断依旧触发的原因了。
上面就是TI的回复了,针对这个寄存器,我们必须要按照下面的时序来操作以确保它生效。
4. 结尾
在我们开发中,有时候出现问题可能并不是由于我们代码的问题,也有可能跟芯片的设定有关。就拿这个VIM_IRQPRIMASK寄存器来说,我们的代码就是按照寄存器手册去写的,那为什么实际没有达到期望的功能效果,也许这中间就暗藏了一些芯片层面的“规则”。所以我们排查问题的时候思维要打开,进行一些头脑风暴后也许就会找到答案。