mcu启动流程

MCU(STM32)启动流程详解笔记

深入理解MCU启动原理:https://blog.csdn.net/Setul/article/details/130019922

STM32的启动过程 --- startup_xxxx.s文件解析(MDK和GCC双环境)https://blog.csdn.net/weixin_42328389/article/details/120656722?fromshare=blogdetail\&sharetype=blogdetail\&sharerId=120656722\&sharerefer=PC\&sharesource=rechol\&sharefrom=from_link

STM32的内存管理相关(内存架构,内存管理,map文件分析):https://blog.csdn.net/weixin_42328389/article/details/120622384

一、概述

STM32 启动流程的核心是地址映射机制与启动介质选择,通过硬件配置(BOOT 引脚)和软件初始化(堆栈、数据段搬运),最终引导 CPU 执行用户程序。整体流程可概括为:复位→地址重映射→堆栈初始化→数据段搬运→执行用户代码。

复制代码

二、内存映射基础

2.1 核心地址空间划分(STM32 Cortex-M4)

STM32 作为 32 位 MCU,寻址能力为 4GB(0x0000 0000~0xFFFF FFFF),地址空间按功能划分为多个 512MB Block,核心区块及用途如下:

Block 0(0x0000 0000~0x1FFF FFFF):含自举区、Flash、系统存储器、选项字节,核心代码存储与启动相关区域。

Block 1(0x2000 0000~0x3FFF FFFF):SRAM 区域,用于存储运行时数据(堆栈、变量),掉电数据丢失。

Block 2(0x4000 0000~0x5FFF FFFF):外设区域,挂载 APB1、APB2、AHB1、AHB2 等总线外设,通过地址访问外设寄存器。

Block 7(0xE000 0000~0xFFFF FFFF):Cortex-M4 内核外设区域,含中断控制器、调试模块等核心硬件。

2.2 核心存储区域详解

|--------------------|--------------------------|-----------------------------------------------------------|
| 存储区域 | 地址范围 | 核心特性与用途 |
| 自举区(重映射区) | 0x0000 0000~0x0007 FFFF | 512KB,复位后默认读取第一条指令的地址,本身不存代码,仅用于地址重映射。 |
| Flash(闪存) | 0x0800 0000~0x0807 FFFF | 512KB(示例型号),非易失性,存放用户代码(.text 段)、只读数据(.rodata 段),掉电数据不丢失。 |
| 系统存储器 | 0x1FFF 0000~0x1FFF 7A0F | 存放出厂自带 Bootloader(ISP 固件),用于固件升级、故障恢复。 |
| SRAM(静态内存) | 0x2000 0000~0x2002 0000 | 128KB(示例型号),易失性,运行时数据存储(堆栈、变量、堆空间)。 |
| 选项字节(Option Bytes) | 0x1FFF C000~0x1FFF C007 | 非易失性配置寄存器,用于硬件级保护(如 Flash 读保护、写保护),防止非法访问。 |

2.3 地址映射原理

CPU 通过 "地址映射" 机制关联地址与物理存储 / 外设:

访问某一地址时,MCU 内部地址译码器将地址映射到对应的存储区域或外设寄存器。

启动阶段的核心是 "自举区重映射",即通过 BOOT 引脚配置,将自举区(0x0000 0000)映射到实际启动介质(Flash/SRAM/ 系统存储器)。

  1. BOOT 引脚配置与启动介质选择

三、关于boot

3.1 自举区与重映射机制

自举区定义:地址范围 0x0000 0000~0x0007 FFFF(512KB),是 STM32 复位后的 "指令入口地址",CPU 复位后优先读取该地址的第一条指令。

重映射本质:自举区不直接存储代码,仅作为 "地址跳板",通过硬件配置将其指向实际存储介质,实现启动介质的灵活切换。

3.2 BOOT 引脚配置规则

STM32 通过 BOOT0 和 BOOT1 两个引脚的电平组合(高电平 1 / 低电平 0),决定自举区的映射目标,具体配置如下:

