← 返回 计组与微机控制

计组与微机控制

9.1 中断向量表和中断源以及优先级

9.1 中断向量表和中断源以及优先级

二. 中断向量表

1.中断向量表定义

定义: 中断向量表是存放异常服务程序入口地址的一张表,CPU 通过它找到对应异常/中断的处理函数。

Cortex-M 采用矢量中断:

向量表中存放的不是跳转指令,而是 ISR 入口地址。

2 指令型向量表与矢量型向量表

指令型中断向量表: 表中存放跳转指令,常见于部分早期处理器。

矢量中断向量表: 表中存放中断服务程序入口地址,Cortex-M 采用这种方式。

6.3 Cortex-M 向量表地址计算

每个向量表项占 4 字节,因此:

向量地址 = 向量表基地址 + 异常编号 × 4

9.1 中断向量表和中断源以及优先级 图 19.1 中断向量表和中断源以及优先级 图 2

例子:HardFault 异常编号 = 3

向量表偏移 = 3 × 4 = 0x0C

HardFault 向量地址 = 向量表基地址 + 0x0C

6.4 向量表前几个固定项

Cortex-M 向量表开头通常为:

0x00:初始 MSP 值

0x04:Reset_Handler

0x08:NMI_Handler

0x0C:HardFault_Handler

...

注意:第 0 项不是中断函数地址,而是主栈指针 MSP 初值。

9.1 中断向量表和中断源以及优先级 图 3

中断流程:

9.1 中断向量表和中断源以及优先级 图 49.1 中断向量表和中断源以及优先级 图 59.1 中断向量表和中断源以及优先级 图 6

7. 向量表重定位

7.1 向量表重定位定义

定义:向量表重定位是把向量表基地址从默认位置改到新的存储区域,使 CPU 按新的向量表响应异常。

Cortex-M 通过 SCB 的 VTOR 寄存器实现:

SCB->VTOR

7.2 为什么需要重定位

默认向量表常位于 Flash 起始地址,运行时不方便修改。若系统需要动态修改中断入口,常把向量表复制到 RAM,再修改 VTOR 指向 RAM 中的新向量表。

常见用途:

BootLoader 跳转应用程序

操作系统切换任务或应用

动态修改中断服务入口

7.3 对齐要求

向量表基地址不是任意地址,必须满足对齐要求。向量表大小通常要扩展到下一个 2 的整数次方。

例子:32 个外部中断 + 16 个系统异常 = 48 个向量

48 × 4 = 192 字节

扩展到 256 字节对齐

75 个外部中断 + 16 个系统异常 = 91 个向量

91 × 4 = 364 字节

扩展到 512 字节对齐

8. NVIC

8.1 NVIC 定义

定义: NVIC 是 Nested Vectored Interrupt Controller,嵌套向量中断控制器,用于管理 Cortex-M 的外部中断请求。

9.1 中断向量表和中断源以及优先级 图 7

作用:

接收多个外部中断请求,管理中断使能/禁止

管理中断挂起状态,管理中断优先级

支持中断嵌套,支持矢量化跳转

Cortex-M 中断与异常

1. 中断向量表

中断发生后,CPU 必须知道:

发生了哪个中断?这个中断对应的服务程序 ISR 在哪里?

这个“中断号 → 中断服务程序入口地址”的对应关系,就由中断向量表完成。

1.1 中断向量表的本质

中断向量表是系统 ROM 或 RAM 中的一块区域,里面按顺序存放每个异常或中断对应的入口信息。

可以理解成:中断编号 → 查中断向量表 → 得到中断服务程序入口地址 → 跳转执行 ISR

中断向量表里通常不是完整的中断服务程序代码, 而是服务程序的入口地址,或者是一条跳转指令。

异常编号 1 ~ 15 是系统异常

其中几个固定优先级很重要:

注意:

Reset、NMI、HardFault 优先级固定,不能像普通中断那样随便改。

2.2 外部中断

外部中断一般来自外设,例如:

定时器GPIO,串口 SPI,I2C,ADC,DMA EXTI 外部中断线

在 Cortex-M 中:异常编号 16 及以后是外部中断

9.1 中断向量表和中断源以及优先级 图 8

所以:

外部中断 IRQ0 对应异常编号 16 外部中断 IRQ1 对应异常编号 17 外部中断 IRQ2 对应异常编号 18

关系可以记成:

异常编号 = IRQn + 16 IRQn = 异常编号 - 16

例如:IRQ0 的向量地址 = VTOR + (0 + 16) × 4 IRQ5 的向量地址 = VTOR + (5 + 16) × 4

2.3 Cortex-M 常见中断源分类

NVIC 接收的中断源分成几类,可以整理为:

外部中断请求 IRQ 不可屏蔽中断 NMI SysTick 系统节拍中断 内核系统异常 软件中断源

外部中断 IRQ

由外设产生,例如:

定时器 I/O 端口 通信接口 ADC DMA EXTI

不可屏蔽中断 NMI

NMI 不能被普通屏蔽寄存器屏蔽。

