一个代码BUG引发的ARM中断抢占与响应优先级的思考

        近日调试一段代码,代码功能就是在外部中断服务函数里面清零一个计时器变量count,该变量在一个10us的定时器中断中累加,累加到一个阈值V1,设置一个GPIO输出高电平,变量继续累加到阈值V2,设置之前的GPIO输出低电平。外部中断输入信号是一个10ms的周期脉冲。外部中断优先级设置为0,定时器中断优先级设置为1(M0内核,总共4个优先级,数值越低,优先级越高)。整个实验现象,用示波器观察,理论上应该是一个周期为10ms的方波。关键代码如下:    

在实际测试中发现,理应完整的方波信号中,偶尔会丢失一个脉冲,实际测试波形如下: 

为了定位问题,做了以下实验:

1、在定时器中断服务函数里面添加临界保护。---------------------输出结果正常

2、定时器中断优先级设置为0,与外部中断优先级保持一致-----------------输出结果正常

3、定时器中断优先级设置为0,外部中断优先级设置为1------------------输出结果正常

所以,现在基本可以确定是由于中断优先级设置不当造成的。现在来看看,之前的设置到底有什么问题。

        我们一开始的优先级是外部中断优先级>定时器中断优先级,因为我想的是,我为了保证我的外部中断信号不会被漏掉,我要保持外部中断优先级最高。现在我们来考虑特殊情况:当程序正在运行定时器中断服务函数的时候,触发了外部中断。

(以下分析需要部分内核知识)这个时候,由于外部中断优先级高于定时器中断,所以定时器中断被打断,程序将跳转到外部中断服务函数。这里就会产生一个现场保护,即将当前进程的各个变量和状态入栈(刚好前几天看了操作系统的任务切换,帮我理解了这一段操作。),当然就包括这里的全局变量count的值入栈保护(外部中断信号周期为10ms,定时器周期为10us,所以在外部中断触发的时候,count的值大概在1000左右,所以这里会把count = 1000的值保存的起来)。然后程序转到外部中断里面,(从上面代码知道,外部中断里面核心代码就是给count清零)当执行完外部中断以后,全局变量count的值变成0,嗯,这正是我们想要的结果,但是!但是!此时我们还在定时器中断里面,即运行完外部中断以后,我们会回到定时器中断继续执行,所以这里会产生一个现场恢复,即将之前入栈的各个变量从栈中取出来(出栈),而我们的count之前保存的值是1000,所以这里出栈后,我们的count又变成1000了,而不是0(这里就是最关键的地方,程序就是在这里产生了异常)。所以这里外部中断的清零操作就无效了,最终就导致了我们的输出波形丢失了一个脉冲。

然后我们再来分析上面3个实验现象:

1、在定时器中断服务函数里面添加临界保护。

        添加临界保护,即我在运行定时器中断服务函数的时候,不允许产生任何中断,即保证了我的定时器中断服务函数不被打断。既然中断没被打断,那么就不会发生上面的情况了。

        这里有另外一个问题,如果我的全局中断被关闭了,我的外部中断不是没法响应了嘛,那这个时候如果来一个外部中断,外部中断函数无法响应,我的count还是没法清零,那也就会导致我丢一个脉冲啊。

       这里就需要了解一下从中断产生到执行中断函数这个过程(具体的过程可以自己去百度,这里只简单分析下)。

      那么在我们全局中断关闭的时候,代码是什么逻辑呢?

      实际上,  __disable_irq();//关全局中断   是屏蔽了所有的中断响应。这个时候当我们的外部中断引脚检测到一个外部中断时,那么外部中断挂起寄存器EXTI->PR还是会被置1的。

但是因为中断响应被屏蔽了,所以程序不会去执行中断服务函数。如下图

而当我们再次打开全局中断的时候,即取消中断屏蔽,这个时候因为我们的挂起寄存器并没有被清零,所以程序又会继续去响应之前产生的这个外部中断。也就是说,假设在上述代码执行过程中产生了一次外部中断,这个外部中断并不会被屏蔽掉,它会在定时器中断执行完毕后去响应(但是如果在中断屏蔽期间产生了多次外部中断,系统是没法识别的,我的分析只限于我当前的应用)。到此,我们第一个实验的现象应该理解清楚了。下面分析第二实验。

2、定时器中断优先级设置为0,与外部中断优先级保持一致

       由于我使用的是M0内核,M0内核中,同一优先级中断,中断按照中断号的大小响应,中断号排在前面的中断具有优先响应权,但是,同一优先级别的中断不具有抢占能力。即中断号排在前面的中断没法打断中断号排在后面的中断。所以当我的定时器中断优先级和外部中断保持一致的时候,也就不会发生中断抢占了,那么我的定时器中断是不会被打断的。那么也就没什么问题了。理解了这个,第三个实验就好理解了,因为外部中断优先级低于定时中断优先级,所以外部中断无法打算定时器中断。

      以上都是自己拍脑袋想出来的,如有错误,欢迎指正。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值