1. 中断向量表基础概念

1.1 中断向量表的定义

中断向量表(Interrupt Vector Table,IVT)是一张存储在固定内存区域的地址映射表,表中每一项存放着对应中断服务程序(Interrupt Service Routine,ISR)或异常处理程序的入口地址。当处理器检测到异常或中断事件时,硬件自动从向量表中取出对应地址,并跳转执行该地址处的代码。

核心要点:中断向量表本质上是“异常编号 → 处理函数地址”的查找表,由硬件直接使用,无需软件干预。

1.2 中断向量表的作用

  • 异常分发:将不同异常源(复位、NMI、硬故障、SVC、PendSV、SysTick 等)映射到对应的处理函数。
  • 系统启动引导:复位后处理器从向量表首地址加载主栈指针(MSP)和复位向量,完成初始化。
  • 实时响应:硬件级查表跳转,延迟极低,满足嵌入式实时性要求。
  • 可配置性:通过修改向量表内容或重定位向量表基址,实现灵活的中断管理。

1.3 在 ARM Cortex-M 系列处理器中的位置

ARM Cortex-M 系列处理器(M0/M0+/M3/M4/M7/M33 等)采用统一中断向量表设计,向量表固定在地址 0x00000000 起始处(默认),或通过 VTOR(Vector Table Offset Register)寄存器重定位到其他地址。

异常编号 向量表偏移 异常类型 优先级 说明
0 0x00 MSP 初始值 — 主栈指针初始值,复位后加载到 SP
1 0x04 Reset -3(最高) 复位异常,系统启动入口
2 0x08 NMI -2 不可屏蔽中断
3 0x0C HardFault -1 硬故障,所有故障的默认处理
4 0x10 MemManage 可编程 存储器管理故障(M3/M4/M7)
5 0x14 BusFault 可编程 总线故障(M3/M4/M7)
6 0x18 UsageFault 可编程 用法故障(M3/M4/M7)
7–10 0x1C–0x28 保留 — ARM 保留
11 0x2C SVC 可编程 系统服务调用(Supervisor Call)
12 0x30 DebugMon 可编程 调试监视器
13 0x34 保留 — ARM 保留
14 0x38 PendSV 可编程 可挂起系统服务请求
15 0x3C SysTick 可编程 系统滴答定时器
16+ 0x40+ 外部中断 可编程 芯片厂商定义的外设中断
注意:Cortex-M0/M0+ 只支持 NMI、HardFault、SVC、PendSV、SysTick 和最多 32 个外部中断;M3/M4/M7 支持完整的 MemManage、BusFault、UsageFault 以及最多 240 个外部中断。

1.4 向量表布局与内存映射

下图展示了 ARM Cortex-M 处理器默认中断向量表在内存中的布局结构:

ARM Cortex-M 中断向量表内存布局 ARM Cortex-M 中断向量表内存布局(默认基址 0x00000000) 地址偏移 异常编号 向量表内容 说明 0x00 0 MSP 初始值 复位后加载到 SP 0x04 1 Reset_Handler 系统启动入口 0x08 2 NMI_Handler 不可屏蔽中断 0x0C 3 HardFault_Handler 硬故障处理 0x2C 11 SVC_Handler 系统服务调用 0x38 14 PendSV_Handler 可挂起系统服务 0x3C 15 SysTick_Handler 系统滴答定时器 0x40+ 16+ IRQ_Handler[0..n] 芯片厂商定义外设中断 地址递增方向(每项 4 字节) 每个向量表项占用 4 字节,存放对应处理函数的入口地址

1.5 向量表在启动文件中的体现

在 ARM Cortex-M 工程中,中断向量表通常由启动文件(startup_xxx.s)定义。以下是一个典型的 Cortex-M4 启动文件片段:

