为什么需要向量表重映射?
STM32的向量表(Vector Table)默认位于Flash起始地址(如0x08000000),存放着复位、中断服务函数(ISR)的入口地址。当Bootloader跳转到App时,App的代码通常位于偏移地址(如0x08010000)。若向量表仍指向Bootloader区域,中断触发时CPU会从错误地址取指,导致程序崩溃。因此,跳转前必须将向量表重映射到App的起始地址。
向量表重映射的两种方式
1. 修改VTOR寄存器(Cortex-M3/M4/M7)
对于Cortex-M3及以上内核(如STM32F1/F2/F3/F4/F7/H7),可通过设置系统控制块中的VTOR(Vector Table Offset Register)寄存器实现重映射。
#define APP_ADDRESS 0x08010000
void jump_to_app(void)
{
// 设置向量表偏移
SCB->VTOR = APP_ADDRESS;
// 后续跳转代码...
}
2. 使用SYSCFG_MEMRMP寄存器(Cortex-M0/M0+)
对于Cortex-M0/M0+内核(如STM32F0/L0),没有VTOR寄存器,需通过SYSCFG配置内存映射,将Flash的起始地址重映射到App区域。
void jump_to_app(void)
{
// 使能SYSCFG时钟
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
// 重映射Flash到0x08010000
SYSCFG->CFGR1 |= SYSCFG_CFGR1_MEM_MODE_0; // 根据实际芯片调整
}
跳转前的关键步骤
1. 关闭全局中断
跳转过程中,任何中断都可能导致不可预知行为。必须确保所有中断关闭,并清除挂起标志。
__disable_irq();
// 关闭所有外设中断(示例:关闭SysTick)
SysTick->CTRL = 0;
2. 设置主栈指针(MSP)
App的起始地址前4字节存放初始栈顶地址,需将其加载到MSP。
typedef void (*pFunction)(void);
uint32_t app_stack = *(volatile uint32_t*)APP_ADDRESS;
__set_MSP(app_stack);
3. 获取App复位向量并跳转
App起始地址后4字节为复位向量,即App的入口函数地址。
pFunction app_entry = (pFunction)(*(volatile uint32_t*)(APP_ADDRESS + 4));
app_entry();
4. 完整跳转函数示例
#define APP_ADDRESS 0x08010000
void jump_to_app(void)
{
// 1. 关闭全局中断
__disable_irq();
// 2. 关闭SysTick
SysTick->CTRL = 0;
// 3. 设置向量表偏移(Cortex-M3/M4)
SCB->VTOR = APP_ADDRESS;
// 4. 设置主栈指针
uint32_t app_stack = *(volatile uint32_t*)APP_ADDRESS;
__set_MSP(app_stack);
// 5. 跳转
pFunction app_entry = (pFunction)(*(volatile uint32_t*)(APP_ADDRESS + 4));
app_entry();
// 6. 不应返回
while(1);
}
App端的配合设置
1. 链接脚本修改
App工程需将Flash起始地址和中断向量表偏移到APP_ADDRESS。以GCC为例:
/* Linker script */
FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 128K
2. 启动文件中的向量表重映射
在App的SystemInit函数或启动文件中,需再次设置VTOR:
void SystemInit(void)
{
SCB->VTOR = 0x08010000;
// 其他初始化...
}
3. 中断服务函数注意
App中所有中断服务函数必须正确声明,且向量表偏移已生效,否则中断无法响应。
常见问题与调试技巧
- 跳转后死机:检查栈指针是否正确,确认App的链接脚本偏移无误。
- 中断不工作:确认VTOR设置成功,且App的SystemInit已执行。
- 时钟配置冲突:Bootloader和App可能使用不同时钟,跳转前无需重置时钟,但App应重新初始化所有外设。
- 使用调试器:在跳转函数处设置断点,单步执行,观察寄存器值。
- 检查Flash写入:确保App已正确烧录到目标地址,可通过读取内存验证。
总结
向量表重映射是Bootloader跳转的核心,理解其原理可避免诸多隐患。本文通过代码示例演示了Cortex-M3/M4的VTOR方法,并提及M0的替代方案。实际开发中,还需结合具体芯片手册,确保配置正确。掌握此技术,可为IAP(在应用编程)打下坚实基础。