一句话总结:

上电后硬件先清零寄存器→自动从向量表加载 MSP 和 Reset_Handler→执行汇编启动文件(关中断→调 SystemInit→调 __main)→__main 完成 .data/.bss 初始化→最终跳到 main()

启动流程:

① 硬件复位:所有寄存器清零

一句话:上电/复位电路先把 CPU 与片上外设的寄存器全部拉到已知默认值。
展开:

1、电源监控器检测到 VDD 过阈值后,内部产生 POR/BOR 脉冲;

2、所有寄存器(R0-R12、PSP、MSP、PRIMASK、NVIC、TIM、GPIO…)被强制置 0 或默认值;

3、复位完成后,CPU 放开总线,准备取第一条指令。


② 向量表读取:取 MSP + Reset 向量

一句话:CPU 自动从地址 0x0000 0000 读出 8 个字节,前 4 字节 → MSP,后 4 字节 → PC(一般指向复位)。
展开:

1、0x0000 0000 实际被重映射到 Flash(0x0800 0000)或 Boot ROM;

2、硬件级把 0x0000 0000 处的 32 位数写入 MSP;

3、把 0x0000 0004 处的 32 位数写入 PC(最低位必须为 1,表示 Thumb 状态)。


③ 汇编启动文件:Reset_Handler

一句话:汇编写的 Reset_Handler 先关中断、再调 C 函数 SystemInit()。
展开:

1、startup_stm32fxxx.s 内实现;

关键动作:

cpsid i 关全局中断;

可选:使能 FPU(M4/M7);

bl SystemInit → 配置时钟、Flash 等待周期、重设 VTOR;

bl __main(C 库入口,绝不返回)。


④ C 库入口:__main

一句话:__main 完成 C 运行环境:把 .data 从 Flash 搬到 RAM,把 .bss 清零,调构造函数。
展开:

由编译工具链提供(Keil 的 __main,GCC 的 _start);

步骤:

复制映像:.data 有初值的全局变量 → RAM;

清零段:.bss、.sbss 清 0;

C++ 构造:调用 __libc_init_array/__cxx_global_var_init;

最终 bl main 跳转。


⑤ 用户 main() 入口

一句话:至此 C 世界就绪,用户开始写外设初始化与业务逻辑。
展开:

栈指针 MSP 已指向正确 RAM 顶部;

时钟已跑到设定频率;

全局变量、静态对象已初始化;

NVIC 已可开中断;

main() 永不返回,返回将陷入死循环或 HardFault。

OS程序流程:

流程

  1. 系统启动时,运行启动代码,此时使用的是主堆栈指针(MSP)
  2. 调用SVC中断(Supervisor Call),os将第一个任务进行切换,触发特权级切换(MSP)
  3. SVC中断完成后(MSP),加载首个任务的上下文,切换至进程堆栈指针(PSP)开始运行
  4. 用户级的线程模式开始执行,此时CPU运行于用户模式,使用PSP。
  5. 中断到来时,自动切换回MSP堆栈,处理中断(特权模式)中断必须在MSP中进行。
  6. 中断处理完成后,恢复PSP,继续用户任务执行。
  7. 当需要任务切换时(如tick中断或任务主动让出CPU),触发PendSV异常。
  8. 在PendSV中断处理函数中,保存旧任务的寄存器到任务的堆栈(PSP)。
  9. 从就绪列表选择新任务,加载新任务的寄存器状态,并切换PSP至新任务堆栈。
  10. 新任务开始执行,继续使用PSP堆栈。

② 注意事项

1、操作中断里的变量,一定用的是MSP指针。在OS中,进入任务中后,运行的就是PSP指针。

2、任务的切换是在PendSV中断中进行

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