完整流程

  1. 上电或复位: 芯片通电或RESET引脚被拉低。

  2. 读取BOOT引脚: 硬件逻辑在复位信号的上升沿锁存 BOOT0 和 BOOT1 引脚的电平状态。

  3. 执行内存重映射(M3/M4才重映射,M7没有重映射):

    • 如果 BOOT0=0,内部总线矩阵将主闪存(0x08000000)的地址重映射到 0x00000000。
    • 如果 BOOT0=1, BOOT1=0,将系统存储器(0x1FFFF000)重映射到 0x00000000。
    • 如果 BOOT0=1, BOOT1=1,将SRAM(0x20000000)重映射到 0x00000000。
  4. CPU开始执行
    CPU的PC指针指向 0x00000000,开始它的生命周期。它首先从 0x00000000 读取栈顶指针(MSP)的初始值,并加载到SP寄存器。然后从 0x00000004 读取复位处理函数(Reset_Handler)的地址,并加载到PC寄存器。

    这段描述适用全部模式:Flash、System Memory、SRAM

  5. 运行软件程序

    • 主闪存模式:CPU开始执行Reset_Handler,在回调函数中分别执行SystemInit和__main,最后执行main()函数。
    • 系统存储器模式:CPU开始执行ST官方的ISP Bootloader中的Reset Handler,在回调函数中做初始化处理后,官方的ISP程序运行,等待通过串口等接收新固件(执行bootloader)。
    • SRAM模式:CPU开始执行0x00000004指向的函数地址下的程序(若用户有将程序拷贝或者是通过写SRAM的方式编写程序,则可正常运行;若SRAM为空,则CPU会触发硬件错误(HardFault)。

流程解析

MCU触发了复位事件后,芯片内部的硬件逻辑会检测BOOT0和BOOT1引脚是高电平还是低电平,根据两个BOOT脚的高低电平组合,将不同的物理存储器的起始地址重映射到0x00000000这个地址上。

紧接着CPU会从0x00000000执行程序,CPU会先将PC指针指向0x00000000,将该地址存放的栈顶指针MSP的初始值取出并加载到CPU寄存器SP中,然后偏移4个字节,将0x00000004地址下存放的复位处理函数Reset_Handler地址取出并加载到CPU寄存器PC中。

然后CPU就开始执行Reset_Handler函数下的程序,在几种模式下,主要是主闪存模式(即BOOT0为0的模式),CPU开始执行程序Reset_Handler(虚函数),默认为执行system_stm32f10x.c文件下的SystemInit()函数,这个函数主要负责最基本的硬件初始化,如配置系统时钟。

紧接着执行C库入口函数__main,在该函数下会建立一个符合C语言标准的程序执行环境,包括:分散加载初始化、复制.data段、清零.bss段、C/C++库初始化、堆初始化、IO初始化、FPU初始化、调用C++静态构造函数。处理完这些就会调用用户编写的main()函数了。

__main()的具体工作

步骤 任务 目标 涉及内存区域
1 分散加载初始化 建立正确的内存数据映像 .data, .bss (SRAM)
1.1 复制.data段 将Flash中的初始值赋给SRAM中的全局/静态变量 .data
1.2 清零.bss段 确保未初始化的全局/静态变量为0 .bss
2 C/C++库初始化 使标准库函数可用 Heap, Stack (SRAM)
2.1 初始化堆 为malloc()等动态内存分配做准备 Heap
2.2 初始化I/O 为printf()等函数准备底层接口 -
2.3 初始化FPU 使能浮点运算单元(如果需要) -
2.4 调用C++静态构造函数 正确构造全局C++对象 -
3 调用main() 将控制权移交给用户代码 Stack
4 处理main()返回 提供一个确定的程序终止行为 -