典型来源:

看门狗 掉电检测 严重外部故障

NMI 的优先级仅低于 Reset。

SysTick 中断

SysTick 来自 Cortex-M 内核的系统定时器。

常用于:

操作系统节拍 定时任务 延时计数 系统调度

软件中断源

课件中提到一些软件触发方式,例如:

SVC 指令触发 SVCall NVIC_STIR 触发外部中断 NVIC_ISPR 设置挂起位 EXTI_SWIER 软件触发外部中断事件

可以理解为:

有些中断不是外设真的拉了一根线, 而是软件主动写寄存器制造一个中断请求。

NVIC 和 SCB 的位置

9.1 中断向量表和中断源以及优先级 图 9

Cortex-M 中,NVIC 和 SCB 都位于系统控制空间 SCS:

SCS 基地址:0xE000E000 大小:4 KB

其中:NVIC:主要管理外部中断 SCB:系统控制块,管理系统异常、向量表重定位、优先级分组等

NVIC 和 SCB 位于系统控制空间 SCS 地址从 0xE000E000 开始 大小为 4 KB

4. Cortex-M 中断管理寄存器

9.1 中断向量表和中断源以及优先级 图 10

4.1 PRIMASK

PRIMASK 用于快速屏蔽大多数中断。

PRIMASK = 0:不屏蔽 PRIMASK = 1:屏蔽所有可屏蔽异常

但是它不能屏蔽:NMI,HardFault

所以可以记成:PRIMASK 屏蔽普通中断和大多数异常, 但 NMI 和 HardFault 仍然可以响应。

PRIMASK 本质上是把当前优先级提高到 0, 因此优先级不高于 0 的可配置异常都进不来。

4.2 FAULTMASK

FAULTMASK 更强。

FAULTMASK = 1:屏蔽除 NMI 以外的所有异常

也就是说:FAULTMASK 置 1 后,只有 NMI 可以响应。

它甚至可以屏蔽 HardFault。

所以它比 PRIMASK 更“狠”。一般用于非常关键的保护段。

另外:除了 NMI 异常处理之外,异常返回时通常会自动清除 FAULTMASK。

4.3 BASEPRI

9.1 中断向量表和中断源以及优先级 图 11

BASEPRI 是按优先级阈值屏蔽中断。

BASEPRI = 0:不屏蔽 BASEPRI = 某个优先级值:屏蔽该优先级及更低优先级的中断

注意 Cortex-M 里:优先级数值越小,优先级越高。

所以如果:BASEPRI = 0x40

那么会屏蔽:优先级数值 >= 0x40 的中断

也就是屏蔽:0x40、0x60、0x80、0xA0、0xC0、0xE0……

但不会屏蔽:0x00、0x20

可以记成:BASEPRI 屏蔽“低于或等于某门槛”的中断, 高优先级中断仍然能进来。

4.4 三个屏蔽寄存器对比

PRIMASK:屏蔽大多数 FAULTMASK:只留 NMI BASEPRI:按优先级门槛屏蔽

5. Cortex-M 中断优先级

5.1 优先级基本规则

Cortex-M 的优先级规则:

优先级数值越小,实际优先级越高。

例如:优先级 0 高于优先级 1 优先级 1 高于优先级 2 0x00 高于 0x20 0x20 高于 0x40

这点和生活中“数字越大越厉害”的直觉相反,要特别注意。

5.2 固定优先级

几个异常优先级固定:

Reset -3 NMI -2 HardFault -1

它们高于普通可编程中断。

普通外部中断和部分系统异常的优先级是可编程的。

5.3 NVIC_IPRx 优先级寄存器

9.1 中断向量表和中断源以及优先级 图 12

每个外部中断都有一个优先级配置。

Cortex-M 中优先级寄存器通常是 8 位宽。

每个中断占 8 位,4 个中断共用一个 32 位 NVIC_IPRx 寄存器

所以:NVIC_IPR0 管理 IRQ0 ~ IRQ3,NVIC_IPR1 管理 IRQ4 ~ IRQ7……

每个优先级用 8 bit 管理,60 个中断需要 60 个 8 bit = 60 字节

对应 15 个 32 位寄存器

5.4 不是 8 位都有效

虽然优先级寄存器是 8 位,但实际芯片不一定实现全部 8 位。

很多 Cortex-M 只实现高几位。

例如 Cortex-M3/M4 常见实现 3 位优先级,则有效位是:bit7 bit6 bit5

低位:bit4 ~ bit0通常没有实现,写了也无效,读出来为 0。

所以可用优先级只有:

0x00 0x20 0x40 0x60 0x80 0xA0 0xC0 0xE0

低位不用,置 0,优先级是高位有效

5.5 Cortex-M0+ 的优先级

Cortex-M0+:

NVIC_IPR 只有 8 个寄存器 每个寄存器管理 4 个 IRQ 最多支持 32 个 IRQ 中断源

如果只实现最高 2 位,则可用优先级只有:0x00 0x40 0x80 0xC0也就是 4 个优先级。