中断的嵌套

读研期间,有幸接触了Stellaris系列的基于ARM Cortex-M3内核的LM3S9B9x微控制器,该微控制器支持中断的嵌套。

中断嵌套是指高优先级的中断能够打断低优先级的中断(反过来不可以),处理完高优先级的中断后,还得回来继续处理低优先级的中断。

中断发生时,下列动作会发生:

  • 入栈(Stacking),即把八个寄存器的值压入堆栈;
  • 取向量(Vector fetch),即从向量表中读取中断服务函数的入口地址;
  • 更新堆栈指针(stack pointer,SP)、链接寄存器(link register)和程序计数器(Program counter,PC)。

响应中断的第一个动作就是自动保存现场的必要部分,即把八个寄存器的值压入堆栈。如果响应中断时,当前的代码正在使用PSP,则压入PSP,也就是进程堆栈;否则就压入MSP,使用主堆栈。一旦进入中断服务函数,就将一直使用主堆栈,因而所有的嵌套中断也将使用主堆栈。

嵌套中断支持已经内置于Cortex-M3内核以及嵌套向量中断控制器(Nested Vectored Interrupt Controller,NVIC),因而无需使用汇编去写贴皮代码(Wrapper Code),我们所要做的就是为每个中断设置优先级。

NVIC和Cortex-M3微控制器会根据优先级来控制抢占和嵌套行为,因此,在某个中断正在响应时,所有优先级不高于它的中断都不能抢占它,包括自己也不能抢占自己(相同的中断是不允许重入的)。

有了自动入栈和出栈(Unstacking),中断嵌套时,就没有了寄存器数据丢失的风险。然而,必须注意的是,由于所有的中断服务函数都使用主堆栈,当中断嵌套很深时,主堆栈的压力会增大,每嵌套一级,都需要额外的堆栈空间,因而要防止主堆栈被用穿的风险。《ARM Cortex-M3 权威指南》一书指出:堆栈用穿(溢出)是致命的,它会使入栈数据和主堆栈前面的数据区发生混迭,使这些数据被破坏;若在中断服务函数返回前混迭区的数据又被更改了,则堆栈内容被破坏,这样一来,在中断服务函数返回后,系统极可能功能紊乱,甚至造成程序跑飞。

(一) 咬尾中断(Tail-chaining)
当响应某个中断时,又有新的中断发生,但是新发生中断的优先级不够高,那么新的中断就会被挂起(Pending)。那么当中断返回后,系统处理挂起的中断时,如果还是先POP(出栈指令),然后把POP的内容再PUSH(入栈指令)回去,这就成了“砸锅炼铁再铸锅”,白白浪费了CPU时间。Cortex-M3不会傻乎乎地POP这些寄存器,而是继续使用上一个中断已经PUSH好的成果,从而避免了资源浪费。这就好像是一个中断把前一个中断的尾巴咬断了,前前后后只执行了一次入栈/出栈操作。
这里写图片描述

(二) 晚到的中断(Late Arrivals)
另外一种提高中断性能的机制就是“晚到的中断处理”。当处理器对某一中断的响应还在早期,即入栈阶段,如果此时收到了高优先级中断的请求,则后到的中断会被优先处理,也就是说前面的入栈操作就成了为高优先级中断所做的了,尽管它来的晚,但是由于优先级高而受到偏袒。比如,在响应低优先级的中断#1的早期时,检测到高优先级的中断#2,则只要中断#2没有太晚,就能以“晚到的中断”机制来处理,如下图所示。
这里写图片描述

当然了,如果中断#2来的太晚,以至于已经执行了中断#1的指令,则按普通的抢占处理,这会需要更多的处理器时间和额外的堆栈空间。在中断#2执行完毕后,再按照前面所述的“咬尾中断”机制来启动中断#1的执行。

参考文献:
1. 《ARM Cortex-M3权威指南》,北京:北京航空航天大学出版社,2009.7
2. 《The Definitive Guide to the ARM Cortex-M3》,Joseph Yiu

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在STM32中,中断嵌套是指在处理一个中断时,能够中断当前中断处理程序处理更高优先级的中断。这是通过NVIC(Nested Vectored Interrupt Controller)来实现的。 要实现中断嵌套,首先需要配置每个中断的优先级。优先级较高的中断会在优先级较低的中断之前被处理。可以使用NVIC的相关函数来设置中断的优先级,例如`NVIC_SetPriority()`函数。 当一个中断请求发生时,中断控制器会根据中断的优先级来决定是否中断当前正在执行的中断处理程序。如果新中断的优先级高于当前中断的优先级,那么当前中断会被挂起,处理新中断,然后再返回到原来的中断处理程序。 在处理完高优先级中断后,中断控制器会自动恢复之前被挂起的低优先级中断,并继续执行原来的中断处理程序。 下面是一个示例代码,演示了如何在STM32中实现中断嵌套: ```c // 配置中断优先级 NVIC_SetPriority(USART1_IRQn, 1); // 设置USART1中断的优先级为1 NVIC_SetPriority(USART2_IRQn, 2); // 设置USART2中断的优先级为2 // 中断处理函数 void USART1_IRQHandler(void) { // 处理USART1中断 // 检查是否有更高优先级的中断发生 if (NVIC_GetPendingIRQ(USART2_IRQn)) { // 挂起当前中断,处理USART2中断 NVIC_SetPendingIRQ(USART2_IRQn); } // 继续执行原来的中断处理程序 } void USART2_IRQHandler(void) { // 处理USART2中断 // 继续执行原来的中断处理程序 } ``` 在上面的示例中,当USART1中断发生时,首先会处理USART1中断,然后检查是否有更高优先级的中断USART2发生。如果有,就挂起当前的USART1中断,处理USART2中断,然后再返回到原来的USART1中断处理程序。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值