BOOT0=0(BOOT1 任意,默认忽略):自举区(0x0000 0000)映射到 Flash(0x0800 0000),正常运行模式,用户程序存储于 Flash,上电后直接执行。

BOOT0=1、BOOT1=0:自举区映射到系统存储器(0x1FFF 0000),ISP 升级模式,通过串口等接口升级 Flash 中的用户程序。

BOOT0=1、BOOT1=1:自举区映射到 SRAM(0x2000 0000),调试 / 临时运行模式,程序仅在 SRAM 中运行,掉电丢失,用于程序调试或临时测试。

3.3 核心作用

通过 BOOT 引脚配置,STM32 可适配三种核心场景:

正常产品运行:选择 Flash 启动,保障程序掉电不丢失。

固件升级:选择系统存储器启动,利用出厂 Bootloader 更新代码。

程序调试:选择 SRAM 启动,避免频繁擦写 Flash,提升调试效率。

四、从 Flash 启动的详细流程(主流启动方式)

当 BOOT0=0 时,系统从 Flash 启动,是最常用的启动模式,流程分为 5 个关键步骤:

四、单片机复位流程

4.1 步骤 1:复位后地址重映射

CPU 复位后,自动访问自举区首地址 0x0000 0000。

因 BOOT0=0,地址重映射机制将 0x0000 0000 指向 Flash 首地址 0x0800 0000,后续指令读取均从 Flash 执行。

4.2 步骤 2:MSP(主堆栈指针)初始化

Flash 首地址(0x0800 0000)存储MSP 初始值(sram栈底地址),CPU 复位后首先读取该值并加载到 MSP 寄存器。

栈的核心参数(以示例配置为例):

栈底地址:0x2002 0000(SRAM 高位地址)。

栈大小:STACK_SIZE = 0x400(2KB)。

生长方向:从高地址向低地址生长(栈顶 SP 初始指向栈底,压栈时 SP 递减,出栈时 SP 递增)。

栈的用途:存储函数局部变量、函数调用返回地址、中断现场保护,是程序运行的基础内存空间。

4.3 步骤 3:PC(程序计数器)初始化

Flash 地址 0x0800 0004 存储复位处理函数(Reset_Handler)的入口地址。

CPU 读取该地址后,PC 指针跳转到 Reset_Handler,开始执行系统初始化逻辑。

4.4 步骤 4:数据段搬运与初始化

Reset_Handler 的核心工作之一是完成 "数据段迁移",确保变量在 SRAM 中正常运行,主要涉及两类数据段:

4.4.1 RW-data 段(读写数据段)

存储:带初始值的全局变量、静态局部变量(如int g_var = 10;)。

存储位置:编译时初始值存于 Flash 的.rodata 段,运行时需搬运到 SRAM 的.data 段。

搬运逻辑:Reset_Handler 通过汇编指令,将 Flash 中 RW-data 的初始值复制到 SRAM 对应地址,确保变量初始值正确。

4.4.2 BSS 段(零初始化数据段)

存储:无初始值或初始值为 0 的全局变量、静态局部变量(如int g_var;或static int s_var = 0;)。

初始化逻辑:系统自动将 BSS 段对应的 SRAM 区域清零,无需从 Flash 搬运数据,节省存储资源。

4.5 步骤 5:进入用户程序(main 函数)

完成堆栈初始化、数据段搬运后,Reset_Handler 调用SystemInit()函数(配置系统时钟、外设时钟等)。

最终跳转到用户编写的main()函数,程序进入用户逻辑执行阶段。

五. 启动文件到底是什么?

启动文件(通常是汇编文件,比如 STM32 的startup_stm32f103xe.s)是由芯片厂商提供、直接与硬件内核(如 Cortex-M3/M4)对接的底层代码,它的作用是:

  1. 定义中断向量表(包括复位向量);

  2. 完成 CPU 上电后最基础的初始化(栈、堆、全局变量等);

  3. 最终 "接力" 跳转到用户代码的main函数。

具体作用:

