0 参考资料
ARM Cortex-A(armV7)编程手册V4.0.pdf
ARM体系结构与编程第2版
1 前言
Cortex-M系列内核MCU中断硬件原生支持嵌套中断,开发者不需要为了实现嵌套中断而进行额外的工作。但在Cortex-A7中,硬件原生是不支持嵌套中断的,这从Cortex-A7中断向量表中仅为外部中断设置了一个中断向量可以看出。本文介绍Cortex-A7的简单的中断处理机制,即不可嵌套中断的处理机制。
2 Cortex-A7:简单中断处理(不可嵌套中断)机制
2.1 概述
简单的中断处理机制意味着在中断发生之后,将会屏蔽掉同类中断,如果在响应中断期间有多个中断请求需要处理,则会按照优先级顺序(取决于中断服务函数写法)依次处理。这样的设计下无法使高抢占优先级的中断抢占低抢占优先级中断执行,也就无法实现中断嵌套。
2.2 中断处理步骤
简单中断处理步骤可以概括为以下5步。
2.2.1 硬件保存上下文
当发生外部中断,硬件将会自动执行以下几个操作:
(1)将当前模式下(中断发生前)的PC(程序计数器)后面第2条指令地址保存到IRQ模式下的LR(链接寄存器)
(2)将当前模式下CPSR(当前程序状态寄存器)保存到到IRQ模式的SPSR(程序状态保存寄存器)
(3)修改CPSR(当前程序状态寄存器),将I位设置为1屏蔽IRQ,同时将模式设置为IRQ模式切换到IRQ模式
(4)将PC(程序计数器)设置为IRQ的中断向量
以上步骤可以用如下示意图描述:
2.2.2 跳转到中断服务函数
(1)中已经将IRQ中断向量传入PC(程序计数器),下一条指令则开始执行中断服务函数
2.2.3 中断服务函数保存上下文
中断服务函数应当将会被修改的寄存器入栈,在中断服务函数完成后将保存的寄存器出栈,恢复原来的值。这里需要注意,如果是使用汇编语言编写中断服务函数,开发者应该自行编写出入栈操作语句。如果是使用C语言编写中断服务函数,则编译器会完成寄存器的出入栈操作。
以上步骤可以用如下示意图描述:
2.2.4 根据中断源执行相应的中断服务函数
不同于Cortex-M的所有外部中断都有独立的中断向量,Cortex-A7的中断处理程序需要自行判断中断源,并调用相应的中断服务函数。
2.2.5 从中断处理程序中返回
(1)将SPSR_IRQ(IRQ模式下的SPSR寄存器)复制到CPSR(当前程序状态寄存器),将系统状态恢复到中断发生前的状态
(2)将IRQ模式下的LR(链接寄存器)内容复制到PC(程序计数器)。下一条指令便会执行中断打断点的下一条指令,恢复现场。
以上步骤可以用如下示意图描述:
2.2.6 简单的IRQ中断服务函数实例
IRQ_Handler
PUSH {r0-r3, r12, lr} @ Store AAPCS registers and LR onto the IRQ mode stack
BL @ identify_and_clear_source
BL @ C-irq_handler
POP {r0-r3, r12, lr} @ Restore registers and
SUBS pc, lr, #4 @ return from exception using modified LR
操作如下:
(1)将LR(程序链接寄存器)及可能破坏的寄存器入栈
(2)识别中断源
(3)跳转到相应的中断服务函数
(4)将保存的寄存器出栈
(5)将LR(链接寄存器)值-4,然后写入PC(程序计数器)
这里之所以需要将LR(链接寄存器)值-4再写入PC原因如下:
当IRQ或FIQ中断产生时,PC(程序计数器)指向当前指令后面第3条指令(对于ARM指令来说,它指向当前指令地址+12字节的位置,对于Thumb指令来说,它指向当前指令地址加6个字节的位置)。ARM指令下,当IRQ和FIQ中断发生时,处理器会将值(PC-4)保存到异常模式下的LR(链接寄存器)中,这时PC-4即指向当前指令后的第2条指令。因此返回操作中再将PC-4就可以得到当前指令后的第一条指令,从而实现现场恢复。
说明:
3 总结
(1)以上例子同样适用于FIQ中断。
(2)IRQ中断的关键操作是保存了中断打断点后面第2条指令地址到IRQ模式的LR(链接寄存器),使得中断打断后能够恢复现场。
(3)从简单中断处理机制可以看出,由于进入IRQ模式时IRQ一直处于屏蔽状态,因此是不可能做到中断嵌套。同时又由于LR(链接寄存器)在每次进入IRQ模式前会硬件自动设置为打断点后面第2条指令地址,即使我们人为进入使能IRQ的IRQ模式,假如我们在将LR(链接寄存器)入栈之前触发了一次IRQ中断后由于LR(链接寄存器)被修改,第一个IRQ将无法返回第一次打断点,一直执行被第二次中断打断后的断点到退出IRQ模式中间的语句,陷入死循环。