cortex-m4架构支持的功能
- 与快中断处理结合的高性能处理性能
- 带有大量的breakpoint和trace功能的增强型系统debug功能
- 高效的处理核,系统和内存
- 带有集成的睡眠模式和可选的深度睡眠模式的超低功耗
- 平台安全的鲁棒性,带有可选的集成MPU
一些组件
-
WIC:The Wakeup Interrupt Controller (WIC) is a peripheral that can detect an interrupt and wake the processor from deep sleep mode
-
NVIC:Nested Vectored Interrupt Controller (NVIC)
- Non Maskable Interrupt(NMI): 提供了256个中断等级
-
process core和NVIC的集成提供了Interrupt Service Routines(ISRs)快速执行,动态的减少中断的延时。
-
System Control Block
-
System timer
-
Memory Protection Unit
-
Floating-point Unit
编程模型:
处理器模式:
-
thread mode
-
handler mode
软件执行的特权等级:
-
Unprivileged
- 对MSR和MRS指令的访问权限有限,并且不能使用CPS指令
- 不能访问system timer, NVIC和system control block
- 对于内存和外设有严格的访问权限
-
Privileged
- 待补充
core registers:
stack:
处理器实现了两个栈main stack 和process stack。CONTROL寄存器的bit[1]控制选择哪个栈, 0选择主栈,1选择进程栈。
异常模型:
异常状态:
- Inactive:
- Pending: 异常正等着处理器处理
- Active: 说明异常正在被处理器处理
- Active and pending: 异常正在被处理,同时该异常源又触发了一次异常
异常的类型:
- Reset :收到该异常之后,将pc指针重置为向量表的reset项中提供的地址(一般是系统代码段的起始地址)
- NMI :不可屏蔽的中断
- HardFault :当异常处理的过程中发生了错误,或者是发生的异常不能归类到其他异常类型中,都会触发HardFault异常。
- MemManage :当出现了与内存保护相关的错误时会触发该异常
- BusFault :是由于指令或者是数据存储相关的内存出现故障触发的异常一般是在总线上出现了问题。
- UsageFault :是一种指令执行故障触发的异常,包括未定义的指令,非法的未对齐的访问,指令执行状态是无效的,异常返回了错误
- SVCall :a supervisor call是SVC指令触发的异常,在OS环境中,应用可以使用SVC指令访问OS内核函数和设备驱动
- PendSV :是一个中断调度请求。在OS环境中,当没有其他异常活跃的情况下,使用PendSV来切换上下文
- SysTick :操作系统的“心跳”,该类型异常的作用就是轮转调度进程
- Interrupt(IRQ)
异常处理器:
- Interrupt Service Routines(ISRs): 处理IRQ中断
- Fault handlers: 处理HardFault,MemManage Fault, UsageFault和BusFault
- system handlers: 处理NMI,PendSV,SVCall, SysTick和所有系统异常
向量表
系统复位时,向量表固定在地址0x00000000。 特权软件可以写入VTOR,以将向量表的起始地址重新定位到其他存储器位置,范围为0x00000080至0x3FFFFF80。
操作的是Vector Table Offset Register,VTOR表示向量表基址与存储器地址0x00000000的偏移量。该寄存器[31:7]有效,bit[29]决定了向量表示是在代码段(0),还是在SRAM内存(1)。
异常的优先级
Exception number | IRQ number | Exception type | Priority | Vector address or offset | Activation |
---|---|---|---|---|---|
1 | - | Reset | -3 | 0x00000004 | Asynchronous |
2 | -14 | NMI | -2 | 0x00000008 | Asynchronous |
3 | -13 | HardFault | -1 | 0x0000000C | - |
4 | -12 | MemManage | Configurable | 0x00000010 | Synchronous |
5 | -11 | BusFault | Configurable | 0x00000014 | Synchronous when precise,asynchronous when imprecise |
6 | -10 | UsageFault | Configurable | 0x00000018 | Synchronous |
7-10 | - | Reserved | - | - | - |
11 | -5 | SVCall | Configurable | 0x0000002C | Synchronous |
12-13 | - | Reserved | - | - | - |
14 | -2 | PendSV | Configurable | 0x00000008 | Asynchronous |
15 | -1 | Systick | Configurable | 0x00000008 | Asynchronous |
16 | 0 | Interrupt(IRQ) | Configurable | 0x00000008 | Asynchronous |
根据异常处理器的分类,PendSV,SVCall, SysTick和所有系统异常以及HardFault,MemManage Fault, UsageFault和BusFault的优先级设置是通过操作System Handler Priority Registers。该寄存器组包含4个寄存器SHPR1-SHPR3。
IRQ中断的优先级是通过操作Interrupt Priority Registers配置的。
对于优先级可配置的中断,优先级只能配置为大于等于0的值。该寄存器组包含60个寄存器,IPR0-IPR59,其中每个寄存器32位,每个字节定义一个中断的优先级从小到大依次决定PRI_0-PRI-239一共240个中断的优先级,优先级的范围在0-255。
通过中断 m 找到IPR号和字节偏移的流程如下:
Interrupt Active Bit Register(IABR)寄存器组包含NVIC_IABR0 - NVIC_IABR7,这些寄存器的每一位都指示对应的中断是否为活跃状态,一共是256位。
对应的IPR号n = (m div 4), 字节偏移为 (m MOD 4)
Software Trigger Interrupt Register(STIR),当写这个寄存器的时候会触发一个中断,低9位有效
中断优先级分组
该机制会将每个中断优先级寄存器的项分为两个字段:
- 高位字段定义了组优先级
- 低位字段定义了组内各项的子优先级
只有组优先级决定了异常的中断优先抢占等级,同一组的异常是不能相互抢占的。
如果多个挂起中断拥有相同的组优先级,子优先级就决定了谁先执行
异常的入口以及返回:
preemption :高优先级的异常可以抢占低优先级的异常。当这种情况出现时,高优先级的中断被称为嵌套中断
return :当异常处理器执行完成后,并且没有其他挂起且优先级足够的中断需要处理,将会返回。处理器将弹出堆栈并且恢复中断发生之前的环境。
Tail-chaining: 该机制会加速中断的处理。当一个异常完成时,恰好有另外一个挂起异常等着执行,那么异常栈在弹出的时候,会自动跳过弹出的过程,自动跳转到进行异常处理函数处继续执行
Late-arriving:该机制会加速中断的抢占。当有一个更高优先级的异常在前一个异常保存状态时发生,处理器会切换到处理更高等级的中断,然后初始化异常的向量获取指针(即从异常向量表的起始位置查找异常),状态保存不会受到Late-arriving中断的影响,因为它们的状态保存都是一样的。
异常的进入
异常进入发生的时机:
- 存在优先级足够并且处于挂起状态的中断
- 处理器在Thread mode
- 发生了高优先级中断抢占当前中断的情况
当处理器接受异常时,除非该异常是一个尾链异常或一个延迟到达的异常,否则处理器将信息推送到当前堆栈。这种操作称为stacking,8个数据字的结构被称为stack frame。
在保存现场的同时,处理器会从异常向量表的起始位置找到对应的异常处理函数。当压栈完成后,处理器会开始执行异常处理函数。同时,处理器会将EXC_RETURN的值写入LR寄存器。这表示哪个堆栈指针对应于堆栈帧,以及在异常发生之前处理器处于什么操作模式。如果在异常输入期间没有发生高优先级异常,处理器将开始执行异常处理程序,并自动将相应的挂起中断状态更改为活动状态。
异常的退出
异常的退出发生的时机是处理器处于Handler mode并且执行了以下指令将EXC_RETURN值写入PC
- an LDM or POP instruction that loads the PC
- an LDR instruction with PC as the destination
- a BX instruction using any register.
故障处理(Fault handling)
fault是异常的子集,fault产生的原因:
- a bus error on:
- an instruction fetch or vector table load
- a data access
- 内部检测到的错误,如未定义的指令
- 试图执行一条指令从被标记为Execute-never的内存区域
- 如果您的设备包含一个MPU、一个特权冲突或试图访问一个非托管区域而导致MPU错误
通过一些寄存器可以获取当前fault的一些信息:
- HardFault status register
- MemMange Fault Address register
- BusFault Status Register
- UsageFault Status Register
具体的信息可以查看芯片文档
fault升级和hard fault
fault升级都会导致hard fault,fault升级的原因:
- fault handler在处理fault时又发生了相同类型的fault
- fault handler在处理fault时又发生了相同优先级或者是较低优先级的fault
- 异常处理器在处理异常时触发了相同优先级或者较低优先级的异常
- 当触发了fault,并且相应的fault handler没有设置
与cpu上下文切换相关:
-
中断上下文切换
异常进入的时候会保存现场,异常执行完成后,会恢复现场 -
进程上下文切换(应该说是不同进程中线程的切换)
-
线程上下文切换
切换时机,一般情况下是线程的时间片用完了触发了SysTick中断,发生了线程的切换