5.1 硬件自动执行(上电复位后):

  • CPU从向量表的第一个条目(0x00000000)读取初始栈指针(MSP)

  • 从向量表的第二个条目(0x00000004)读取复位向量(Reset_Handler的地址)

  • CPU跳转到Reset_Handler函数

5.2 启动文件的初始化工作

启动文件(如startup_stm32xxxx.s)是一段汇编代码,主要完成以下任务:

复制代码
  • 初始化栈和堆:在 SRAM 中划分栈空间(用于函数调用、局部变量)和堆空间(用于malloc等动态内存分配)。

  • 初始化中断向量表。

  • 初始化全局变量:

    • 将 Flash 中.rwdata段的 "初始化了特定值的变量" 复制到 SRAM 的.data段。

    • 将 SRAM 中.bss段的 "未初始化或初始化为 0 的变量" 清零。

  • 初始化系统外设:如配置系统时钟(SystemInit 函数,部分启动文件会调用)。

  • 启动文件完成所有初始化后,通过汇编指令跳转到用户编写的main函数,此时才真正开始执行你写的第一行用户代码。

5.3一图流总结

六 中断向量表

通过上文的Boot ROM与Boot Loader我们知道:Boot ROM会读取Boot引脚的电平配置来选择启动方式。

6.1 BOOT 配置:决定 "程序从哪里读"

单片机通过BOOT 引脚(如 STM32 的 BOOT0、BOOT1)配置程序的启动介质,这一步决定了 "中断向量表和代码存在哪里":

  • BOOT0=0:从主 Flash启动(最常用,用户程序存放在这里)。

  • BOOT0=1,BOOT1=0:从系统存储器启动(用于出厂引导程序(厂家的bootloader)或 ISP 在线编程)。

  • BOOT0=1,BOOT1=1:从SRAM启动(多用于调试场景)。

6.2 向量表的 "唯一性" 与 "偏移"

  • 系统中只有一份 "逻辑上的 中断向量表 " ,但它的 "物理存储位置" 可以通过SCB->VTOR偏移到 Flash 或 SRAM。

  • 也就是说,向量表的 "内容(各中断的服务函数地址)" 是固定的,但 "存储这张表的物理地址" 可以切换 ------ 这就是 "偏移" 的本质。

6.3 复位向量指向的复位服务函数

(如 Reset_Handler )是唯一的 ,但它的 "存储地址" 会随向量表的偏移而变化:

  • 场景 1:向量表在 Flash( SCB->VTOR = 0x08000000 ), 复位向量(0x08000004)指向的是Flash 中存储的 Reset_Handler 函数的地址

  • 场景 2:向量表在 SRAM SCB->VTOR = 0x20000000 此时需要先将Flash 中的向量表复制到 SRAM (包括Reset_Handler的地址),然后SCB->VTOR指向 SRAM 起始地址。复位向量(0x20000004)指向的是Flash 中存储的 Reset_Handler 函数的地址。(与 Flash 中原始地址一致,因为向量表是复制过来的)。

6.4 中断向量表里存的是什么?

中断向量表的每一个条目(比如第0条是初始栈指针MSP,第1条是复位向量),存储的并不是指令代码本身,而是一个地址值(32位指针)。

  • 对于复位向量,这个地址值就是 Reset_Handler 函数在内存中的入口地址。

6.5 函数的地址(入口地址)是固定的吗?

在编译和链接阶段,链接器会根据链接脚本(Linker Script)为每一个函数分配一个固定的逻辑地址。假设 Reset_Handler 函数被链接器定位到了 Flash 区域的 0x08000C00 这个地址。

那么,无论中断向量表放在哪里(向量表偏移),Reset_Handler 这个函数的本体,其物理位置就在 Flash 的 0x08000C00 处,不会移动。而向量表中的复位向量就永远指向0x08000C00 这个地址。

6.6 中断向量表:"程序入口" 的索引表

上文说过,中断向量表是一个地址列表,存储了复位向量、所有中断服务函数的入口地址。它位于启动介质的起始地址区域(如 Flash 的0x0800 0000处)。

它的结构(以 Cortex-M 内核为例):

