异常状态
在Cortex-M7处理器中有四种异常状态
- 不活跃
- 挂起
- 活跃
- 活跃和挂起
- CPU正在处理一个异常,但是还有一个与他相同中断源的异常处于挂起状态
异常类型
异常类型 | 描述 |
---|
复位异常(Reset) | 复位异常始终有效,他有一个固定的优先级-3 | 不可屏蔽中断(NMI) | 可以由外设发送信号或者软件触发,这是除了复位之外的最高优先级中断 它有一个固定优先级-2,他不可以被其他活跃的异常屏蔽 也不可以被除了复位之外的异常抢占 | 硬件故障(HardFault) | 该异常发生于异常处理时出现错误,或者是因为该异常不能被任何其他的异常机制管理 他的优先级固定为-1,意味着它拥有比那些优先级可配置的异常更高的优先级 | 内存管理错误(MemManage) | 这是由于内存访问限制,或者MPU设置的内存访问属性造成的错误 这个异常常用于终止在不可执行区域的指令访问 | 使用故障(UsageFault) | 这个异常发生和指令执行相关,例如未定义指令,非法的非对齐内存访问 无效的状态和指令执行,异常返回出错,另外还有一些可以配置的的行为也会造成该异常,在未对齐的地址进行半字访问和字访问,除0 | SVC | 这个类似于Linux的系统调用,在带操作系统环境下,使用SVC指令可以触发该异常,用于访问内核资源和设备驱动 | PendSV | PendSV 是系统级服务的中断驱动请求,在带操作系统环境下,没有其他异常活跃的情况下使用 PendSV 进行上下文切换 | SysTick | 一个向下计数器,当他计数值为0时将触发异常,也可以通过软件触发,在带操作系统的环境下,这个异常可以用作操作系统的系统时钟 | Interrupt | 由于指令或者外设触发的中断,所有外设的中断优先级都是可以配置的,外设通过中断和处理器进行通讯 |
异常处理程序
类型 | 描述 |
---|
ISR | IRQ0到IRQ239的中断都是由中断服务程序处理,具体的中断号由厂商实现定义 | 故障处理 | HardFault、MemManage fault、UsageFault 和 BusFault 都是由故障处理程序处理 | 系统服务程序 | NMI、PendSV、SVCall SysTick、均由系统处理程序处理 |
中断向量表
在内部引导程序运行期间使用的中断向量表从0x00000000开始,运行用户程序时,中断向量表的地址由用户决定,例如ST的固件库就是将中断向量表存放于0x8000000。
中断优先级
上图中的中断向量表中所有异常都有优先级:
- 优先级的数字越低代表优先级越高
- 除了复位异常,故障异常,不可屏蔽中断他们的优先级不可更改,其他的优先级都可以改。
如果软件没有设置优先级,那么所有优先级可配置的异常的优先级都为0。
优先级的最大可配置范围是0-255,实际可用的配置发范围是由实现定义的,这意味着优先级固定为负数的复位异常,故障异常,不可屏蔽中断他们的优先级总是比其他的异常更高。
中断优先级分组
为了在有中断的系统中增加优先级控制,NVIC支持优先级分组。这将每个中断优先级寄存器输入分为两个区域:
- 高位部分代表组优先级
- 低位部分在组内定义一个子优先级
只有组优先级会影响到中断抢占,当处理器正在执行一个中断处理程序时,发生另外一个中断,这个中断的组优先级和当前正在处理的中断是相同的,此时不会发生抢占。
如果多个挂起的中断具有相同的组优先级,则子优先级将确定处理它们的顺序。如果多个挂起中断具有相同的组优先级和子优先级,则首先处理中断号最低的中断。
异常和返回
抢占
当处理器正在处理一个异常时,该异常可以被一个更高优先级的异常抢占,这种情况叫做异常嵌套。
异常返回
发生于下面两种情况:
- 异常处理完成,并且没有正在挂起且优先级够高的异常时。
- 异常处理已完成,并且没有后到达还未处理的异常。
处理器从栈上恢复进入中断之前的状态。
Tail-chaining
这种机制加快了异常服务的速度, 在完成一个异常处理程序后,如果有一个处于挂起状态且满足进入异常处理的条件,堆栈弹出将被跳过,控制权将被转移到新的异常处理程序。
Late-arriving
这种机制加速了抢占, 如果在先前异常在状态保存期间有更高优先级的异常发生,处理器将处理更高优先级的异常并从中断向量获取异常处理程序。 状态保存不受影响,状态保存是对这两个异常都是相同的, 因此状态保存不会被打断。 处理器可以接受迟到的异常,直到原有异常的异常处理程序的第一条指令进入处理器的执行阶段。
异常进入
-
当一个异常有足够的优先级,并且满足下面其中一个条件:
-
当一个异常抢占另一个异常,这种情况下异常是嵌套的。 -
当一个异常拥有更高的优先级,意味着异常屏蔽寄存器对它的限制越小,如果新的异常优先级低于被挂起的异常,那么他不会被处理器响应。
当处理器处理一个异常时,会把当前的信息放到栈上,这个操作叫做入栈,由8个字组成的数据结构叫做栈帧。
使用浮点例程时,Cortex-M7 处理器在入栈时将自动把该架构的浮点状态入栈,下图展示了Cortex-M7 处理器发生中断或者异常时的堆栈帧布局。 栈帧中包含了异常返回地址,该地址是被中断程序的下一条指令地址,当异常返回后,该地址将恢复到PC中,被中断的程序继续执行。
在入栈的同时,处理器从中断向量表中查找到异常处理程序的地址,入栈完成后,处理器开始执行异常处理程序,与此同时,处理器将会写入一个EXC_RETURN值到LR寄存器中,该值表明哪个栈指针与栈帧一致,以及在中断发生之前处理器处于什么操作模式。
异常返回
异常返回发生在Handler模式,并且执行了以下指令将EXC_RETURN放入PC寄存器中:
- 一条LDM或者POP指令加载到PC中
- 一条LDR指令,PC作为目的寄存器
- 使用任何寄存器执行BX指令
EXC_RETURN是异常进入时放入到LR中的值,异常处理机制依赖于该值来检测处理器何时完成了异常处理,该值的最低5位提供了返回时的栈信息和处理器模式。
EXC_RETURN的5到31位全为1,当这个值被加载到处理器中时,表面处理器已经完成了异常处理。
故障处理
故障是异常的一个子集,它通常由下面几个原因造成
- 总线错误
- 由内部侦测到的错误,例如未定义指令
- 试图在一个不可执行的内存区域执行指令
- 如果您的设备包含MPU,违反了对应的权限或试图访问一个不受管理的区域将导致MPU故障(例如使用外部的SDRAM但是没有通过MPU为该区域设定权限,会导致HardFault)
|