十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32系统内存启动模式实战:BOOT0/BOOT1引脚与Bootloader烧录全解析

STM32系统内存启动模式实战:BOOT0/BOOT1引脚与Bootloader烧录全解析 做嵌入式开发的朋友对“启动模式”这个词应该都不陌生。尤其是第一次用STM32的时候看到BOOT0、BOOT1两个引脚往往一头雾水——既不知道它们是干什么的更不知道为什么芯片明明连接成功了却翻不了机。ST官方有一份常年更新的应用笔记AN2606全名就叫《STM32微控制器系统内存启动模式》专门把这件事从头到尾讲透了。这篇文章不是为了翻译PDF而是从实战角度拆解这份笔记的核心内容讲讲系统内存启动模式到底是什么、怎么用、踩过哪些坑以及量产和现场升级时怎么把这套机制变成自己的工具。这份笔记最大的价值在于它告诉你怎么在没有调试器、没有ST-LINK、甚至连IDE都没有的情况下只用一颗USB转串口芯片就能把固件烧进去。对做小批量产、样板调试、甚至是帮别人救砖的场景来说这就是嵌入式工程师的“备用钥匙”。无论你是刚入门的新手还是天天和HAL库打交道的老人搞懂系统内存启动模式都值得。1. AN2606到底是什么一篇解决“烧录困境”的应用笔记1.1 为什么系统内存启动模式这么重要STM32上电以后CPU会先到某个固定地址取第一条指令。这个“取指地址”由启动模式决定而启动模式又由引脚或者选项字节决定。绝大多数情况下我们让芯片从主Flash启动直接跑App。但在某些场景下主Flash里的程序可能是空的、损坏的或者压根就不想跑它——比如板子刚焊好Flash里空空如也或者固件有Bug导致跑飞了这时候就需要一个“兜底路径”。这个兜底路径就是系统内存System Memory。所谓系统内存是芯片出厂时固化在ROM里的一段引导程序我们通常叫它BOOTROM或者内置Bootloader。它支持通过若干串行接口把数据写进Flash。AN2606就是这段引导程序的“说明书”它把所有系列STM32支持的启动接口、引脚、协议版本、时序参数全部列了出来。很多新手容易混淆系统内存不是SRAM不是用户程序区而是一块不可擦除的ROM区域。它不占用户Flash空间也不影响你正常编译下载。它就像汽车备用轮胎——平时用不到关键时刻没有它事情就大了。理解了这一点后面操作起来才踏实。1.2 AN2606覆盖的范围与正确读法AN2606这份笔记的覆盖面非常大从老一代的F1系列一直延伸到F0、F2、F3、F4、F7、L0、L1、L4、H7、G0、G4、U5这些系列。每个系列在笔记里都有一个小节内容包括该系列支持哪些启动源主Flash、系统内存、SRAM以及部分系列支持的OTP/外部存储器等从系统内存启动时对应哪些引脚配置或者哪个选项字节要设置为多少Bootloader支持哪些接口USART、SPI、I2C、USB DFU、CAN/FDCAN等每个接口对应的具体引脚PA9/PA10、PA2/PA3之类支持的协议版本和选项字节、校验字节用户Flash的起始地址、页面大小、擦除/编程注意事项读这份笔记的正确姿势不是从头读到尾而是先找到自己所用型号对应的那几页再对着参考手册Reference Manual和数据手册Datasheet交叉看。AN2606虽然叫“应用笔记”但本质上是一份“映射表”加“配置指南”。你所在意的问题比如“这款芯片能不能用USART1进Bootloader”“DFU接口和UART接口有没有冲突”在对应系列的小节里都能找到答案。我自己的习惯是每次新到一个项目先查AN2606里对应系列的表格确认Bootloader支持的外设接口和引脚然后把这个表保存到项目的docs目录里。后面不管是做产线工装还是写IAP升级手册都用得上。2. 启动模式选择机制BOOT0/BOOT1引脚背后的硬件逻辑2.1 三类启动源与引脚组合STM32启动模式的核心其实不复杂复位释放的一瞬间芯片采样BOOT0、BOOT1引脚的电平然后决定从哪个地址开始运行。以最常见的STM32F103为例它的启动模式如下BOOT0BOOT1启动源说明0X主Flash正常运行用户程序10系统内存执行ROM内Bootloader11SRAM从RAM运行调试/临时代码注意F103的BOOT1引脚对应的是PB2而不是多出来的专用脚。BOOT0则是一个专用引脚通常在芯片的某个角落具体位置要看封装图。在实际板子上BOOT0一般会通过一个10kΩ的下拉电阻接地这样可以保证默认从主Flash启动。如果要进Bootloader就把BOOT0拉高复位一下。等你烧录完把BOOT0拉回低电平再复位一次程序就能正常跑了。这里有一个容易忽略的硬件细节BOOT引脚是在复位释放瞬间被采样的采样完成后即使BOOT0电平变化也不会影响本次已经确定的启动路径。所以你在操作时可以先设置BOOT0再按复位键顺序别反。对于STM32F4系列逻辑其实是类似的。F407的BOOT0在低电平时从主Flash启动BOOT0为高电平、BOOT1为低电平时从系统内存启动BOOT0和BOOT1都为高电平时从SRAM启动。F4系列的BOOT1是PH5在LQFP100封装中可能未引出这在实际使用时需要留意有些封装并没有把BOOT1引出来这种封装上可能已经内部默认接低了因此只能通过BOOT0来切换主Flash和系统内存。2.2 新老系列的区别选项字节时代的到来如果只做F1和F4了解引脚组合就够了。但如果你用了L4、F7、H7、G0这些较新的系列情况就稍有不同——这些芯片不一定有BOOT1引脚甚至有的封装的BOOT0也没引出来。这时候启动模式的选择逻辑改成了“引脚电平 选项字节Option Bytes”的联合判断。具体来说新系列的选项字节中有一个nBOOT0位和一个nBOOT1位。nBOOT0可以取反BOOT0引脚的电平nBOOT1则用来在BOOT0条件满足时决定是进入系统内存还是SRAM。某些芯片还有nSWBOOT0位当它置1时BOOT引脚电平直接被忽略启动源完全由选项字节里的配置决定。这意味着你可以通过软件设置选项字节让芯片在下一次复位后直接进入Bootloader而不需要碰任何引脚。实际产品设计里这个特性非常有用。很多量产的板子为了节省空间或者防误触根本不会把BOOT引脚引出来那么出厂前就可以通过调试接口先把选项字节写好之后就能远程控制启动路径。这也是AN2606在最近几个版本里加入大量选项字节说明的原因。不过老工程师看到这里可能会笑选项字节配置错了怎么办那就成一个很尴尬的状态——芯片既不从Flash启动也进不了Bootloader。所以我的建议是在没有十足把握的前提下新手还是优先用引脚方式切换启动模式选项字节这种东西等你有大量同型号芯片再折腾。2.3 系统内存里的Bootloader到底能干什么搞清楚如何进入系统内存接下来最重要的问题就是进去了以后能干什么答案是通过Bootloader支持的通信接口对主Flash进行读写、擦除、校验以及读写选项字节甚至可以读取芯片的版本信息和UID。以STM32F1系列为例出厂Bootloader支持USART1大容量的型号还支持CAN2和USB DFU。STM32F4系列Bootloader支持的接口更多一些除了USART1/2/3还支持USB DFU部分型号支持CAN2。L4、G0这些系列还能通过I2C和SPI烧录。H7系列则增加了FDCAN等接口。从AN2606的表格中可以看到每一个接口都有对应的引脚定义。比如F103的USART1 Bootloader固定使用PA9TX和PA10RX连接时注意要与USB转串口模块交叉相连——PA9发出去接对方RXPA10收进来接对方TX。引脚不要接反这是最常犯的第一个错误。Bootloader支持的操作指令是一个基于命令行的协议具体定义在配套的应用笔记AN3155USART协议、AN3156USB DFU协议、AN4221I2C协议、AN4286SPI协议等文档里。AN2606是总览AN3155这些是细分协议。实践中你一般不需要自己实现这套协议因为ST官方的STM32CubeProgrammer已经把这些协议封装好了。3. 实操通过系统内存启动模式烧录固件3.1 硬件连接与BOOT引脚设置进入系统内存启动模式的操作流程不复杂但每一个细节都值得认真对待。以最常见的F103最小系统板为例完整流程如下准备一套USB转TTL模块比如CH340或者CP2102几根杜邦线一块F103核心板。先把核心板上的BOOT0跳线帽或者排针接到3.3VBOOT1保持接地F103的BOOT1是PB2如果引脚没引出很多核心板已经默认拉低。然后用USB转TTL连接PA9、PA10模块的RXD接芯片的PA9TX模块的TXD接芯片的PA10RX最后共地。注意共地这一步绝对不能省。接好线后给板子上电或者按一次复位键。此刻芯片已经从系统内存启动UART的Bootloader正在等待通信。这时候打开串口助手用8E18个数据位、偶校验、1个停止位的格式波特率先设成115200发送一个0x7F字节正常的话会收到一帧应答。这里的0x7F是Bootloader的自动波特率检测命令。Bootloader拿到这个字节后会计算准确的波特率并返回状态码。如果你用的是一个支持十六进制发送、又能解析回包的串口工具整个过程会非常直观。需要说明的是如果你用普通串口调试助手直接发0x7F看到回包不一定能识别成“成功”因为Bootloader回应的是协议帧不是一个可读字符串。这里更推荐直接用STM32CubeProgrammer它的“UART”模式自带协议解析不需要手动发字节。3.2 使用STM32CubeProgrammer走一遍完整烧录流程STM32CubeProgrammer是ST官方力推的烧录工具用来替换老旧的ST-LINK Utility和Flash Loader Demonstrator。我用它做过几十块板子的批量烧录稳定性很好。以下是UART启动模式烧录的完整操作打开STM32CubeProgrammer右侧选择“UART”连接方式选择对应的串口号波特率保持默认的115200即可。然后点击“Connect”。如果连线正确、BOOT0已经拉高并复位过软件会识别出芯片型号并显示当前Flash的大小、版本等信息。连接成功后先点击左侧的“Erase”对全片进行擦除。之所以建议先擦除是为了避免旧固件残留导致跳转异常。擦除完成后回到“Programming”选择要烧录的.hex或.bin文件填写烧录起始地址。注意bin文件必须指定起始地址一般F1/F4写0x08000000hex文件自带地址信息不必手工填写。点“Start Programming”进度条走完后断开连接。然后把BOOT0跳线帽恢复到接地一侧按复位键芯片就从主Flash启动了。如果此时程序还不运行问题多半出在选项字节或者启动引脚上具体排查看下一节。整个流程看似很简单但有一个容易出问题的地方在擦除或者编程过程中千万不要断电也不要断开串口线。UART Bootloader是在主机和芯片之间一帧一帧交互的中途断掉Flash可能停留在半擦除状态芯片会变得看似“砖”了一样。这时候再重新进Bootloader全片擦除一次基本能缓过来。3.3 UART Bootloader的协议细节与参数设置很多人问为什么AN2606里说USART Bootloader要选偶校验但STM32CubeProgrammer里好像没有“校验位”这个选项答案是工具自动处理了。STM32CubeProgrammer在做UART连接时会自动把串口配置为8E1你不需要手动干预。但如果你要自己写一个上位机或者用脚本调用就务必按照8E1来配置。USART波特率方面Bootloader支持自动波特率检测范围通常在1200bps到115200bps之间部分系列支持到更高。我实测下来115200最稳通信效率也够高。如果你的板子用的是劣质晶振波特率漂移大了可能导致握手失败这时候可以把波特率降到9600再试成功率会显著提升。握手细节也值得多说一句芯片复位并进入Bootloader后它会等待接收0x7F。收到0x7F后完成波特率校准然后回发ACK字节0x79甚至有一个0xF1字节反馈版本信息表示“我准备好了”。之后的数据帧格式大多是“命令字节 命令字节取反”比如GET命令就是0x00 0xFF读Flash命令是0x11 0xEE写Flash命令是0x31 0xCE。简单来说这是一种带校验的简单协议保证命令完整性。如果你不想用现成工具而是想用Python写一个最小bootloader烧录程序那AN3155就是你必然要读的文档。AN2606负责告诉你接口和引脚AN3155负责告诉你字节流格式。两篇配合起来才能手工实现底层的烧录逻辑。3.4 通过USB DFU模式启动除了串口另一条常用的系统内存启动路径是USB DFUDevice Firmware Upgrade。带USB功能的STM32芯片比如F4系列带USB OTG的型号或者F0系列带USB外设的型号在从系统内存启动时USB接口会枚举成一个DFU设备。电脑上不需要装驱动直接用STM32CubeProgrammer的USB模式连接就能像串口一样擦写Flash。使用DFU模式的好处是速度快而且不用额外接串口线。但不是所有STM32都支持USB DFU必须看AN2606。还要注意DFU模式下USB D引脚上通常需要接一个上拉电阻用于设备枚举。虽然很多核心板内置了但如果你是自制板子记得确认这部分硬件。在实际项目里我发现DFU模式特别适合做现场升级——只需要一根USB线不需要拆机箱不需要动BOOT跳线只要芯片里预先烧录了一小段跳转Bootloader的代码就能在运行状态切到DFU。这种模式在消费类产品和便携设备里尤其常见。4. 常见问题与排查技巧实录4.1 Bootloader进不去怎么办这是遇到最多的情况BOOT0拉高了也复位了但STM32CubeProgrammer就是连不上。排查思路从硬件到软件一条条过首先检查引脚。F103用USART1那么PA9和PA10是否与其他外设冲突如果板子上有别的器件把PA9/PA10复用成了别的功能比如RS485芯片把收发方向控制占用那么Bootloader通信会直接失败。最稳妥的办法是自制测试板时要把USART1 Bootloader当作“唯一确定能用的通道”来设计不要用跳线让PA9/PA10和别的芯片共用。其次检查BOOT0采样电平。BOOT0要在复位释放瞬间处于高电平。如果你是用杜邦线直接飞线线比较长且接触不良可能导致采样时BOOT0还是低电平。有时候多按几次复位键或者把板子断电重上电会比只按复位键更有效——因为某些板子的复位电路有RC延时电源刚上电时BOOT引脚可能还没稳定。还有一种情况是最容易忽略的芯片长时间处于低功耗模式。如果有外部看门狗在复位后短时间内把芯片拉死或者代码设置了RDP保护Bootloader也会进不了。这时先检查选项字节读保护级别如果RDP已经是等级1或等级2行为会不同。RDP为等级1时Bootloader还能通过全片擦除解除保护但RDP为等级2时芯片基本就“锁死”了只能换片。所以千万不要在没有明确把握的情况下设置RDP等级2。4.2 连接成功但烧录失败如果工具已经识别出芯片却在擦除或编程环节报错最常见的原因有两个。一是芯片的Flash写保护。很多新系列STM32出厂时选项字节里的写保护可能不是默认的0或者上一手测试把写保护打开了。此时先进入选项字节页面把写保护位全部清掉再回来擦写。二是供电电压不稳定。Bootloader对Flash进行擦写时内部电荷泵会消耗较大电流如果板子的LDO余量不足导致VDD在擦写瞬间跌落烧录就会中途失败。这个问题在电池供电或者用劣质USB转串口模块供电时尤其明显。实测数据F103擦写一片Flash瞬时电流峰值可以达到数十毫安核心板自带的LDO一般没问题但如果你用ST-LINK的3.3V输出给目标板供电同时又接了其他外设就要小心了。最好用独立供电共地即可。4.3 烧录完成程序不运行的常见套路烧录过程显示100%成功但重新上电以后程序就是没跑起来。这种情况多半不是烧录本身的问题而是启动源又回到了系统内存或者SRAM。先回忆一下BOOT0是不是已经恢复为低电平如果BOOT0还接在高电平复位后芯片当然会再次进入Bootloader而不是执行Flash里的App。很多人在测试台上用飞线连接BOOT0烧录完忘记换线就会反复出现“烧进去了但程序不跑”。除此之外检查启动地址是否正确。如果你烧的是bin文件并且起始地址填成了0x08008000假设前面预留了Bootloader区域而你的App本身又不是为这个地址编译的那么跳过去就是一堆乱码。这个属于工程层面的配置问题AN2606帮不了你但排查时不要忽视了。还有一类情况程序本身在main里死循环或者初始化外设失败导致表现像是“没烧进去”。这种问题需要用调试器看PC指针跑到哪里或者用串口打印输出判断。千万别把一切锅都甩给Bootloader。4.4 读保护与芯片锁死的应急处理开发过程中经常有人不小心把读保护RDP设成异常级别。RDP等级1时调试接口连接会受限Bootloader访问Flash也会受限但至少可以通过选项字节修改把它降回0。RDP等级2就麻烦了它是永久性的芯片直接变成“一次性”。ST之所以这么做是为了防止固件被非法提取对开发者来说这就是一把双刃剑。如果芯片还能通过ST-LINK连接并且只处于RDP等级1可以用STM32CubeProgrammer选择“Option Bytes”把Read Protection改成“AA”或者“Disable”执行并复位芯片就会解除保护不过会顺带全片擦除。这个操作等于“恢复出厂设置”。如果芯片处于RDP等级2或者JTAG/SWD引脚全部被禁用没有任何调试接口能连上那唯一的希望就是看芯片有没有别的启动路径。如果这款芯片还支持从SRAM启动而且里面恰好有一点你自己写的RAM程序那还有救。否则就只能换新芯片了这块片子的Flash被永久锁定。我在一个量产项目里一次误配了10片F405的RDP2当场报废教训非常深刻。5. 系统内存启动模式在工程应用中的三个典型场景5.1 量产烧录产线工装的关键通道量产阶段最忌讳的是每台设备都用ST-LINK加IDE来回点按钮。效率低、不稳定、还容易出错。比较成熟的方案是在产线上准备一台工装电脑和几个USB转TTL模块把目标板的BOOT0引脚做成测试点用夹具或者顶针压住BOOT0到高电平然后批量跑一个烧录脚本。烧录脚本可以基于STM32CubeProgrammer的命令行接口也可以自己用Python和pyserial走一遍AN3155协议。命令行接口最简单的用法是STM32_Programmer_CLI -c portCOM10 -e all -w app.hex -v -rst这条命令的意思是通过COM10连接先全片擦除写入app.hex校验并复位。产线上只需要把串口号动态配置一下就能实现自动烧录。用系统内存启动配合串口烧录比SWD烧录的最大优势是不需要调试器硬件成本只要一个几块钱的USB转TTL芯片即可。这在低成本量产工装里非常实用。5.2 配合自定义IAP实现远程升级我们知道Bootloader本身支持通过串口写Flash那为什么很多产品还要再写一个用户自己的IAP Bootloader原因很简单出厂ROM里的Bootloader是固定的进它的条件需要外部引脚或者选项字节不适合在已经部署的设备里远程切换。常规做法是用户Flash的最前面一个扇区放置一段自己写的IAP代码。App运行时如果收到远程升级指令先把升级包存到外部Flash或RAM然后跳转到IAP。IAP通过UART、SPI、CAN、Wi-Fi链路把升级包写入App区域再跳回App。这套架构有一个前提IAP本身不能写坏否则设备就变砖了。但如果IAP区域也损坏了怎么办这时系统内存Bootloader就成了第二级备份。只要硬件上BOOT0还能被触发产线或者售后人员就能强制进入ROM Bootloader把整个Flash重新擦写一遍。这就是我常说的“双重保障”用户IAP负责远程升级系统内存Bootloader负责极端情况恢复。在任何量产产品里我强烈建议保留这个恢复通道。5.3 变砖恢复最后的救命稻草很多初学者手里都有一两块“变砖”的板子。其实绝大多数“变砖”都是软变砖用系统内存启动模式都能救回来。常见的场景包括不小心把系统时钟配置错了导致程序一直卡在时钟初始化IDE连不上或者把某个引脚复用成JTAG导致SWD调试口被禁用又或者升级过程中断电Flash里的一半数据是旧的、一半是新的程序跳转时跑飞。这类问题有一个共同点芯片本身没有硬件损坏只是Flash内容不对。只要能用Bootloader全片擦除再重新烧录一份好固件电路板就原地复活。最后再提一句系统内存启动模式本身不依赖用户代码也不依赖调试接口所以它是在任何恶劣情况下都能兜底的通道。我自己处理过的绝大多数“砖头”板子最后都是靠拉高BOOT0、串口全片擦除、重新烧录这三板斧解决的。所以如果你现在正对着一块连不上调试器的STM32发愁不妨先试试这条最传统、最稳定、也最容易被人忽略的启动路径。
返回列表