引子:
对于ARMv7-M系列SOC来说,上电后程序复位执行的过程相对来说比较简单,因为绝大部分芯片,都是XIP(eXecute In Place,就地执行)模式执行程序,不需要通过BooROM->PL(preloader)->SBL(second bootloader)->Kernel这样的复杂加载过程。XIP的程序复位执行的总体流程如下图(以STM32F407为例):

阶段1:硬件自动初始化
1. SOC上电或复位
-
当STM32F407上电或接收到复位信号时,芯片开始启动过程
-
内部电压调节器、时钟系统开始工作
2. CPU读取地址 0x0000_0000
-
ARM Cortex-M4内核从内存映射的0x0000_0000地址读取第一个值
-
在STM32F407中,这个地址映射到Flash存储器起始位置(0x0800_0000)
-
读取的值被加载到主堆栈指针(MSP)中
3. 加载值到MSP
-
读取的32位值作为初始堆栈指针值
-
堆栈通常设置在RAM的起始位置加上栈大小(如0x2000_0000 + RAM大小)
4. CPU读取地址 0x0000_0004
-
CPU继续读取下一个32位地址(0x0000_0004)
-
这个地址包含复位向量的值
5. 加载值到PC(复位向量)
-
从0x0000_0004读取的值被加载到程序计数器(PC)
-
这个值指向Reset_Handler函数的地址
-
CPU开始执行Reset_Handler处的代码
阶段2:软件初始化(Reset_Handler)
6. PC跳转到Reset_Handler()
-
CPU开始执行启动文件(如startup_stm32f407xx.s)中的Reset_Handler函数
-
这是芯片上电后执行的第一段程序代码
7. 堆栈设置判断
-
检查是否需要设置多堆栈(进程堆栈PSP)
-
对于大多数应用,只使用主堆栈(MSP)
8. C环境设置
复制.data段从Flash到RAM
-
将已初始化的全局变量和静态变量从Flash复制到RAM
-
使用链接器定义的符号:
-
_sidata
: .data段在Flash中的起始地址 -
_sdata
: .data段在RAM中的起始地址 -
_edata
: .data段在RAM中的结束地址
-
在RAM中清零.bss段
-
将未初始化的全局变量和静态变量所在的内存区域清零
-
使用链接器定义的符号:
-
_sbss
: .bss段的起始地址 -
_ebss
: .bss段的结束地址
-
9. 系统初始化
调用SystemInit()函数
-
在system_stm32f4xx.c文件中定义
-
关键配置:
-
时钟配置:启用PLL,设置系统时钟为168MHz
-
总线分频器:配置AHB、APB1、APB2总线时钟
-
Flash延迟:设置Flash等待状态,确保在高速时钟下可靠运行
-
电源控制:配置电源管理相关设置
-
10. (可选)初始化C库
-
如果需要,初始化C标准库
-
设置堆(heap)和标准I/O等
阶段3:应用程序启动
11. 跳转到main()函数
-
所有初始化完成后,跳转到用户编写的main()函数
-
此时:
-
时钟系统已正确配置
-
内存已正确初始化
-
外设寄存器处于默认状态
-
12. C应用程序运行
-
用户应用程序开始执行
-
可以安全地初始化外设、创建任务、处理中断等
STM32F407特定细节
-
Flash基地址:0x0800_0000
-
RAM基地址:0x2000_0000(112KB或192KB,取决于型号)
-
系统时钟:最高168MHz
-
向量表:位于Flash起始位置,包含中断服务例程的地址
这个启动过程确保了硬件和软件环境在main()函数执行前都已正确初始化,为应用程序提供了稳定可靠的运行基础。