七、变量存储区域详解(SRAM 内部划分)

上图的 STACK_SIZE 栈大小应该为 1Kbytes

SRAM 作为运行时数据存储区,内部按功能划分为多个区域,从高地址到低地址分布如下:

栈(单片机自己的Stack):

地址范围:0x2001 FC00~0x2002 0000(栈顶→栈底)。

用途:函数调用、局部变量存储、中断现场保护。

特性:自动分配与释放,生长方向为高地址→低地址,溢出会导致程序崩溃。

堆(单片机自己的Heap):

地址范围:0x2001 8000~0x2001 FBFF(示例配置:HEAP_SIZE=0x800,FreeRTOS_HEAP_SIZE=15KB)。

用途:动态内存分配(如malloc()、free()),FreeRTOS 的任务栈、队列等也基于堆分配。

特性:手动分配与释放,生长方向为低地址→高地址,需避免内存泄漏。

FreeRTOS 堆(ucHeap):

专门用于 FreeRTOS 操作系统的内存管理,独立于普通堆,避免操作系统与用户程序内存冲突。

BSS 段:

地址范围:0x2000 8000~0x2001 7FFF。

存储:未初始化或初始值为 0 的全局 / 静态变量,系统启动时自动清零。

Data 段:

地址范围:0x2000 0000~0x2000 7FFF。

存储:已初始化的全局 / 静态变量,初始值从 Flash 搬运而来。

八、补充疏漏知识点

8.1 完整启动流程时序(从复位到 main)

上电 / 复位→CPU 读取 BOOT 引脚电平→确定自举区映射目标。

从自举区映射地址读取 MSP 初始值→初始化主堆栈。

读取 PC 初始值(复位处理函数地址)→跳转到 Reset_Handler。

Reset_Handler 执行:关闭中断→配置时钟→搬运 RW-data 段→清零 BSS 段→开启中断。

调用 SystemInit ()→跳转到 main ()→执行用户程序。

8.2 核心存储区域补充说明

RO-data 段(只读数据段):存储于 Flash,包含字符串常量(如"hello")、const 修饰的全局变量,不可修改,掉电不丢失。

选项字节(Option Bytes):除读保护外,还支持写保护(指定 Flash 区域不可擦写)、看门狗配置(硬件看门狗使能 / 禁用)等,修改后需重启生效。

系统存储器:内置的 Bootloader 支持 UART、I2C 等接口的 ISP 升级,无需外接编程器即可更新 Flash 程序。

8.3 关键注意事项

栈大小配置需匹配程序复杂度:函数嵌套层级深、局部变量多时,需增大 STACK_SIZE,避免栈溢出。

数据段搬运的必要性:Flash 为只读存储,带初始值的变量需搬运到可读写的 SRAM 才能修改。

BOOT 引脚配置错误的影响:若 BOOT0=1 但未烧录系统存储器程序,会导致 MCU 无法启动(死机)

相关推荐
chuwengeileyan13 小时前
stm32 adc采集光敏传感器模块的模拟输出脚A0的值
单片机·嵌入式硬件
啊森要自信3 小时前
【C语言】 C语言文件操作
c语言·开发语言·汇编·stm32·单片机
1+2单片机电子设计4 小时前
基于 STM32 的数控 BUCK-BOOST 升降压电源设计
stm32·单片机·嵌入式硬件
SUNNYSPY0014 小时前
SI2301S-ASEMI工业控制专用SI2301S
单片机
易水寒陈4 小时前
解析器模式,解析不同协议
stm32·单片机
1379号监听员_5 小时前
PID定速/定位置控制电机
stm32·单片机
李永奉5 小时前
杰理芯片SDK开发-内置触摸按键配置教程
嵌入式硬件·mcu·物联网
SystickInt6 小时前
32 LCD显示(FSMC应用)-寄存器
stm32·单片机·嵌入式硬件
d111111111d6 小时前
C语言中static修斯局部变量,全局变量和函数时分别由什么特性
c语言·javascript·笔记·stm32·单片机·嵌入式硬件·学习