2. Bootloader与App双区Flash布局设计
任务目标
在STM32 IAP架构中,Bootloader将应用程序烧录到Flash的偏移地址(如0x08008000)后,CPU复位仍从0x08000000取向量表。若应用程序不进行向量表重定位,所有中断(如SysTick、UART、EXTI)将错误地跳转到Bootloader的向量表,导致中断无法响应。本案例目标是在应用程序启动早期设置正确的向量表偏移(VTOR),使中断能够从应用程序自身的向量表中正确取址。
核心原理
Cortex-M3/M4内核通过向量表偏移寄存器(VTOR,地址0xE000ED08)决定中断向量表的基地址。设置方法为:SCB->VTOR = APPLICATION_ADDRESS。该操作必须在任何中断使能之前完成,通常放在main()函数的第一行或系统初始化函数中。
完整实现代码
// 文件:main.c(应用程序工程)
#include "stm32f1xx.h" // 以STM32F103为例,其他系列头文件类似
// 应用程序在Flash中的起始地址(需与Bootloader约定的偏移一致)
#define APPLICATION_ADDRESS 0x08008000u
// 简单延时函数(用于演示LED闪烁)
static void delay(volatile uint32_t count) {
while (count--) {
__NOP();
}
}
int main(void) {
// ========== 关键步骤1:向量表重定位 ==========
// 必须在使能任何中断之前执行
SCB->VTOR = APPLICATION_ADDRESS;
// ========== 关键步骤2:验证重定位是否生效 ==========
// 读取VTOR寄存器值,若等于APPLICATION_ADDRESS则设置成功
uint32_t vtor_value = SCB->VTOR;
// ========== 外设初始化(演示中断响应) ==========
// 使能GPIOB时钟(板载LED通常接在PB0或PC13,此处以PB0为例)
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
GPIOB->CRL = (GPIOB->CRL & ~0x0F) | 0x03; // PB0推挽输出50MHz
// 配置SysTick定时器:1ms中断(假设系统时钟72MHz)
SysTick_Config(SystemCoreClock / 1000);
// 主循环:LED闪烁,若中断正常则延时准确
while (1) {
GPIOB->ODR ^= (1 << 0); // 翻转PB0
delay(500000); // 粗略延时(若SysTick中断正常,此延时不影响主循环节奏)
}
}
// SysTick中断服务函数(必须位于应用程序的向量表中)
void SysTick_Handler(void) {
static uint32_t tick = 0;
tick++;
// 此处可添加周期任务,例如每1000ms翻转一次LED
// 若此函数被正确调用,说明中断向量表重定位成功
}
工程配置要点
- 链接脚本(.ld或.sct):必须将应用程序的
FLASH起始地址改为0x08008000,且VECTOR_TABLE_OFFSET同步修改。以GCC链接脚本为例:
/* STM32F103C8T6 应用程序链接脚本片段 */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08008000, LENGTH = 120K /* 偏移32KB,保留64KB给Bootloader */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
}
- 编译选项:若使用STM32CubeIDE或Keil,需在工程设置中定义
VECT_TAB_OFFSET宏(部分标准库依赖此宏自动设置VTOR),但本案例直接操作寄存器,不依赖该宏。
运行与验证方法
前提条件:需先烧录一个Bootloader程序到0x08000000(该Bootloader负责跳转到0x08008000执行应用程序)。若暂无Bootloader,可临时将应用程序直接烧录到0x08000000并注释掉VTOR设置行,用于对比验证。
验证步骤:
- 将应用程序编译后烧录到0x08008000地址(通过Bootloader跳转或调试器直接烧录)。
- 在
SCB->VTOR = APPLICATION_ADDRESS;处设置断点,单步执行后查看VTOR寄存器值是否为0x08008000。 - 在
SysTick_Handler中设置断点,若程序能进入该中断服务函数,说明中断向量表重定位成功。 - 观察LED闪烁频率:若闪烁正常(约1Hz),说明SysTick中断正常触发;若LED常亮或闪烁极快/极慢,则中断未正确响应。
通过判定标准:
- VTOR寄存器值等于
0x08008000; - 程序能进入
SysTick_Handler中断服务函数; - LED以预期频率闪烁(证明SysTick中断周期准确)。
常见问题排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 程序跑飞/硬件错误 | VTOR设置前已有中断使能 | 确保VTOR设置在系统初始化最早期,且关闭所有中断 |
| 中断不响应 | 链接脚本Flash起始地址未修改 | 检查.ld或.sct中FLASH的ORIGIN是否为0x08008000 |
| 烧录后无现象 | Bootloader未正确跳转 | 确认Bootloader跳转地址与APPLICATION_ADDRESS一致 |
关键提示:向量表重定位是IAP应用的基础,若此步骤遗漏,所有中断功能(通信、定时、外部触发)均会异常。本案例以SysTick中断作为验证载体,实际项目中应在系统初始化函数(如
SystemInit())中尽早完成VTOR设置。