文章目录
-
-
- [ARM Cortex-M 向量表详解](#ARM Cortex-M 向量表详解)
-
- 一、什么是向量表?
- 二、向量表的结构与核心内容
- 三、关键概念深入解析
-
- [1. `__initial_sp`(初始栈指针)详解](#1.
__initial_sp(初始栈指针)详解) - [2. 向量表偏移寄存器 (VTOR)](#2. 向量表偏移寄存器 (VTOR))
- [3. 中断优先级 (NVIC) 与向量表的关系](#3. 中断优先级 (NVIC) 与向量表的关系)
- [1. `__initial_sp`(初始栈指针)详解](#1.
- 四、总结要点
-
ARM Cortex-M 向量表详解
一、什么是向量表?
向量表是一个存储在代码存储器(通常是 Flash)起始区域的字对齐数组。其中的每一个字(32位数据)都代表一个特定的地址,称为"向量"。
当处理器发生异常(如复位、中断、系统调用)时,内核硬件会自动查询这个表,并根据异常类型跳转到对应的地址执行程序。这是 Cortex-M 处理器处理异常和启动的基石。
二、向量表的结构与核心内容
下表列出了 Cortex-M 向量表的标准布局。其起始地址默认为 0x00000000,但可通过 VTOR(向量表偏移寄存器)重定位。
| 地址偏移量 | 向量名称 | 简要说明 | 重要性/备注 |
|---|---|---|---|
0x00000000 |
初始主栈指针 (MSP) | 硬件加载到主栈指针寄存器的初始值。 | 至关重要。决定了程序启动后栈的起始位置(通常指向内部 RAM 顶端)。 |
0x00000004 |
复位向量 (Reset_Handler) | 程序执行的入口点。芯片复位后,PC 指针被设置为此地址。 | 至关重要 。包含 main() 函数调用的起点,负责初始化 C 运行时环境。 |
0x00000008 |
非屏蔽中断 (NMI_Handler) | 不可被屏蔽的中断处理函数地址。 | 高优先级异常,用于处理严重硬件故障。 |
0x0000000C |
硬错误 (HardFault_Handler) | 所有严重错误的默认处理函数。 | 重要。用于调试,如内存访问违规、非法指令等。 |
0x00000010 |
内存管理错误 (MemManage_Handler) | MPU 访问违规触发的异常(Cortex-M3/4/7 等)。 | 可选,但启用 MPU 后非常重要。 |
0x00000014 |
总线错误 (BusFault_Handler) | 总线访问错误(如访问不存在的地址)。 | 可选,用于高级错误诊断。 |
0x00000018 |
用法错误 (UsageFault_Handler) | 未定义指令或非法状态等错误。 | 可选,用于高级错误诊断。 |
0x0000001C |
保留 | ||
0x00000020 |
保留 | ||
0x00000024 |
保留 | ||
0x00000028 |
SVCall 异常 (SVC_Handler) | 由 SVC 指令触发的系统调用。 |
重要。用于实现操作系统(如 FreeRTOS)的系统 API。 |
0x0000002C |
调试监控 (DebugMon_Handler) | 调试监控异常。 | 主要用于调试器。 |
0x00000030 |
保留 | ||
0x00000034 |
PendSV 异常 (PendSV_Handler) | 可挂起的系统服务中断。 | 极其重要。常用于操作系统(如 FreeRTOS)的上下文切换。 |
0x00000038 |
SysTick 异常 (SysTick_Handler) | 系统定时器中断。 | 极其重要。为操作系统提供心跳时钟,也可用于裸机程序延时。 |
0x0000003C 及以后 |
外设中断 (IRQ Handlers) | 如 EXTI0_IRQHandler, TIM2_IRQHandler, USART1_IRQHandler 等。 |
重要。数量由芯片型号决定,是用户处理外部事件的关键。 |
三、关键概念深入解析
1. __initial_sp(初始栈指针)详解
-
值从哪里来?
__initial_sp的值由链接器(如 ARM GCC 的链接脚本*.ld文件)计算得出,通常被设置为内部 RAM 的末地址+1 。例如,如果 RAM 地址范围是0x20000000~0x20007FFF(32KB),则__initial_sp通常为0x20008000。 -
存储在哪里?
链接器会将计算好的
__initial_sp值放置在最终程序映像的最开头 ,即物理地址0x08000000(Flash 起始地址)。 -
处理器如何读取?
- Cortex-M 处理器硬件设计为:上电或复位后,首先从逻辑地址
0x00000000读取第一个字作为 MSP 初始值,从逻辑地址0x00000004读取第二个字作为复位向量。 - 在 STM32 等芯片中,通过启动模式配置 (如 BOOT 引脚),逻辑地址
0x00000000在启动阶段会被重映射 到某个物理存储器(如主 Flash0x08000000、系统存储器或 SRAM)。 - 结论 :
__initial_sp的值存储在 Flash 的0x08000000处,但处理器在启动时通过地址重映射,从0x00000000这个"窗口"读取到它。
- Cortex-M 处理器硬件设计为:上电或复位后,首先从逻辑地址
2. 向量表偏移寄存器 (VTOR)
- 作用 :允许软件将向量表从默认的地址(如
0x00000000)重定位到 RAM 或其他 Flash 区域。 - 应用场景 :
- Bootloader 程序 :Bootloader 位于
0x08000000,其向量表也在此。当跳转到用户应用程序(如位于0x08010000)时,需要先将 VTOR 设置为0x08010000,以便中断能正确跳转到用户程序的中断服务函数。 - 动态修改中断函数:将向量表复制到 RAM 中,并修改 VTOR 指向 RAM。这样可以在运行时动态更改某个中断的服务函数,实现灵活的插件机制。
- Bootloader 程序 :Bootloader 位于
3. 中断优先级 (NVIC) 与向量表的关系
- 关系 :向量表存储的是中断服务函数(ISR)的地址 ,而 NVIC 管理的是这些中断的优先级和使能状态。
- 在 STM32CubeMX 工程中的体现 :
-
向量表内容 :在
Startup/startup_stm32fxxxx.s汇编文件中定义。例如:cg_pfnVectors: .word _estack /* 0x00000000: __initial_sp */ .word Reset_Handler /* 0x00000004: Reset Vector */ .word NMI_Handler /* 0x00000008: NMI */ .word HardFault_Handler /* 0x0000000C: Hard Fault */ // ... 其他向量 .word TIM2_IRQHandler /* 某个外设中断向量 */ -
NVIC 配置(优先级和使能) :
- 优先级设置 :在
main.c的MX_NVIC_Init()函数中,通过HAL_NVIC_SetPriority(IRQn, preemptPriority, subPriority)为每个中断源设置优先级。 - 中断使能 :在
stm32fxxxx_hal_msp.c的各外设MspInit函数中,通过HAL_NVIC_EnableIRQ(IRQn)使能中断。
- 优先级设置 :在
-
四、总结要点
- 向量表是地址表:它存的是函数指针,不是代码本身。
- 前两个向量是硬性要求 :
MSP初始值和复位向量是芯片能正常启动的绝对必要条件。 - 地址是逻辑映射的 :
0x00000000是硬件的"入口",其背后映射的物理存储器由芯片的启动配置决定。 - 向量表是可移动的:通过 VTOR 寄存器,可以灵活地将向量表放置在需要的位置,这是高级应用(如 Bootloader、OS)的基础。
- 向量表与 NVIC 分工明确:向量表负责"去哪儿执行"(地址),NVIC 负责"何时执行"以及"谁先执行"(优先级和使能)。