Cortex-M3 NVIC与中断控制
NVIC概览
向量中断控制器,即NVIC,是 Cortex-M3 不可分离的一部分,它与 CM3 内核的逻辑紧密耦合。NVIC 与 CM3 内核同声相应,同气相求,相辅相成,里应外合,共同完成对中断的响应。NVIC 的寄存器以存储器映射的方式来访问,除了包含控制寄存器和中断处理的控制逻辑之外,NVIC 还包含了 MPU、SysTick 定时器以及调试控制相关的寄存器。
NVIC 共支持 1 至 240个外部中断输入(通常外部中断写作 IRQs)。具体的数值由芯片厂商在设计芯片时决定。此外,NVIC 还支持一个“永垂不朽”的不可屏蔽中断(NMI)输入。NMI 的实际功能亦由芯片制造商决定。在某些情况下,NMI 无法由外部中断源控制。
NVIC 的访问地址是 0xE000_E000。所有 NVIC 的中断控制/状态寄存器都只能在特权级下访问。不过有一个例外——软件触发中断寄存器可以在用户级下访问以产生软件中断。所有的中断控制/状态寄存器均可按字/半字/字节的方式访问。此外,还有几个中断掩蔽寄存器也与中断控制密切相关,它们是“特殊功能寄存器”,只能通过 MRS/MSR 及 CPS 来访问。
中断的使能与除能
中断的使能与除能分别使用各自的寄存器来控制——这与传统的,使用单一比特的两个状态来表达使能与除能是不同的。CM3 中可以有 240 对使能位/除能位(SETENA位/CLRENA 位),每个中断拥有一对。这 240 个对子分布在 8 对 32 位寄存器中(最后一对没有用完)。欲使能一个中断,我们需要写 1 到对应 SETENA 的位中;欲除能一个中断,你需要写 1 到对应的CLRENA 位中。如果往它们中写 0,则不会有任何效果。写零无效是个很关键的设计理念:通过这种方式,使能/除能中断时只需把“当事位”写成 1,其它的位可以全部为零。再也不用像以前那样,害怕有些位被写入0 而破坏其对应的中断设置(反正现在写 0 没有效果了),从而实现每个中断都可以自顾地设置,而互不侵犯——只需单一的写指令,不再需要读-改-写三步曲。
如上所述,SETENA 位和 CLRENA 位可以有 240 对,对应的 32 位寄存器可以有 8 对,因此使用数字后缀来区分这些寄存器,如 SETENA0, SETENA1…SETENA7。但是在特定的芯片中,只有该芯片实现的中断,其对应的位才有意义。因此,如果某个芯片支持 32 个中断,则只有 SETENA0/CLRENA0 才需要使用。SETENA/CLRENA 可以按字/半字/字节的方式来访问。又因为前16个异常已经分配给系统异常,故而中断 0 的异常号是 16。
1
2
SETENAs:0xE000_E100 – 0xE000_E11C # 使能
CLRENAs:0xE000_E180 - 0xE000_E19C # 除能
中断的悬起与解悬
如果中断发生时,正在处理同级或高优先级异常,或者被掩蔽,则中断不能立即得到响应。此时中断被悬起。中断的悬起状态可以通过“中断设置悬起寄存器(SETPEND)”和“中断悬起清除寄存器(CLRPEND)”来读取,还可以写它们来手工悬起中断。
悬起寄存器和“解悬”寄存器也可以有 8 对,其用法和用量都与前面介绍的使能/除能寄存器完全相同。
1
2
SETPENDs:0xE000_E200 – 0xE000_E21C # 悬起
CLRPENDs:0xE000_E280 - 0xE000_E29C # 解悬
优先级
每个外部中断都有一个对应的优先级寄存器,每个寄存器占用 8 位,但是 CM3 允许在最“粗线条”的情况下,只使用最高 3 位。4 个相临的优先级寄存器拼成一个 32 位寄存器。如前所述,根据优先级组的设置,优先级可以被分为高低两个位段,分别是抢占优先级和亚优先级。优先级寄存器都可以按字节访问,当然也可以按半字/字来访问。有意义的优先级寄存器数目由芯片厂商实现的中断数目决定。
1
2
中断优先级寄存器阵列 0xE000_E400 – 0xE000_E4EF
系统异常优先级寄存器阵列 0xE000_ED18 - 0xE000_ED23
活动状态
每个外部中断都有一个活动状态位。在处理器执行了其 ISR 的第一条指令后,它的活动位就被置 1,并且直到 ISR 返回时才硬件清零。由于支持嵌套,允许高优先级异常抢占某个 ISR。然而,哪怕中断被抢占,其活动状态也依然为 1(请仔细琢磨前文讲到的“直到 ISR 返回时才清零)。活动状态寄存器的定义,与前面讲的使能/除能和悬起/解悬寄存器相同,只是不再成对出现。它们也能按字/半字/字节访问,但他们是只读的。
1
ACTIVE 寄存器族 0xE000_E300_0xE000_E31C
特殊功能寄存器 PRIMASK 与 FAULTMASK
待补充…
BASEPRI 寄存器
待补充…
系统Handler控制及状态寄存器(SHCSR)
用法fault,总线fault以及存储器管理fault都是特殊的异常,因此给它们开了小灶。其中,它们的使能控制是通过“系统Handler控制及状态寄存器(SHCSR)”(地址:0xE000_ED24)来实现的。各种faults的悬起状态和大多数系统异常的活动状态也都在该寄存器中。 系统Handler控制及状态寄存器SHCSR(地址:0xE000_ED24)
SHCSR中的活动位虽然也是可写的,但是改动时必须予以极度的小心,否则这是玩火行为——设置或者清零这些位,会改变处理器中对异常活动的记录,却不会对应地修复堆栈中的数据(不会为了此改动而特意执行一次自动入栈或自动出栈操作),于是埋下了破坏堆栈内容而引起程序跑飞的隐患;另外,其它一些重要的数据结构也得不到清除,后患无穷。事实上,只有操作系统在特殊场合下才会修改它们。例如:在任务执行系统调用的过程中执行上下文切换(大幅提升实时性),或者在使用软件模拟未定义指令的功能期间(在用法fault服务例程中),以及软件模拟协处理器的功能期间,执行上下文切换,同样大幅提升实时性。
中断控制及状态寄存器ICSR。
对于NMI、SysTick定时器以及PendSV,可以通过此寄存器手工悬起它们。另外,在该寄存器中,有好多位段都用于调试目的。在大多数情况下,它们对于应用软件都没有什么用处,只有悬起位对应用程序常常比较有参考价值。
中断控制及状态寄存器ICSR(地址:0xE000_ED04)
未完待续…