MCU 上电启动流程
简化版
MCU上电流程:
1. 外部电源接入芯片 VDD,内部 LDO、模拟电路开始上电;
2. POR上电复位,电压低于阈值时 持续复位;
3. 内核、外设、寄存器复位和 flash、RAM 就绪;
4. 等待HIS稳定;
5. 锁定boot值
6. 上述操作完成后,复位信号NRST拉高,CPU内核退出复位,硬件自动开始取指。
MCU软件启动流程:
1. 上电,硬件自动加载 主栈指针MSP
2. 跳转到复位中断函数
3. 初始化数据段.data、清.bss段
4. 进入 main
5. 用户初始化时钟、外设
6. 进入主循环程序
常见问题:
1. 数据段和 BSS 段是什么?
- .data 段:有初始值的全局 / 静态变量,需要从flash复制初始值
- .bss 段:没初始化的全局 / 静态变量,启动时必须清 0
2. 启动文件 startup.s 作用?
startup.s汇编文件,内部包含Reset_Handler 复位函数,负责最早期硬件与 C 语言环境初始化,没有它main函数跑不起来。
3. 程序从哪里开始执行?
不是从 main 开始!是从 Reset_Handler 复位函数开始,再跳 main
4. 什么是MSP?
MSP 本质是一个32位寄存器,存放 栈内存的顶端地址。
MSP 指向的栈 作用是 保存临时数据、函数局部变量。上电必须先初始化 MSP,否则没有MSP指向的栈,CPU无法调用函数、响应中断,程序根本跑不起来;
关键特点:栈是向下生长,因此MSP 初始值是栈最高地址,使用时地址不断减小;
普通版
一、硬件上电时序
1. 外部电源接入芯片 VDD/VSS,内部 LDO、模拟电路开始上电;
2. 电源监控模块(POR)工作:
- POR:上电复位,电压低于阈值时持续输出复位信号;
3. 内核、外设、寄存器复位;
4. flash、RAM 就绪,上电后可以稳定读写;
5. 等待HIS稳定;
6. 复位结束:上述操作完成后(需要额外的delay时间),复位信号NRST拉高,CPU内核退出复位,硬件自动开始取指。
delay时间解释:
一般上电时间很快,所以POR复位信号很快就会释放,但是芯片还需要复位内核、外设等模块,等待模拟IP的稳定(LDO、HIS)、以及等待加载FLASH的OTP数据等。因此需要先把CPU内核复位拉低,等待准备好后,再释放NRST。
二、硬件自动取指
1. 硬件读取 BOOT0/BOOT1引脚电平,选择向量表起始基地址:
- BOOT0=0:向量表基址 = 0x08000000(主 Flash 启动)
- BOOT0=1:向量表基址 = 0x20000000(SRAM启动)或系统存储器(BOOTloader)
2. 硬件从选中的基址读 0 偏移 = MSP,0x4 偏移 = Reset_Handler 地址;
例如从flash启动:
Flash起始地址0x0800_0000,也是中断向量表的基地址。
地址0x08000000存放的是栈顶地址MSP,即主栈指针;
地址0x08000004存放的是复位函数Reset_Handler的入口地址;
CPU内核复位结束后固定操作:
1. 从中断向量表的基地址0x08000000读取4字节,作为主栈指针MSP;
2. 从地址0x08000004读取4字节,作为复位函数Reset_Handler的入口地址,写入程序计数器 PC;
3. CPU跳转到复位函数Reset_Handler入口地址,正式进入软件启动阶段。
三、软件启动全过程
(分为:复位函数Reset_Handler → C库初始化 → main 函数)
阶段1:执行startup.s里的复位函数Reset_Handler
注:复位中断服务函数是CPU上电执行的第一条代码
执行复位函数Reset_Handler,包含以下步骤:
1. .bss段 清零
没初始化的全局 / 静态变量,启动时必须清 0
2. .data段 数据初始化
有初始值的全局 / 静态变量,需要从flash复制初始值,给全局变量赋初始值;
3. 跳转到标准库入口 __main(C 库初始化入口)
阶段2:C标准库初始化(__main,编译器自带)
完成 C 标准库相关初始化,随后调用用户 main 函数。
阶段3:用户main函数初始化(应用层软件)
1. 初始化外设:配置 RCC,开启HSE/PLL、配置AHB/APB分频,确定系统主频;以及其他外设。
2. 中断配置:EXTI、NVIC 优先级、中断屏蔽;
3. 低功耗、定时器、串口、ADC 等外设初始化;
4. 主循环 while (1);
阶段4:程序运行&中断抢占
程序正常跑主循环,外设产生中断请求送 NVIC,打断主流程,跳转到对应中断服务函数;
若进入 WFI/WFE 休眠,由 EXTI、定时器等外设唤醒 CPU,恢复运行。
