Cortex-M7 异常(中断)基础总结

1 前言 

         Cortex-M7集成了嵌套向量中断控制器(Nested Vectored Interrupt Controller),最大支持256个中断优先级,其 “向量” 指示着中断服务函数(interrupt  service routines, ISRs)响应的方式不再通过软件编程来实现,即由硬件堆叠的寄存器组和相应可挂起的多指令加载和存储指令(可被中断打断,给中断让路),来实现从中断响应到ISR入口的快速选择这一过程。

2 异常模型(Exception model)

2.1 异常状态(Exception states)

表1 异常状态
状态描述
Inactive该异常非active,且没有pending
Pending该异常正在等待CPU响应
ActiveCPU已经开始处理该异常,且尚未结束(当一个异常打断另一个异常处理时,则认为这两个异常都处于Active状态)
Active and pending该异常已被CPU处理,同时又有同一中断源的新异常发生,该新异常被悬起

2.2 异常类型(Exception Types)

        Cortex-M7的中断向量表最大支持256个异常,并主要包含以下异常类型:

 2.2.1 Reset

        Reset是一种特殊的异常类型,在系统上电或热复位后执行,其优先级固定为-3(全局最高,会得到最优先的响应),且永远处于使能状态,谁也无法剥夺一个系统重启的权利;当Reset被触发时,CPU会放下手头正在做的任何事情,立即响应,并从中断向量表中找到对应的中断服务函数(ISR),即Reset_Handler,重启完成后进入特权级线程模式;

        通常来说,从复位开始,到重启开始,这之间通常还有一个过程,而Reset_Handler则是在重启后运行并完成初始化过程的。

2.2.2  NMI

        non-maskable interrupt,不可屏蔽中断,其优先级固定为-2,仅次于Reset,NMI的使用取决于用户,通常会用于看门狗、安全警报、调试等场景。

2.2.3 Hardfault

        Hardfault是由异常处理过程中的错误引发的异常,或者是由一个其他异常机制处理不了的问题引起。其优先级固定为-1,也就是说排名老三,是最后一个优先级不可配置(为固定值)的异常。

2.2.4 MemManage

        通常是由内存保护相关的错误引起的异常。通常由固定的内存保护规则或MPU来定义这种错误,该错误通常用于种植对非执行内存区域(Excute Never, XN)的指令访问。总之,对特定内存区域的违规操作,通常会通过MemManage异常来进行处理。

2.2.5 BusFault

        通常是由数据或指令处理过程中,内存系统总线上发生了错误,而导致该异常。

2.2.6 UsageFault

        通常是由于非法的指令的执行导致,包括:

        ① 一个未定义的指令;

        ② 非法的未对齐访问;

        ③ 指令执行的无效状态;

        ④ 异常返回时发生错误;

        例如,除0操作或在字或半字对齐的存储器上访问未对齐的地址,都会导致该异常。而Cortex-M7虽然支持非对齐访问,但也只局限于以下指令

• LDR, LDRT.
• LDRH, LDRHT.
• LDRSH, LDRSHT.
• STR, STRT.
• STRH, STRHT

        其余的非对其访存都会引发UsageFault,而且通常非对齐访存的效率都会降低,所以变成过程中还是要养成内存对齐的习惯。

2.2.7 SVCALL

        Supervisor call(SVC),由SVC指令触发。在OS环境下,应用程序可以通过SVC指令陷入内核进行系统调用或访问设备驱动层。

2.2.8 PendSv

        PendSv通常用于OS的任务(线程)切换,并设置其优先级为最低,以保证不会抢占其他异常的处理过程,即在其他异常处理完成后运行;

2.2.9 SysTick

        当产生系统时钟。

2.2.10 Interrupt(IRQ,中断请求)

        通常由外设或软件请求产生的异常,通常这种异常是由外部信号或软件向CPU的请求产生,所以通常称之为外部中断。所以,外部中断对于CPU当前的指令执行来说都是异步的,也就是说CPU不知道它何会来,来了就是个情理之中的不速之客。因此,外部中断,可以理解为外设与CPU通信的手段。

        总的来看:

        ① 除了Reset,NMI和HardFault这三个优先级为固定负数值的大佬外,其余异常的优先级都是可配置的;

        ② 除了MemManage,UsageFault等CPU可以自己检测发现的错误引发的异常,以及SVCall
这种通过显式指令执行引发的异常,绝大部分异常对于CPU来说都是异步的。所谓,兵来将挡,水来土掩,CPU按优先级对发生的异常一一处理,若多个异常同时发生,则将排队中的异常悬起等待;

        ③对于异步的异常,除了Reset之外,处理器在异常触发和进入对应的异常处理函数(ISR)前,尚有一条指令的时间处理其余事情(想必是用于收拾行李吧)。

2.3 异常处理

        异常处理主要包括三种:

        ①System handlers,主要是NMI,PendsV, SVcall等系统自定义的16个异常(MSP除外,其实是15个);

        ②Interrupt Service Routines(ISRs),中断服务函数,主要是指外部中断的处理函数,通常由用户自定义,最多支持240个,实际支持的数量取决与具体的CPU设计。

