4. 中断向量表重定向
任务目标
在Bootloader与应用程序分层架构中,应用程序链接地址通常与Bootloader不同。当应用程序启动后,CPU仍默认从Bootloader所在地址读取中断向量表,导致应用程序的中断(如SysTick、UART等)无法正确响应。本案例实现应用程序启动时将中断向量表重定向至自身起始地址,确保中断正常触发。
核心原理
Cortex-M内核通过SCB->VTOR寄存器(地址0xE000ED08)定位中断向量表。重定向只需将VTOR设置为应用程序向量表所在地址,并满足地址按0x200(512字节)对齐要求。向量表首字为初始栈指针(MSP),第二个字为复位向量,应用程序链接脚本需保证向量表位于其Flash起始地址。
实现代码
/* app_main.c — 应用程序中断向量表重定向示例 */
#include "stm32f4xx.h"
/* 应用程序向量表起始地址(由链接脚本定义,此处以0x08010000为例) */
#define APP_VECTOR_TABLE_ADDR 0x08010000UL
/* 应用程序入口函数(由启动文件调用) */
void app_entry(void)
{
/* 1. 检查当前是否已运行在目标向量表地址 */
if (SCB->VTOR != APP_VECTOR_TABLE_ADDR)
{
/* 2. 关闭全局中断,防止重定向过程中断响应错乱 */
__disable_irq();
/* 3. 设置VTOR寄存器,完成向量表重定向 */
SCB->VTOR = APP_VECTOR_TABLE_ADDR;
/* 4. 数据同步屏障,确保写操作完成 */
__DSB();
/* 5. 重新使能全局中断 */
__enable_irq();
}
/* 6. 验证重定向是否成功(可选,用于调试断言) */
if (SCB->VTOR != APP_VECTOR_TABLE_ADDR)
{
/* 重定向失败,进入错误处理(实际工程可替换为断言或LED指示) */
while (1);
}
/* 7. 应用程序主逻辑(此处仅演示中断响应) */
SysTick_Config(SystemCoreClock / 1000); /* 1ms SysTick中断 */
while (1)
{
/* 主循环 */
}
}
/* SysTick中断服务函数 — 验证重定向后中断是否正常响应 */
void SysTick_Handler(void)
{
static uint32_t tick_count = 0;
tick_count++;
/* 实际工程中可在此翻转LED或发送调试信息 */
}
链接脚本关键配置
应用程序的链接脚本必须将FLASH起始地址设置为0x08010000(与APP_VECTOR_TABLE_ADDR一致),并确保向量表位于该地址首部。以GCC LD脚本为例:
/* app.ld — 应用程序链接脚本关键段 */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 240K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* 向量表必须放在起始地址 */
. = ALIGN(4);
} >FLASH
/* 其余段省略 */
}
编译与烧录
- 将应用程序编译链接到
0x08010000起始地址,生成app.bin。 - 通过Bootloader或烧录器将
app.bin写入Flash地址0x08010000。 - 复位芯片,Bootloader运行后跳转到
0x08010000执行app_entry。
验证方法
- 静态验证:在调试器中设置断点于
SCB->VTOR = APP_VECTOR_TABLE_ADDR执行后,查看VTOR寄存器值是否为0x08010000。 - 动态验证:在
SysTick_Handler中设置断点,若程序能周期性进入该中断,说明向量表重定向成功且中断正常响应。 - 失败判据:若未执行重定向,SysTick中断将无法触发(因为CPU仍从Bootloader向量表取中断入口),程序会卡死在启动文件默认Handler中。
常见问题
- 对齐错误:若向量表地址未按
0x200对齐,VTOR写入无效,需检查链接脚本中FLASH ORIGIN是否满足对齐。 - 跳转前未重定向:Bootloader跳转到应用程序前,若应用程序入口代码未执行VTOR设置,则中断仍指向Bootloader区域,需确保
app_entry在使能任何中断前完成重定向。 - RAM中运行:若应用程序在RAM中调试运行,VTOR需设置为RAM中向量表地址,且需将向量表从Flash复制到RAM起始位置。