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
    // 若此函数被正确调用,说明中断向量表重定位成功
}

工程配置要点

  1. 链接脚本(.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
}
  1. 编译选项:若使用STM32CubeIDE或Keil,需在工程设置中定义VECT_TAB_OFFSET宏(部分标准库依赖此宏自动设置VTOR),但本案例直接操作寄存器,不依赖该宏。

运行与验证方法

前提条件:需先烧录一个Bootloader程序到0x08000000(该Bootloader负责跳转到0x08008000执行应用程序)。若暂无Bootloader,可临时将应用程序直接烧录到0x08000000并注释掉VTOR设置行,用于对比验证。

验证步骤:

  1. 将应用程序编译后烧录到0x08008000地址(通过Bootloader跳转或调试器直接烧录)。
  2. 在SCB->VTOR = APPLICATION_ADDRESS;处设置断点,单步执行后查看VTOR寄存器值是否为0x08008000。
  3. 在SysTick_Handler中设置断点,若程序能进入该中断服务函数,说明中断向量表重定位成功。
  4. 观察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设置。