3 中断向量表

        如图1所示,所谓中断向量表,其代码层看起来就是个一位数组,其元素为32位的地址。第一个元素比较特殊,为复位后MSP的初始地址(值),其余255个都是中断服务函数(ISR)的入口地址。

        通常来说,系统上电后,会在一个已知的固定地址找到这个向量表,从而获取MSP的初始值(也就是栈的初始地址),在后续中断发生的时候,根据向量表的初始地址(数组的初始地址),就可以定位到ISR的入口地址,进而控制PC跳过去。

        此外,由于只支持在Thumb下执行指令,在EPSR 的T字段为0的情况下,执行任何指令都将导致错误或锁定,而向量表中地址都是要写入PC的。所以,向量表中的这些地址的bit[0]必须是1,这个1会最终体现在EPSR 寄存器的T字段。此外,如果这个向量表中填的是ISR的函数指针,且编译器设置选项中设置了Thumb-2指令模式,则编译器会保证bit[0]为1;如果是手动填入的地址,则需要应用程序自己来保证。

42280fcb48044ab684340394f599fb9f.png

图1 中断向量表(Vector table)

4 中断相关的程序状态寄存器

        程序状态寄存器(Program Status Register, PSR)属于特殊功能寄存器,包括以下三个子状态寄存器:

        • Application Program Status Register (APSR);
        • Interrupt Program Status Register (IPSR);
        • Execution Program Status Register (EPSR)

16d417fbb4c6430488e459604ff82935.png

图2 PSR寄存器位域分布  

        其位域分布如图2所示,通过 MRS/MSR 指令,这 3 个 PSRs 即可以单独访问,也可以组合访问(2 个组合, 3 个组合都可以)。当使用三合一的方式访问时,应使用名字“xPSR”或者“PSR”,具体如图3所示。

58cc44d46eb24d7d9bd1779f8af8c1fe.png

 图3 PSR寄存器组合(combinations)说明

        在这三个子状态寄存器种,IPSR和EPSR都与中断有着直接的关系。CPU响应异常的第一步就是寄存器压栈(保护现场),包括xPSR, PC, LR, R12以及R3-R0都是由硬件自动完成压栈,同时指令总线(I-CODE)总线会进行中断向量的取指工作,即找到ISR入口地址。在此基础上,还需要更新SP(使用MSP)、IPSR的ISR_NUMBER、PC(中断向量取指完成后指向ISR入口地址)、LR(存放EXC_RETURN)同时还会伴随着NVIC中响应异常的悬起位的清除与活动位的置位。

4.1 中断程序状态寄存器IPSR

         IPSR(Interrupt Program Status Register)记录了当前正在执行的ISR(Interrupt Service Routine)对应的异常号。该寄存器属于特殊功能寄存器,仅在特权模式下只读(不可写),非特权模式更是想都不要想,其位域分布如图4所示:     

6245409de77f4169be030845a1c26a56.png

图4 IPSR寄存器位域分布 

        注意,图4中的ISR_NUMBER为中断异常号,代表的是该异常在中断向量表中索引,包含CPU自身的16个系统中断(姑且将MSP也算在内)和最多240个外部中断。 当ISR_NUMBER为0时,表示当前处于线程模式,而非异常处理过程。

4.2 执行程序状态寄存器EPSR 

        EPSR(Execution Program Status Register)记录了程序执行种的状态信息,包括Thumb状态位,IT(if-then)指令块和可中断的连续指令(Interruptible-Continuable Instruction ,ICI)的执行状态位,具体位域分布如下:

表1 Execution Program Status Register 的位域分布
BitsName功能
31~27--Reserved
26~25,15~10ICI/IT可中断的连续指令/IT指令块的执行状态位
24TThumb状态位
23~16,9~0--Reserved

        其中,bit26~25,15~10指示的是指令的执行状态,由于IT指令块和ICI指令包含一系列连续的操作,若在执行过程种被异常打断,则在进入异常处理序列前,该执行状态位也参与到异常响应前的现场保护中去,并在异常返回时,结合LR中存储的信息恢复现场,继续指令的执行。

### Cortex-M7 处理器中断处理机制及配置方法 #### 中断控制器 (NVIC) Cortex-M7 配备了一个嵌套向量中断控制器(NVIC),用于管理和优先级分配多个中断源。NVIC 支持多达 240 个可编程优先级的外部中断线,允许灵活配置不同外设和事件触发的响应顺序[^1]。 #### 中断优先级分组 为了实现更精细的控制,Cortex-M7 提供了中断优先级分组功能。通过设置 `AIRCR` 寄存器中的 PRIGROUP 字段可以调整抢占式优先级(preemptive priority) 和子优先级(subpriority) 的位宽分布。这种设计使得系统能够更好地平衡实时性和资源利用率。 #### 向量表重定位 默认情况下,向量表位于闪存起始地址处;然而,在某些应用场景下可能需要动态改变其位置。为此,可以通过修改 `VTOR` (Vector Table Offset Register)来指定新的基址,从而支持更加复杂的应用需求如多任务调度或安全分区隔离。 #### 软件触发中断 除了硬件产生的中断请求之外,软件也可以主动发起特定编号的异常调用(SWI, Software Interrupt Instruction),这为调试工具以及操作系统内核提供了便利接口。 ```c // 设置全局中断使能 __enable_irq(); // 清除某个具体IRQ通道上的挂起状态 NVIC_ClearPendingIRQ(USART1_IRQn); // 设置某类IRQ对应的回调函数指针 void (* const usart1_handler)(void); usart1_handler = USART1_IRQHandler; // 安装并启用该IRQ通道 NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0)); NVIC_EnableIRQ(USART1_IRQn); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值