STM32-BOOT的三种启动方式
STM32-BOOT的三种启动方式
STM32的三种启动方式
STM32-DataSheet
1. 启动引脚与三种启动选项
“At startup, boot pins are used to select one out of three boot options:”
(在启动时,启动引脚被用来选择三种启动选项之一:)
单片机外部通常会有特定的引脚(通常命名为BOOT0和BOOT1)。在芯片通电的那一瞬间,硬件会检测这几个引脚是高电平(接3.3V)还是低电平(接地)。根据引脚电平的不同组合,芯片会选择以下三个地方之一作为程序的起点:
Boot from user Flash(从用户闪存启动)
这是最正常、最常用的工作模式。User Flash 就是你平时用电脑写完代码后,程序被烧录进芯片永久保存的地方。选择这个模式,芯片通电后就会直接运行你编写的程序。Boot from system memory(从系统存储器启动)
System memory 是一块特殊的只读存储区。芯片在出厂前,厂家(比如ST公司)会在里面固化一段不可修改的程序,称为Bootloader(引导加载程序)。选择这个模式,芯片不运行你写的代码,而是运行厂家的这段内部代码。Boot from embedded SRAM(从内置SRAM启动)
SRAM(静态随机存取存储器)通常是用来存放程序运行时的变量(内存)的,掉电后数据会丢失。从这里启动主要用于开发人员进行高级调试,或者用于某些需要极快代码执行速度的特殊场景(因为 SRAM 的读取速度比 Flash 快得多)。
2. Bootloader(引导加载程序)的作用
“The boot loader is located in system memory. It is used to reprogram the Flash memory through a serial (UART, I2C, CAN, SPI and USB) communication interface. Refer to application note AN2606 for details.”
(引导加载程序位于系统存储器中。它被用于通过串行通信接口(UART, I2C, CAN, SPI 和 USB)对 Flash 存储器进行重新编程。详情请参考应用笔记 AN2606。)
- 它的核心作用是用来给芯片“下载/烧录”程序的。
- 如果你手头没有专用的下载器(比如
ST-Link或J-Link),你可以通过设置引脚让芯片进入“系统存储器启动”模式。 - 此时运行的 Bootloader 可以激活芯片上的各种通信接口(比如普通的串口 UART、USB 接口等)。然后,你就可以直接用一根 USB 线或串口线,把你电脑上写好的新程序发送给单片机。
- Bootloader 接收到这些新程序后,会把它们自动写入到User Flash(用户闪存)中。这个过程在工程上通常被称为ISP (In-System Programming,在系统编程)。
- 最后一句话提到,关于这个 Bootloader 支持哪些接口、具体怎么通讯,厂家提供了一份专门的文档叫AN2606(这是ST官方非常有名的讲解系统 Bootloader 的文档),有需要可以去查阅。
BOOT0和BOOT1引脚
BOOT1 通常是一个“复用”引脚(以经典系列为例)
在很多经典的 STM32 芯片(比如非常流行的 STM32F1、F4 系列)中,BOOT1 并没有自己专属的独立引脚,它通常与普通的 GPIO 引脚 PB2 共用。
在芯片复位(上电)的那一瞬间: 硬件会去读取 PB2 引脚上的电平高低,把它当作 BOOT1 信号来决定从哪里启动。
在启动完成,程序开始运行后: 这个引脚就恢复成了普通的 PB2 引脚,你可以把它配置成输入、输出或者其他外设功能。
在 CubeMX 中: 软件主要负责配置程序运行起来之后的引脚状态。因此,它在界面上只会标出 PB2,而不会特意标注它是 BOOT1。
STM32 User Reference Manual三种启动方式描述
SRAM
STM32F446xx 具有 4 Kbytes 的备份 SRAM(参见 第 5.1.2 节:电池备份域)以及 128 Kbytes 的系统 SRAM。 嵌入式 SRAM 可以按字节、半字(16 位)或全字(32 位)进行访问。读写操作以 CPU 速度执行,零等待状态。嵌入式 SRAM 最多分为两个块: SRAM1 和 SRAM2 映射在地址 0x2000 0000 处,可由所有 AHB 主机访问。 AHB 主机支持并发 SRAM 访问(来自 USB OTG HS):例如,当 CPU 正在读/写 SRAM1 时,USB OTG HS 可以读/写 SRAM2。 当选择从 SRAM 启动或选择物理重映射时(SYSCFG 控制器中的 第 8.2.1 节:SYSCFG 存储器重映射寄存器 (SYSCFG_MEMRMP)),CPU 可以通过系统总线或 I-Code/D-Code 总线访问 SRAM1 和 SRAM2。为了获得 SRAM 执行的最大性能,应选择物理重映射(启动或软件选择)。STM32F4还可以使用FSMC重映射到外部的SRAM启动; 可通过配置SYSCFG_MEMRMP寄存器.
STM32F7只有BOOT引脚, 额外有启动地址选项字节.
较新的芯片
在较新的芯片中,BOOT1 变成了“选项字节 (Option Byte)”
为了节省宝贵的物理引脚,意法半导体在许多较新的系列(例如 STM32G0、G4、L4、H7 等)中,直接取消了物理的 BOOT1 引脚。
在这些芯片中,BOOT1 的功能被移到了芯片内部的非易失性存储器中,成为了一个叫做 nBOOT1 的选项字节(Option Byte)。
你不再需要通过外部电阻去拉高或拉低引脚。
而是需要使用专用的下载软件(如 STM32CubeProgrammer)连接芯片后,直接在软件里修改内部寄存器的值来设定启动模式。
SRAM使用场景
在日常的绝大多数开发中,几乎用不到。但在特定的工业生产和极客场景下,它是不可替代的。
对于 99% 的嵌入式软件工程师来说,可能职业生涯中都不会把硬件引脚拨到 BOOT0 = 1, BOOT1 = 1。但它存在必然有其价值,主要用于以下几个特殊场景:
保护 Flash 的擦写寿命(工厂自动化测试): 单片机的 Flash 是有寿命的(通常是 1 万到 10 万次擦写)。在芯片出厂测试,或者大批量 PCBA(电路板)生产线上的功能验证阶段,如果每测一块板子都要烧写一次测试代码到 Flash 里,会极大地损耗 Flash 寿命。此时,测试设备会通过 SRAM 启动模式,直接把测试代码灌入内存运行,测完断电,无痕且不伤 Flash。
解除读保护(极客/破解场景): 如果一块 STM32 被设置了最高级别的读保护,Flash 里的代码是被锁死的。在某些破解或安全研究场景下,可以通过 SRAM 启动,在内存中运行一段特权代码,来尝试擦除整个 Flash 并解除芯片锁定(当然,这会清空原有程序)。
编写/调试 Flash 烧录算法: 如果你自己要写一段代码去更新或擦除主 Flash(比如做 OTA 升级),CPU 是不能“一边在 Flash 里运行,一边擦除自身所在的那块 Flash”的(这会卡死)。这时候,你必须把这段执行擦写动作的代码放到 SRAM 里去运行。
STM32启动流程
- 上电复位, 硬件自动执行, 系统从复位状态开始, 为后续运行做准备;
- 确定启动方式;
- CPU根据BOOT引脚电平确定启动方式;
- 从启动地址加载栈顶地址MSP, 并自动跳转到复位中断
- 执行启动文件, 执行汇编代码, 初始化堆栈指针, 配置中断向量表;
- 执行SystemInit函数, 初始化系统时钟;
- 执行__main, 初始化RW段, 清除bss段, 软件设置SP指针, 初始化栈空间, 最后跳转到main函数;
四个核心阶段
阶段一:纯硬件苏醒与引脚采样 (Hardware Phase)
上电与复位 (Power-on & Reset): 当你给芯片通电,或者按下 Reset 按键松开的一瞬间,芯片内部的硬件电路开始复位,系统时钟 (SYSCLK) 开始震荡。
采样 BOOT 引脚: 就像我们之前在数据手册里看到的,在复位后的第 4 个时钟上升沿,硬件会瞬间“锁定” BOOT0 和 BOOT1 引脚的电平状态。
内存重映射 (Aliasing): 硬件根据刚才读取的 BOOT 状态,拨动内部的总线开关。如果是最常见的从主 Flash 启动,硬件就会把物理地址 0x0800 0000 (Flash 起始位置) 映射到逻辑基地址 0x0000 0000。
(此时,CPU 还没有执行任何一行代码,全都是纯硬件的本能反应。)
阶段二:CPU 内核接管 (Cortex-M Core Phase)
此时,ARM Cortex-M 内核正式苏醒,它固定会去做两件“刻在基因里”的事情:
获取栈顶指针 (Fetch MSP):
CPU 去读取 0x0000 0000 这个地址里的前 4 个字节的数据,把它装载到自己的 MSP(主栈指针寄存器) 里。
意义:C 语言的运行极其依赖“栈(Stack)”来保存局部变量和函数调用记录。CPU 醒来第一件事就是找一块 SRAM 作为自己的“办公桌”。
获取复位向量 (Fetch PC):
CPU 紧接着去读取 0x0000 0004 这个地址里的数据,把它装载到 PC(程序计数器) 里。这个数据存放的就是第一条代码指令所在的地址(通常被称为 Reset_Handler 复位中断服务函数)。
意义:CPU 找到了程序的第一行代码,正式开始执行!
阶段三:汇编引导文件 (Startup Code Phase)
此时,PC 指针跳转到了 Reset_Handler。这段代码通常是用汇编语言写的(就是你工程里那个叫 startup_stm32xxx.s 的文件)。它的主要任务是为 C 语言的运行搭建环境:
系统初始化 (SystemInit): 配置好单片机的系统时钟树(把默认的慢速内部时钟切换到高速外部晶振,拉满芯片主频),并配置好 Flash 的读取延迟。
搬运 .data 段:
你在 C 语言里写了 int a = 5;(带有初值的全局变量)。这个 5 掉电不能丢,所以它是存在 Flash 里的。但程序运行时变量又必须在 SRAM 里读写。所以,启动代码会把这些变量从 Flash 中复制到 SRAM 里。
清零 .bss 段(填坑解惑):
上一问我们提到,刚上电时 SRAM 里全是乱码。如果你写了 int b;(没赋初值的全局变量),按 C 语言标准,它默认应该是 0。为了实现这一点,启动代码会强行把 SRAM 中分配给这些变量的区域全部填成 0。这就是为什么你没赋值的全局变量不会是乱码的原因!
跳转到 C 库: 调用 __main,完成 C 标准库的初始化。
阶段四:进入 C 语言世界 (C World)
经过前面所有的铺垫,环境终于准备就绪。__main 函数最终会调用一条指令:BL main。
此时,程序计数器 (PC) 跳转到了你亲手编写的 main.c 里的 main() 函数。
接着进入 while(1) 死循环,你的代码开始日复一日地控制 LED 闪烁、读取传感器、收发串口数据,直到下一次断电。
相关参考文档
STM32的BOOT1和BOOT0查找及配置-都有BOOT1引脚的_stm32boot1引脚在哪-CSDN博客
STM32的完整启动流程分析_stm32启动过程详解-CSDN博客
典型arm32位单片机启动流程(从上电到main.c) - 林接接 - 博客园
