中断向量表不必强制放在flash物理起始地址,只需确保其实际存放地址与scb->vtor设置值一致且128字节对齐;链接脚本需显式指定.isr_vector段位置并keep保护,vtor必须在禁用中断后、main前设置,且地址末7位为0。

中断向量表必须放在 Flash 起始物理偏移?先别急着硬塞
不是所有场景都要求向量表“绝对”放在 Flash 物理起始地址(比如 0x08000000)。Cortex-M 系列芯片上电复位时,硬件确实会从 0x00000004(或映射后的 0x08000004)取复位向量,但这个行为依赖于启动时的地址映射状态(如 BOOT0/BOOT1 引脚配置、SYSCFG_MEMRMP 寄存器设置)。如果你的固件是作为 App 运行在 Bootloader 之后(例如起始地址为 0x08010000),那它**绝不能**把向量表硬塞进 0x08000000 —— 那里是 Bootloader 的地盘,写进去会覆盖甚至破坏引导逻辑。
真正要确保的,是:向量表在 Flash 中的存放位置,与你在运行时通过 SCB->VTOR 设置的地址完全一致,且该地址满足对齐要求(128 字节边界,即低 7 位为 0)。
链接脚本里用 .isr_vector 段 + ORIGIN 控制物理位置
向量表不是靠“手动画内存图”或“烧录时手动挪地址”来定位的,而是由链接脚本(ld script)决定其最终落点。关键不是“让它出现在 0x08000000”,而是“让它出现在你指定的、App 实际起始的地址”。
典型做法是在链接脚本中定义一个独立段,并显式指定其地址:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 512K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.isr_vector :
{
. = ALIGN(128);
KEEP(*(.isr_vector))
. = ALIGN(128);
} > FLASH
这段配置确保了三件事:
-
.isr_vector段强制对齐到 128 字节边界(满足VTOR要求) - 整个段被放置在
FLASH内存区域,而该区域起始就是0x08010000 -
KEEP防止链接器优化掉向量表(尤其在启用--gc-sections时)
如果你在 C 代码里声明了:
extern const uint32_t __isr_vector_start[];
// 或更常见的是用 section 属性:
__attribute__((section(".isr_vector"))) const uint32_t VectorTable[] = { ... };
那么它就会被链接进 .isr_vector 段,最终落在 0x08010000 开头的位置 —— 不是靠猜,是靠链接脚本算出来的。
SCB->VTOR 必须在跳转后、main 之前立即设置
即使向量表已正确烧录到 0x08010000,若不改 VTOR,CPU 仍会去默认地址查表,结果就是跑飞或执行 Bootloader 的 ISR。
设置时机非常关键:必须在禁用全局中断后、初始化任何外设前、且在调用 main() 之前完成。常见错误是把它放在 main() 里太靠后,或者漏掉 __disable_irq()。
推荐写法(放在 Reset_Handler 尾部或自定义入口函数中):
__disable_irq(); SCB->VTOR = 0x08010000UL; // 必须和链接脚本中 .isr_vector 起始地址完全一致 __enable_irq();
注意:SCB->VTOR 写入的是**绝对地址**,不是偏移量;且该地址末 7 位必须为 0(0x08010000 & 0x7F == 0),否则写入无效。
验证向量表是否真在目标地址?别只信烧录日志
烧录工具显示“成功写入 0x08010000”不代表向量表就在那儿 —— 可能是整个 bin 文件偏移加载,也可能是链接脚本没生效,还可能是编译器把 .isr_vector 放进了别的段。
最可靠的方法是反汇编或 dump 出烧录后的 Flash 数据:
- 用
arm-none-eabi-objdump -d your_app.elf查看.isr_vector段实际 VMA(Virtual Memory Address) - 用
arm-none-eabi-readelf -S your_app.elf确认.isr_vector的Addr字段是否等于你期望的起始地址 - 用调试器连接 MCU,直接读
0x08010000开始的 64 字(256 字节),核对前几个值:栈顶地址是否在合理 RAM 范围(如0x2000xxxx),复位 handler 地址是否指向 Flash 区域内有效位置
最容易被忽略的一点:如果用了 C++,全局对象构造函数可能在 main() 前执行,而这些构造函数若依赖中断(比如串口 log 初始化),就会在 VTOR 设置前触发中断 —— 此时系统必然崩溃。所以,**所有中断相关初始化必须严格安排在 VTOR 设置之后**。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