; 中断向量表定义(startup_stm32f407xx.s)
__Vectors       DCD     __initial_sp          ; 0x00: MSP 初始值
                DCD     Reset_Handler          ; 0x04: 复位向量
                DCD     NMI_Handler            ; 0x08: NMI
                DCD     HardFault_Handler      ; 0x0C: 硬故障
                DCD     MemManage_Handler      ; 0x10: 存储器管理故障
                DCD     BusFault_Handler       ; 0x14: 总线故障
                DCD     UsageFault_Handler     ; 0x18: 用法故障
                DCD     0                      ; 0x1C: 保留
                DCD     0                      ; 0x20: 保留
                DCD     0                      ; 0x24: 保留
                DCD     0                      ; 0x28: 保留
                DCD     SVC_Handler            ; 0x2C: SVC
                DCD     DebugMon_Handler       ; 0x30: 调试监视器
                DCD     0                      ; 0x34: 保留
                DCD     PendSV_Handler         ; 0x38: PendSV
                DCD     SysTick_Handler        ; 0x3C: SysTick
                ; 外部中断从 0x40 开始
                DCD     WWDG_IRQHandler        ; 0x40: 窗口看门狗
                DCD     PVD_IRQHandler         ; 0x44: PVD
                ; ... 后续中断向量
常见错误:向量表第一项必须是有效的栈指针值,第二项必须是复位处理函数地址。如果这两个值错误,芯片上电后将无法正常启动,直接进入 HardFault 或死机。

1.6 向量表重定位(VTOR 寄存器)

Cortex-M3/M4/M7/M33 等处理器提供了 VTOR(Vector Table Offset Register) 寄存器,允许将向量表从默认的 0x00000000 重定位到其他地址(如 SRAM 或 Flash 的偏移位置)。这在以下场景中非常有用:

  • Bootloader + 应用程序:Bootloader 位于 Flash 起始地址,应用程序位于偏移地址,需重定位向量表。
  • 运行时动态更新:将向量表复制到 SRAM 中,运行时修改中断处理函数。
  • 多核系统:每个核使用独立的向量表。

VTOR 寄存器位于系统控制块(SCB)中,地址为 0xE000ED08,其格式如下:

位段 名称 描述
[31:7] TBLBASE 向量表基址的高 25 位,要求 128 字节对齐
[6:0] 保留 必须写 0

设置 VTOR 的示例代码:

/* 将向量表重定位到 0x08010000(应用程序起始地址) */
#define SCB_VTOR      (*(volatile uint32_t *)0xE000ED08)
SCB_VTOR = 0x08010000;
对齐要求:VTOR 的值必须按 128 字节对齐(即低 7 位为 0),否则处理器行为不可预测。向量表大小至少为 16 个异常向量(64 字节),加上外部中断后总大小需对齐到 128 字节的整数倍。

1.7 异常优先级与向量表的关系

ARM Cortex-M 使用抢占优先级模型,异常编号越小,优先级越高(复位为 -3,NMI 为 -2,HardFault 为 -1)。向量表本身不存储优先级信息,优先级由系统优先级寄存器(如 SHPR1–SHPR3)和NVIC 优先级寄存器单独配置。向量表只负责提供处理函数的入口地址。

异常优先级与向量表关系 异常优先级与向量表关系 优先级 最高 最低 复位 (-3) NMI (-2) HardFault (-1) SVC (可编程) PendSV (可编程) SysTick (可编程) 中断向量表(存储处理函数入口地址) 优先级由 NVIC 优先级寄存器配置,向量表只提供地址

1.8 本章小结

  • 中断向量表是异常编号到处理函数地址的映射表,由硬件直接使用。
  • 在 ARM Cortex-M 中,向量表默认位于 0x00000000,通过 VTOR 可重定位。
  • 向量表第一项为 MSP 初始值,第二项为 Reset_Handler,这是系统启动的关键。
  • 异常优先级由独立的寄存器控制,与向量表内容无关。
  • 启动文件中的 __Vectors 段是向量表的具体实现,必须保证正确性。