单片机启动过程解析

一、正常程序运行流程

.png
  1. 初始化阶段

    • MSP初始化:上电后处理器从0x8000000地址读取主堆栈指针(MSP)初始值(占据0x8000000~0x8000003)。
    • PC跳转:从0x8000004地址读取复位中断向量值,程序计数器(PC)跳转至该地址。
  2. 复位中断处理

    • 关键操作Reset_Handler依次执行:
      • 初始化系统时钟(SystemInit
      • .data段从Flash复制到RAM
      • 清零.bss
      • 调用__main(完成C库初始化)
  3. 用户程序执行

    • 跳转至main函数执行用户代码。
    • 中断机制:无中断时运行主循环;中断触发时通过中断向量表跳转至对应服务程序,执行后返回断点继续运行。

二、中断向量表机制

  • 地址计算中断向量地址 = 0x8000000 + 4 * (IRQn + 16)
    • 注:之所以可以找到复位中断程序,是因为中断向量表占据的是从0x8000000起始的连续空间,且每个中断占4字节,按固定顺序存放在表中。
    • 注:不同芯片厂商可能采用不同偏移规则(如STM32复位向量位于第2项),需以具体手册为准。
  • 异常处理:复位中断(IRQn=-15)位于向量表第1项,地址为0x8000004

三、加入IAP后的启动流程

IAP.png
  1. BootLoader阶段

    • 上电后执行IAPReset_Handler,跳转至IAPmain函数。
    • 完成固件接收、校验、写入等操作。
  2. 跳转至应用程序

    • 无需复位IAP直接跳转至APP入口(如0x8003000)。
    • 关键操作
      • 重设MSP:从APP起始地址读取新MSP值。
      • 重映射向量表:SCB->VTOR = 0x8003000;
  3. 应用程序执行

    • 执行APPReset_Handler,流程同正常启动。

四、关键注意事项

  1. 向量表重映射

    • GD32F330特性SystemInit()默认设置VTOR,用户需在其后重设:

      1
      2
      SystemInit();          // 库函数可能覆盖VTOR
      SCB->VTOR = APP_ADDR; // 需在SystemInit之后设置
    • 低功耗唤醒:部分芯片唤醒后VTOR复位,需重新配置。

    • 其他芯片:使用任何芯片在设置VTOR前都应先查看是否有其他地方已经设置过了!

  2. 跨厂商差异

    • STM32的复位向量为向量表第2项(地址0x8000004)。
    • 需查阅芯片参考手册确认中断向量偏移规则。
  3. IAP设计要点

    • 跳转前准备:关闭所有中断,清理外设状态。
    • 地址对齐APP起始地址需满足芯片的Flash扇区对齐要求。
    • 示例跳转代码
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      typedef void (*pFunction)(void);
      uint32_t ApplicationAddress = 0x8003000;

      /**
      * @brief 跳转到用户程序执行
      */
      uint8_t Jump_To_User_Program(void)
      {
      __disable_irq();
      if (((*(__IO uint32_t *)ApplicationAddress) & 0x2FFE0000) == 0x20000000)//判断用户是否已经下载程序,防止跑飞
      {
      //跳转至用户代码
      JumpAddress = *(__IO uint32_t *)(ApplicationAddress + 4);
      Jump_To_Application = (pFunction)JumpAddress;
      //初始化用户程序的堆栈指针
      __set_MSP(*(__IO uint32_t *)ApplicationAddress);
      Jump_To_Application();
      }
      else
      {
      return 1;
      }
      return 0;
      }

五、附录:关键段说明

段名作用存储位置
.data存储已初始化的全局变量RAM
.bss存储未初始化的全局变量(启动时清零)RAM
.text存储程序代码和常量Flash
__mainC库初始化(堆栈、静态变量等)自动调用