MCU上电启动流程

MCU上电启动流程
THEDIBROM(一级引导加载程序)
基本概念
MCU的BROM
(Boot ROM,启动只读存储器)代码,是指芯片制造过程中被烧录的,固化在MCU芯片内部的ROM中(独立于Flash)的一段代码,无法被用户更改。
MCU最先运行的就是这段代码
,它负责设备上电后最底层的初始化工作,判断启动模式、并加载后续的引导程序Bootloader
BROM作用
1. 外设初始配置:BROM通常会做一些最基本的硬件初始化,比如时钟设置、存储器控制器配置等。
2. 启动引导(Boot strapping):MCU上电或复位时,BROM会被第一个执行,判断用来决定MCU的启动方式(比如从外部Flash、内部ROM、或者通过串口、USB等下载程序)。
判断条件
:通常是检测Strapping pin管脚,决定启动模式
Strapping pin
:用于在上电或复位时配置芯片启动行为或工作模式的引脚例如:
ESP32
的Strapping pin引脚是GPIO0、GPIO2
STM32
的相关引脚就是BOOT0、BOOT1通过检测这两个引脚的电平,来判断如何启动
3. 安全机制:BROM可以集成安全启动(Secure Boot)、加密认证等逻辑,确保只有经过认证的固件(bootloader等)能够运行。
BROM典型执行流程
ESP32
上电或复位,MCU执行BROM代码
- 芯片上电或复位后,MCU自动跳转(
程序计数器PC
指向)到BROM(Boot ROM)起始地址,执行固化在ROM中的引导代码。
- 芯片上电或复位后,MCU自动跳转(
最小硬件初始化
- 配置最基本的时钟源和供电电路,初始化必要的内置外设(如UART)。
- 保证能读取启动配置(Strapping)并支持后续数据通信。
读取Strapping引脚状态(启动配置)
检查关键Strapping引脚(如GPIO0、GPIO2等)状态,判断当前芯片应进入哪种启动模式。
常见启动模式有:
- SPI Flash启动(正常工作模式)
- UART下载(烧录)模式(通常GPIO0拉低)
- 其他特殊模式(如SD卡启动,具体依芯片型号而定)
启动模式分支执行
选择为
SPI Flash
启动(正常启动):- 根据Flash引脚配置,初始化SPI接口。
- 从SPI Flash的固定地址读取Bootloader头部信息,校验格式与有效性。
- 若启用安全启动,则校验Bootloader签名(可选)。
- 校验通过后,将Bootloader从SPI Flash加载到
RAM
,并跳转到Bootloader入口地址。 - Bootloader继续运行,进一步初始化、读取分区表,找到并校验用户App(主程序)的位置,最后跳转到用户App入口地址,开始用户应用的执行。
选择为
UART下载模式
:- 初始化UART,发送握手字符,如不断发送‘C’(XMODEM协议的握手信号。
BROM使用
串口文件传输协议
(如UART的XMODEM1K
、XMODEM协议
),用于和上位机(如电脑上的烧录工具)进行数据收发。- 等待PC端工具(如esptool.py)连接,与其交互,使用
XMODEM1K协议
完成烧录(App、Bootloader、分区表等)等命令。 - 按照协议完成Flash操作,烧录结束后可复位重启进入正常启动。
其他模式:
- 若支持SD卡、HSPI等启动方式,按需求初始化相关硬件并加载固件。
异常与回退处理(如有)
- 如果Flash启动失败、固件校验出错,或用户请求安全擦除等,BROM可回退至UART下载模式,允许用户重新烧录修复。
STM32
上电或复位,MCU执行BROM代码
- MCU上电或复位后,MCU自动跳转到BROM(System Memory)起始地址,执行固化在ROM中的引导代码。
最小硬件初始化
- 设置堆栈指针。
- 初始化系统时钟为内部默认振荡器(如HSI)。
- 关闭大部分外设,仅为后续判断和通信保留必要硬件支持。
读取启动配置(BOOT引脚)
- 读取BOOT0和BOOT1引脚状态。
- 根据引脚状态决定启动模式:
- 主Flash启动(通常进入用户应用或用户Bootloader)
- System Memory 启动(进入BROM内置系统Bootloader,支持烧录)
- SRAM启动(调试/测试模式,部分型号支持)
启动模式分支执行
主Flash启动(正常启动)
:- 跳转到主Flash首地址(通常是0x08000000),执行用户自定义Bootloader(如果Bootloader被省略,直接执行用户App)。
- 若存在Bootloader,Bootloader负责进一步初始化和启动用户App(主程序)。
System Memory 启动(系统Bootloader/烧录模式)
:- 初始化串口/I2C/USB等通信外设(具体支持接口依型号而异)。
- 等待上位机(如STM32CubeProgrammer、Flash Loader Demo等)发送烧录/下载命令。
- 根据接收到的命令,实现固件烧录、擦除、校验等。
SRAM启动
:(部分型号支持):
- 跳转到SRAM首地址,通常用于调试或特殊应用。
错误/异常处理
- 若启动模式配置错误、Flash无效或校验失败,部分型号会停留在BROM,等待外部干预。
BootLoader(二级引导加载程序)
基本概念
Bootloader(引导加载程序)是指在MCU启动过程中,在BROM之后、用户应用(App)之前执行的一段程序,它通常存储在MCU的Flash
中,由开发者或芯片厂家提供,可升级。
当一级引导程序(BROM)校验并加载完二级引导程序后,它会从二进制镜像的头部找到二级引导程序(bootloader)的入口点,并跳转过去运行。
Bootloader是MCU系统启动的中间桥梁
,连接BROM
与用户App
,承担安全、升级、初始化等关键任务。
BootLoader作用
系统初始化
- 完成比BROM更复杂的硬件初始化(如外设、分区表、时钟、存储等),为后续应用运行做准备。
固件升级/下载
- 支持通过UART、USB、CAN、网口、
OTA
、SD卡等多种方式下载/升级主固件,实现远程或本地维护。
- 支持通过UART、USB、CAN、网口、
固件校验与安全启动
- 校验主固件完整性(如CRC、Hash、签名等),防止固件损坏或恶意替换,支持加密和安全启动。
多分区/多固件管理
- 通过分区表管理多套固件,实现A/B升级、回滚、出厂恢复等功能。
异常处理与恢复
- 检测主固件异常(如校验失败、启动失败等),可自动回滚、恢复或进入维护模式。
引导用户应用
- 校验通过后,将控制权跳转(设置PC)到主应用(App)入口地址,正式启动用户业务。
BootLoader典型流程
1. Bootloader自身启动(由BROM/硬件跳转)
主要内容
:- 上电或复位后,BROM执行完毕后,跳转到Bootloader执行,接管系统控制权。
- Bootloader通常位于Flash的固定地址(如ESP32的0x1000,STM32的0x08000000)。
2. 初始化时钟、存储、外设等
主要内容
:- 配置系统时钟到正常运行频率(如PLL倍频,切换到外部晶振)。
- 初始化存储器(如外部SPI Flash、片上Flash、SRAM等)。
- 配置必要的外设(如UART、CAN、USB、WiFi、以太网等),为后续升级、通信等做准备。
- 初始化看门狗、GPIO、调试接口等系统资源。
3. 读取并解析分区表或固件头
主要内容
:- 从Flash的指定位置读取分区表或固件头部信息。
- 解析出每个分区(如App、OTA、参数区、数据区、NVS等)的起始地址、大小和用途,这样BootLoader才能正确找到并加载要启动的用户App。
- 检查分区表或固件头的有效性(如magic number、校验和等)。
- 支持多固件、多数据分区,为OTA升级和数据管理打基础。
4. 判断是否进入固件升级/下载模式(如按键、命令、定时、固件异常等)
主要内容
:- 检查是否有升级请求(如检测升级按键、串口命令、网络指令、定时器触发、上次异常标志等)。
- 判断是否进入固件下载、烧录或维护模式。
- 支持
多种升级方式
(如本地串口、USB、SD卡、远程OTA等)。 - 若进入升级模式,初始化对应通信外设,准备接收新固件。
5. 如果需要升级,等待或接收外部新固件,烧录到指定分区,并校验完整性。校验完成后进行复位重启
主要内容
:通过通信接口接收新固件(如串口、WiFi、以太网、USB等)。
按分区表将固件数据写入指定分区(如app1、upgrade等区域)。
对接收到的固件数据进行校验(如长度、CRC、签名等)。
烧录完成后再次校验固件完整性,确保升级过程正确无误。
切换分区标志/准备启动新固件,复位重启
6. 选择合适的主固件(App)分区,校验签名/Hash等
主要内容
:- 根据分区表和系统当前状态(如成功升级、上次启动成功分区、回滚标志等)选择要启动的主固件分区。
- 读取目标固件头部信息,校验固件签名、Hash、CRC等,确保固件安全和完整。
- 支持多分区(如A/B分区结构)、升级回滚等机制,提升系统可靠性。
7. 校验通过后,跳转到主固件入口(用户App)
主要内容
:- 设置主固件的入口地址(如中断向量表、Reset_Handler等)。
- 关闭或重置Bootloader期间用到的外设,释放系统资源。
- 跳转到主固件入口,正式启动用户应用(App)。
若失败,则根据策略回滚、恢复、报警或停留在Bootloader
- 主要内容:
- 如果固件校验失败或主固件启动异常,根据回滚策略自动切换到上一个可用固件(回滚)。
- 若回滚也失败,则进入恢复模式、报警(如LED闪烁、蜂鸣器等),或停留在Bootloader等待用户操作。
- 通过多样化的异常处理,防止异常固件导致系统“变砖”,提升产品的可维护性和安全性。
- 主要内容:
BROM和BootLoader区别
存放位置区别
BROM
:存放在MCU内部的一块ROM区域
这是芯片出厂时烧录固化,用户无法更改或擦写。
它和MCU的内核、外设等一样,是芯片设计时就“刻”进硅片里的,通常在芯片内部的一个固定物理地址空间(如0x00000000或芯片手册指定的ROM区)。
Bootloader
:一般存放在Flash当中
- 具体的存放地址取决于芯片架构和启动配置:
- 常见MCU(如STM32):Bootloader通常放在用户Flash的起始地址(如0x08000000),也可以自定义位置,只要BROM跳转时能找到。
- ESP32/W800等带外部Flash的芯片:Bootloader通常放在外部SPI Flash(如ESP32的0x1000,W800的0x2000)。
- Bootloader是可以被擦写、升级、替换的,一般由开发者或厂家烧录进去。
以下是常见MCU的存储区域划分参考即可:
ESP32
:
STM32
:
下载/烧录的区别
BROM的下载烧录
:主要就是我们平时将代码写好后,使用烧录工具烧录芯片,就是BROM的下载模式
,写入固件(分区表、Bootloader、App)到MCU的flash
表现为:
- 你通常需要按下“BOOT”键或短接某些引脚(如ESP32的EN+IO0),
- MCU进入“下载/烧录模式”,
- 烧录工具就能识别并开始烧写——这整个过程都是由BROM实现的。
Bootloader的下载/升级
:Bootloader的下载/升级功能主要用于产品应用阶段的FOTA/OTA(Firmware Over The Air)升级、本地U盘/SD卡升级等“固件维护”场景。
它是设备已经有Bootloader和App之后,系统自己实现的升级方案(比如远程下载新固件、热切换等),而不是空芯片下载烧录
小结
:
- 开发阶段用烧录工具刷写固件,就是用的BROM的下载/烧录功能
- Bootloader的下载/升级一般是产品运行起来后,做OTA升级、本地维护时才用到。
分区表机制
基本概念
分区表就是把MCU
上的Flash
(闪存)分块管理的一种机制
。可以把Flash(芯片里的存储空间)看作一大块硬盘。上面要存很多不同内容:程序代码、配置信息、升级数据、用户数据等。如果大家都“乱放”,就容易互相覆盖、数据混乱。
所以就有了分区表的概念,将每个内容的存储地址固定下来,可以看作存储空间的使用说明书
分区表中的每个条目都包括以下几个部分:
- Name(名字):比如app、nvs、bootloader等,代表分区用途。
- Offset(起始地址):从Flash哪个地址开始。
- Size(大小):这块分区有多大。
- Flag:目前没用,通常填0。
所有这些信息都写在一张表里,叫“分区表”,芯片启动时会加载它。
W800 分区表的默认偏移地址(默认存放)为 0xE000
,分区表的大小为 0x1000
(一个sector,4k)。
这个默认偏移地址就是在Flash基地址
下进行一个偏移
的操作,如基地址为0x08000000
,实际地址就是0x08000000+0xE000
即0x0800E000
注意:
分区表的 Offset 和 size 需要
4K
对齐。请确保在配置分区表时,每个分区的 Offset 和 size 都是4K
的整数倍。
存放分区表
- 固件烧录/生产阶段
- 首次烧录时,和
Bootloader
、App
等一起,通过烧录工具(如esptool.py、STM32CubeProgrammer、厂家自带烧录脚本等)将分区表写入Flash的指定位置(分区表规定的Flash的位置)。
这通常是出厂生产或初次开发板刷机时的标准步骤。
一般烧录命令会自动包含分区表(如ESP32的--partition-table
参数,W800的wm.py flash
脚本)。
- 固件升级/OTA阶段(很少见)
某些平台允许通过OTA升级时连同新固件一起下发新的分区表(比如分区方案有变更、增加新分区等)。
这种情况较少见,且有兼容性和安全风险——因为分区表变更可能导致旧数据丢失或启动失败,所以一般需要特殊处理和校验。
- 用户自定义分区表时
- 如果你选择自定义分区表(如ESP-IDF/W800的custom partition table),则会在编译时生成自定义的partition_table.img,烧录时也会被刷写到Flash指定区域。
使用分区表
一般由我们的Bootloader
读取我们烧录进去的分区表:
Bootloader启动后,会从Flash指定的分区表位置(如W800的0xE000,ESP32的0x8000)读取分区表内容。
读取后,Bootloader解析分区表,获取各分区(如app、ota、nvs、user等)的起始地址、大小、类型等信息。
Bootloader接下来就会根据这些信息,决定如何加载主固件、如何支持固件升级、数据存储等功能。
以下基于WinnerMicro W80X系列的分区表
使用分区表时,包含几种不同的分区表方案:三种预置的分区表和一种用户自定义分区表:
Normal app, no OTA(普通应用程序,没有OTA)
Large app, no OTA(大型应用程序,没有OTA)
Normal app, with OTA(普通应用程序,带有OTA)
Custom partition table(用户自定义分区表)
内置分区表样式:
- Normal app, no OTA(partition_table_normal.csv)
- Large app, no OTA(partition_table_large.csv)
- Normal app, with OTA(partition_table_with_ota.csv)
这三种分区表中,Normal 的分区不带app_ota
和 user
分区,SDK 默认使用 Large 这个分区表,可以从 Kconfig 配置中指定其他分区表。下面是对出现的名词的解释:
ft(factory)
:芯片的出厂固件,启动时将默认加载这个文件。bootloader
:存放 bootloader 的启动程序,完成OTA升级文件的解压和固件更新。partition_table
:存放分区表信息本身,包括各个分区的名称,地址,大小和FLAG。app
:存放应用程序,也就是我们的代码app_ota
:存放 OTA 升级包的user
:用户自定义分区,可选nvs
:非易失存储分区,用于 NVS 模块的 key-value 数据存放,常用来存配置、参数等,断电也不会丢,该分区需要一块做垃圾回收,所以 NVS 的大小需要大于等于2*0x1000。
注意:
ft分区,是芯片出厂固件,用户不能修改其中的内容。
ft,bootloader,partition_table这3个分区的配置 不能修改 。app,app_ota, NVS 这3个分区 不能修改名称 ,可以修改地址和大小。
用户自定义分区表
如果想要根据自己的程序使用灵活性更高的分区表,那么请在 menuconfig
的 Partition Table 菜单中选择 Custom partition table 选项,启用自定义的分区表功能。之后在工程根目录下添加一个 partition_table_custom.csv
文件即可,在编译时构建系统会自动识别并进行处理。
- Custom partition table(partition_table_custom.csv)
字段之间的空格会被忽略,任何以 # 开头的行(注释)也会被忽略。
TXT 文件中的每个非注释行均为一个分区定义。
user 是一个用户自己配置的分区的示例,我们在使用时只需要合理的设置 offset 和 size 字段的内容即可。
ft, bootloader, partition_table 这3个分区不能改,app,nvs 这2个分区名称不能改,地址和大小可以修改。
烧录与擦除
一般使用脚本烧录
烧录(写入固件)时,分区表决定了每个固件/数据要写到Flash的哪个位置,烧录工具会自动参考分区表把内容写到正确地址。
为什么要烧录这么多分区内容?
芯片不是只需要运行你写的主程序,还需要其他很多内容才能安全、可靠地工作,比如:
- bootloader:负责上电启动,决定加载哪个主程序,有的还负责升级。
- app:你的主应用
- nvs:用来存放参数、配置信息
- app_ota/user区:升级固件、用户自定义数据
- ft:出厂固件,有时用于回滚或工厂测试
- 分区表本身:让芯片知道这些“房间”的分布
所以烧录过程就是把这些功能模块分门别类地装到芯片的不同地方,让它们各司其职。
芯片类似的分区表(stm32、esp32)
esp32分区表
:
MCU启动流程
这是以WinnerMicro的W80X系列MCU进行总结的启动流程,与ESP32类似,但是与STM32有好像不同
执行流程
上电或复位
- MCU加电或复位后,自动进入启动流程。
执行BROM(一级引导加载程序)
- 芯片首先运行内部固化的BROM代码,完成最基础的初始化和启动模式判断,然后决定后续加载哪个程序(如Bootloader或用户App)。
执行Bootloader(二级引导加载程序)
- 若启动模式为正常启动,BROM会将控制权交给Bootloader。Bootloader负责更完整的初始化、分区表解析、固件校验、升级检测等,并选择合适的主固件(App)进行启动。
启动用户App(主程序)
- 校验无误后,Bootloader跳转到用户App入口,开始执行用户主程序,系统正式进入应用阶段。
注:
- BROM和Bootloader的具体功能与实现细节见上面内容。
- 分区表、固件升级、异常处理等机制均在Bootloader阶段完成。
启动流程图
简略流程:BROM->Bootloader->app
详细流程: