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

【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


### 如何在 STM32F103 上配置应用程序的中断向量表 对于STM32F103系列微控制器而言,当采用双区Bootloader架构时,正确设置应用(APP)区域的中断向量表至关重要。这不仅影响到系统的稳定性也关系着功能能否正常启动。 #### 中断向量表简介 中断向量表包含了多个入口地址,这些地址指向不同的异常处理函数和服务例程ISR(Interrupt Service Routine),用于响应各种硬件事件如定时器溢出、外部输入变化等。默认情况下,该表格位于闪存起始位置即0x0800_0000处[^1]。 #### 移动中断向量表至自定义位置 为了支持多分区运行模式——比如拥有两个独立的应用程序副本分别驻留在Flash的不同部分以便于在线更新而不影响当前操作——需要重新定位这个重要的数据结构。具体做法如下: - **调整链接脚本**:确保应用程序被编译并放置在一个特定区域内;例如,如果希望App从0x0800_4000开始,则应在项目构建工具链中指定相应基址。 - **修改启动汇编代码(start.s)**:更改堆栈指针初始值的同时也要告知CPU新的向量表所在之处。通过编写一段简单的ARM指令来完成这项工作,在进入C环境之前执行它即可生效。 下面是一份简化版的例子展示如何实现上述逻辑: ```assembly .syntax unified .cpu cortex-m3 .thumb /* 定义重定向后的向量表偏移 */ #define VECT_TAB_OFFSET 0x4000 /* 设置NVIC->VTOR寄存器以改变向量表的位置 */ __attribute__((section(".after_vectors"))) void SetVectorTableOffset(void){ SCB->VTOR = FLASH_BASE | (VECT_TAB_OFFSET & 0x1FFFFF); } ``` 此段代码片段应当嵌入到`start.s`文件内,并且保证其作为最早被执行的一批命令之一。这里利用了CMSIS库提供的宏定义以及SCB(System Control Block)系统级外设的相关特性来动态设定中断向量表的新起点。 另外值得注意的是,在某些应用场景下可能还需要考虑保护机制防止意外覆盖合法代码区间内的关键信息。因此建议开发者仔细阅读官方文档了解更详尽的安全措施指南[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值