STM32 中断向量表的位置 、重定向

本文详细解析了STM32的中断向量表及其工作原理,包括中断向量表的布局、如何通过硬件配置指向正确的中断入口地址,以及中断发生时CPU是如何定位并跳转到相应中断处理函数的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【lanmanck原创】

这篇文章已经说了STM32的启动过程:

http://blog.youkuaiyun.com/lanmanck/article/details/8252560

我们也知道怎么跳到main函数了,那么,中断发生后,又是怎么跑到中断入口地址的呢?

从stm32f10x.s可以看到,已经定义好了一大堆的中断响应函数,这就是中断向量表,标号__Vectors,表示中断向量表入口地址,例如:

AREA    RESET, DATA, READONLY ; 定义只读数据段,实际上是在CODE区(假设STM32从FLASH启动,则此中断向量表起始地址即为0x8000000)
                EXPORT  __Vectors
IMPORT OS_CPU_SysTickHandler
       IMPORT OS_CPU_PendSVHandler

__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler             ; Reset Handler
                DCD     NMI_Handler               ; NMI Handler
                DCD     HardFault_Handler         ; Hard Fault Handler
                DCD     MemManage_Handler         ; MPU Fault Handler
                DCD     BusFault_Handler          ; Bus Fault Handler
                DCD     UsageFault_Handler        ; Usage Fault Handler

这个向量表的编写是有讲究的,跟硬件一一对应不能乱写的,CPU找入口地址就靠它了,bin文件开头就是他们的地址,参考手册RM0008的10.1.2节可以看到排列。

我们再结合CORTEX-M3的特性,他上电后根据boot引脚来决定PC位置,比如boot设置为flash启动,则启动后PC跳到0x08000000。此时CPU会先取2个地址,第一个是栈顶地址,第二个是复位异常地址,故有了上面的写法,这样就跳到reset_handler。

那么这个reset_handler的实际地址是多少.?下面的一堆例如Nmi_handler地址又是多少呢?发生中断是怎么跑到这个地址的呢?下面挨个讲解。

1、我们可以通过反向来得知这些入口地址,查看工程下的map文件就可以看到了,这个地址跟keil里面设置的target->flash起始地址息息相关,实际上我们不太需要关心,让编译器分配,中断向量表放的就是他们的地址。

2、对比ARM7/ARM9内核,Cortex-M3内核则是固定了中断向量表的位置而起始地址是可变化的。

3、进到C语言后会先配置NVIC,NVIC_SetVectorTable()里面可以配置中断向量表的起始地址和偏移,主要是告诉CPU该向量表是位于Flash还是Ram,偏移是多少。例如设置为位于Flash内,偏移就是烧入的程序地址,可在Keil target中设置。这样CPU就知道入口地址了。

4、发生中断后,CPU找到中断向量表地址,然后根据偏移(对号入座)再找到中断地址,这样就跳过去了。

我们截一个图说明一下,map文件:


对应的bin文件,看是不是放的上面地址:


显然,200039c0就是栈顶地址,而08006F21就是reset_handler地址!


如何定位?以放到0x20000000为例

1、keil设置ram起始为0x20000100,我们在0x20000000~0x20000100放中断向量表,其他给程序用

2、设置NVIC_SetVectorTable(NVIC_VectTab_FLASH,0);

3、跳到C时把中断向量表拷贝到0x20000000


### STM32启动文件中与中断向量表相关的配置 #### 中断向量表概述 STM32中断向量表是一个存储区域,用于定义各种异常和中断处理程序的位置。该表位于闪存或 SRAM 的起始地址处,并通过硬件加载到 CPU 的 NVIC(嵌套向量中断控制器)。当发生中断或异常时,CPU 将从向量表中获取对应的服务例程入口地址并跳转执行。 在 STM32 启动过程中,无论哪种启动模式,设备始终从 `0x0000 0000` 地址开始运行[^1]。此地址通常是 Flash 存储器的起点,在某些情况下也可以重新定位至其他内存区域(如 SRAM)。 --- #### 初始化过程解析 初始化中断向量表的过程通常由启动文件完成。以下是具体实现细节: 1. **向量表结构** 在启动文件中,会定义一个名为 `__Vectors` 的段,表示中断向量表的内容。例如: ```c __Vectors: .word _estack /* 堆栈指针初始值 */ .word Reset_Handler /* 复位中断服务程序 */ ... .word NMI_Handler /* 非屏蔽中断 (NMI) */ .word HardFault_Handler /* 硬件错误中断 */ ... ``` 这些条目依次列出了复位、系统异常以及外设中断的入口地址[^2]。 2. **链接脚本的作用** 链接脚本负责将上述向量表放置于指定的内存位置。例如: ```ld MEMORY { FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K } SECTIONS { .isr_vector : { KEEP(*(.isr_vector)) } >FLASH } ``` 此部分确保了中断向量表被正确映射到 Flash 起始地址 `0x08000000` 或者可以动态调整到 SRAM 地址范围内的某个偏移位置。 3. **SystemInit 函数的功能扩展** SystemInit 是一个重要的初始化函数,一般位于 `system_stm32fxxx.c` 文件中。它的职责之一就是设置中断向量表的具体基地址。如果需要更改默认的向量表位置,则可以通过修改 SCB->VTOR 寄存器来实现。例如: ```c SCB->VTOR = VectorTableAddress; // 设置新的向量表地址 ``` 默认情况下,SCB->VTOR 指向的是 Flash 的首地址;但在调试阶段或者特殊应用场合下可能将其改写为 SRAM 地址以便支持自定义功能需求[^3]。 4. **复位流程中的角色扮演** 当 MCU 上电或手动触发 RESET 键后,PC 寄存器会被赋予指向复位矢量的第一个字节的数据作为第一条要被执行命令所在之处——即 Reset_Handler 所代表的地方[^5]。随后按照既定逻辑逐步调用必要的子模块直至进入用户编写的 Main 循环体之前完成了全部前期准备工作。 --- #### 动态重定向技术探讨 除了固定不变的标准布局之外,还有机会利用软件手段灵活改变当前使用的实际表格版本号。这允许开发者在同一项目里根据不同场景切换不同的响应策略而无需反复烧录固件代码本身即可达成目的。操作步骤如下所示: - 修改 VTOR 寄存器以更新活动状态下的有效目标列表; - 刷新缓存机制以防旧数据残留干扰新设定生效; - 测试验证改动后的行为表现是否符合预期效果。 这种灵活性特别适用于多任务操作系统环境或者是那些频繁涉及实时性能优化工作的复杂工程项目之中。 --- ### 示例代码展示 下面给出一段简单的演示如何编程控制 STM32 更换正在运用当中所依赖的那个特定实例化形式的例子: ```c // 定义一个新的向量表放在SRAM中 void NewVectorTable(void){ uint32_t *new_table; new_table = (uint32_t *)0x20000000; // 新建堆栈顶部地址 *(new_table++) = ((uint32_t)&_estack); // 添加各个中断处理器... *(new_table++) = (uint32_t)Reset_Handler; *(new_table++) = (uint32_t)NMI_Handler; *(new_table++) = (uint32_t)HardFault_Handler; ... // 更新VTOR寄存器指向这个新的向量表 SCB->VTOR = 0x20000000; } ``` 以上片段展示了怎样构建另一个可供选择采用的形式并且激活它成为即时可用选项的方法论思路。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值