咬尾中断
Cortex-M3 内核发生中断时,硬件会自动将 XPSR、PC、LR、R12、R3、R2、R1 和 R0 这 8 个寄存器压入栈,其余的 R4~R11、LR、XPSR 寄存器的备份则需要由 C 编译器去做。
我们知道每次中断操作有三部曲:入栈 ISR 出栈。Cortex-M3 内核支持中断嵌套。所谓中断嵌套就是高优先级的中断可以打断低优先级的中断转而去执行高优先级的中断服务程序,当高优先级中断服务程序执行完毕再去接着执行低优先级的中断服务程序。若在高优先级中断服务程序执行过程中产生了低优先级中断,那么低优先级中断需要等高优先级中断服务程序执行完毕才能去执行。对于后者两个中断是串行执行的,如果按照每个中断备份、恢复寄存器的过程,那么高优先级中断先将上述 8 个寄存器压入栈中,等执行完毕再从栈中弹出这 8 个寄存器,紧接着低优先级中断再将这 8 个寄存器压入栈中,等执行完毕再从栈中弹出,这么做对这 8 个寄存器重复入栈出栈 2 次,浪费了时间,Cortex-M3 内核采用咬尾中断机制避免这种问题发生,来看下图:
Cortex-M3不会再出栈这些寄存器,而是继续使用上一个异常已经压栈好的结果,消除出栈和入栈操作的耗时。这样一来我们执行两次中断只需要:入栈 ISR1 ISR2 出栈。
咬尾中断看上去好像后一个异常把前一个的尾巴咬掉了,前前后后只执行了一次PUSH/POP操作。这两个异常之间的“时间沟”就变窄了很多,大大提高了效率!
与常规中断处理(ARM7)的比较:
晚到中断
Cortex-M3的中断处理还有另一个机制,它强调了优先级的作用,这就是“晚到的异常处理”。
这里有一种情况,低优先级中断先发生,而在低优先级中断压栈的过程中又发生了高优先级的中断,这时高优先级中断就会抢占低优先级中断,如果高优先级中断再压栈然后执行,再出栈,低优先级中断执行再出栈,这样对这 8 个寄存器又是重复入栈出栈 2 次,做了无用功,Cortex-M3 内核采用晚到中断机制避免这种问题发生,来看下图:
比如,若在响应某低优先级异常#1的早起,检测到了高优先级异常#2,则只要#2没有太晚,就能以“晚到中断”的方式处理,在入栈完毕后执行ISR#2。如图所示:
如果异常#2来得太晚,以至于已经执行了ISR#1的指令,则按普通的抢占处理,这会需要更多的处理器时间和额外32字节的堆栈空间。在ISR#2执行完毕后,则以“咬尾中断”的方式来启动ISR#1的执行。
参考摘录:
《ARM Cortex-M3权威指南.pdf》
END