ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Keil MDK集成STM32CubeProgrammer:命令行烧录与外部Flash配置实战

2026/8/30 1:45:29 拓冰建站 浏览量
Keil MDK集成STM32CubeProgrammer:命令行烧录与外部Flash配置实战 前言里先说清楚一件事LAT1187这个编号在ST工程师圈子里常被当成“在Keil里用STM32CubeProgrammer烧录”的缩影。很多人看到标题会愣一下Keil里不是早就配了Flash Download吗为什么还要折腾STM32CubeProgrammer但如果你的项目涉及STM32H7的外部Flash、读保护等级设置、OTP烧写或者只是单纯觉得Keil默认的烧录校验不够直观那这个笔记就正好戳中痛点。这篇内容我按照自己实际踩过的坑整理从方案选型到命令行配置再到接线、日志、外部Loader尽量讲透适合正在用Keil MDK做STM32开发、同时想用好STM32CubeProgrammer的工程师。1. 为什么要在Keil里调用STM32CubeProgrammer1.1 Keil默认烧录方式的局限Keil MDK默认的烧录流程是借助Debug选项卡里配置的调试器常见的J-Link、ST-Link CMSIS-DAP、ULINK以及Flash Download选项卡里的Download Function和Programming Algorithm。这套流程在日常开发里完全够用编译完按一下F8代码就进去了。但它有几个先天限制烧录算法FLM文件由Keil的Pack管理一旦芯片型号比较新或者外部Flash型号不在算法列表里就得手动找FLM放到Keil安装目录的Flash文件夹下折腾不说还容易版本不匹配。Keil的烧录过程不会帮你设置RDP读保护等级也不会帮你烧OTP区域更不会智能处理H7系列的双Bank启动。如果代码里用了外部QSPI FlashKeil默认配置根本烧不进去必须在Flash Download里单独加外部算法还要保证地址范围没错这步出了错报错信息还特别隐晦。这些场景下STM32CubeProgrammer反而更适合做烧录主工具而Keil只负责编译。所以这篇笔记的核心思路不是让你把Debugger换成CubeProgrammer因为Keil的调试器选项里根本没有它而是用它替代Flash Download那一环让Keil编译完以后自动把固件交给CubeProgrammer去写。1.2 STM32CubeProgrammer独有的硬核能力STM32CubeProgrammer相比Keil的烧录功能最值钱的能力包括四个第一外部Flash的加载器支持非常完善。官方提供了一堆.stldr加载器文件可以直接把固件写到外部QSPI、OSPI甚至HyperFlash上地址映射、初始化时序都帮你封装好了。Keil要配这个得先确认FLM对应型号还要自己维护Flash大小和起始地址稍不留神就白屏。第二可以对芯片做安全级别的操作。比如把RDP等级从0调到1或者2通过命令一条搞定。Keil里你想做这些要么用ST-Link Utility这种老工具要么写一堆脚本远没有CubeProgrammer来得干净。第三命令行接口做得非常完整。GUI能干的事CLI几乎全都能干。这正好适合嵌入到Keil的After Build/Rebuild钩子里实现“编译完自动烧录”的工作流。第四它对ST-Link固件的适配比较统一。只要ST-Link驱动正常不管你是老款的ST-Link/V2还是板载的ST-Link/V3-ISOCubeProgrammer都能识别不会出现Keil里“No ST-LINK detected”这种让人摸不着头脑的情况。1.3 典型使用场景我归纳了三个最常走这条路的场景你可以对照一下自己是否中招场景ASTM32H750VBT6这种内部Flash只有128KB的芯片代码稍微一膨胀就放不下于是把代码放到外部W25Q64上。这时Keil内部Flash烧录还正常外部Flash就完全交给CubeProgrammer通过After Build命令自动烧录外部loader和目标固件。场景B产品需要批量设置RDP等级防止别人把固件读出来。Keil没这个能力但CubeProgrammer一条命令搞定。你在Keil里编译完它自动帮你把Flash锁上非常顺手。场景C你正在调试串口ISP烧录流程需要让上位机先去拉低BOOT0再通过USART写入固件。这个流程用CubeProgrammer的CLI就能做Keil里只是调用它不需要你手动切换软件。这些场景共同点是Keil负责“编译工程”这件事STM32CubeProgrammer负责“把固件放进芯片”这件事各干各的互不干扰但通过After Build钩子串在一起后用户体验又跟以前一样流畅。2. 整体方案构建后自动调用CLI2.1 先看清两种联动方式的差异有人会觉得直接用STM32CubeProgrammer GUI打开hex手动烧不就行了为什么要折腾Keil手动烧一次两次可以但如果你要反复改代码、频繁烧录手动操作就会成为开发节奏的瓶颈。而且手动模式下每次都要关心hex文件有没有重新生成、路径对不对容易漏。另一方面Keil支持的联动方式其实有两种方式一在Options for Target的User选项卡里配置After Build/Rebuild命令让编译完成后自动执行一条命令行。方式二编译后不自动烧录而是生成hex/bin文件再由外部脚本或者你手动打开CubeProgrammer烧录。方式一的自动化程度最高也是这篇笔记的重点。方式二适合做量产工具、测试工装这类场景因为你需要把烧录过程单独拎出来给产线用不能依赖Keil。这两种方式的取舍核心看你在什么阶段开发调试期用方式一省心小批量生产或验收检测期用方式二干净。2.2 准备好STM32CubeProgrammer命令行环境先把前提条件准备好。STM32CubeProgrammer装完以后CLI工具的默认路径是C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\STM32_Programmer_CLI.exe建议第一步就是把这个bin目录加进系统环境变量PATH里不然每次在Keil命令里写一长串绝对路径看着头疼。加完PATH后重新打开Keil让它重新读取环境变量。验证方式很简单打开命令行输入STM32_Programmer_CLI.exe --help能正常打印一堆参数说明就说明环境OK。如果提示找不到命令多半是PATH没生效重新启动终端或者检查路径是否写错。这里提醒一个容易忽略的点STM32CubeProgrammer需要通过ST-Link连接目标板ST-Link的驱动一定要装好。很多时候CLI提示连接失败不是命令问题是驱动被USB电源管理策略给挂起了。Windows设备管理器里看到STM32 STLink带着黄色感叹号先去重装驱动别急着改命令。2.3 Keil输出文件配置生成hex/bin不管哪种方式前提是Keil必须生成可烧录的文件。大部分人的习惯是只生成axf配合Keil自己的调试器没问题但CubeProgrammer不认识axf它需要hex或者bin。所以先打开Options for Target - Output勾上Create HEX File。这一步不做后面After Build命令就算写了也白写因为找不到hex文件。另外如果你想生成bin文件Keil默认是不生成的需要在After Build里用fromelf命令转换。比如fromelf --bin --output .\Build\app.bin .\Build\app.axf这个命令我建议放在烧录命令之前。因为有些场景下ST-Link或者外部Flash loader对hex格式的处理有兼容性问题直接烧bin反而更稳。我个人在H750贴片外置Flash的项目里就是烧binhex文件给客户看代码时再给。输出文件路径要统一管理。我在工程模板里习惯专门建一个Build文件夹axf、hex、bin都往那里放脚本里引用路径时不会因为在不同目录而迷路。3. 实操从零配置Keil的After Build命令3.1 写好第一个“编译完自动烧录”命令打开Keil工程进入Options for Target - User选项卡在After Build/Rebuild栏下面找到Run #1。这一行就是编译成功后会自动执行的命令。先把最简单的一条测试命令填进去STM32_Programmer_CLI.exe -c portSWD modeUR resetHWrst -w .\Build\app.hex -v -rst逐段说一下参数含义-c是连接芯片。portSWD表示通过ST-Link的SWD口连接。如果你用的是JTAG模式改成portJTAG但SWD足够用了占用的引脚也少。modeUR表示连接时使用Under Reset模式也就是在复位状态下建立连接防止芯片内部程序把调试口复用了导致连不上。resetHWrst表示复位方式为硬件复位。如果你的板子ST-Link的NRST引脚没有连接这里可以改成modeHOTPLUG热插拔模式不再依赖复位引脚。-w后面跟要烧录的文件路径这里我用的是相对路径.\Build\app.hex但要注意Keil执行命令时的工作目录未必是工程目录。保险起见我推荐在Run #1里调用一个批处理脚本脚本用%~dp0定位自身所在目录这样路径永远是对的。-v表示烧录完成后校验建议不仅加上而且别省略。-rst表示烧录完成且校验通过后自动复位芯片运行程序。测试这条命令时建议先只勾选Run #1不要勾选Run #2避免出问题时分不清是哪条命令引起的。3.2 批处理脚本让命令更健壮直接写在Keil的Run #1里适合命令特别简单的情况。但实际项目里命令会越来越长比如要同时烧外部loader、设置RDP、打印日志写在一起既难看也难排查。我的习惯是把所有逻辑写进一个build_and_flash.bat脚本放在工程根目录的Tools文件夹里然后在Keil的Run #1里只留一行$(ProjectDir)Tools\build_and_flash.bat $(ProjectDir)脚本大致长这样echo off setlocal set PROJ_DIR%~1 set CLIC:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\STM32_Programmer_CLI.exe set LOG%PROJ_DIR%Build\flash_log.txt %CLI% -c portSWD modeUR resetHWrst -e all -w %PROJ_DIR%Build\app.hex -v -rst %LOG% 21 if %errorlevel% neq 0 ( echo ---- STM32CubeProgrammer failed ---- type %LOG% exit /b 1 ) echo ---- STM32CubeProgrammer flash OK ---- type %LOG% endlocal脚本里我加了-e all意思是烧录前先整片擦除。对于大多数STM32这么做虽然慢一点但能避免某些段没有被正确覆盖导致的老程序残留问题。为什么要把日志重定向到文件再type出来因为STM32CubeProgrammer CLI默认会打印到标准输出但在Keil的Build Output窗口里这条命令输出并不总是完整显示而且如果命令执行失败Keil只会报一个笼统的“User command exited with code X”原因被吞了。重定向到log再用type打印出来就能看到具体的失败原因。还有一点如果脚本执行失败一定要exit /b 1让Keil认为编译后命令执行失败。这样你在编译输出窗口里能第一时间发现问题而不是稀里糊涂以为烧录成功了。3.3 没有ST-Link时串口ISP模式也能用前面说的都是SWD连接但STM32CubeProgrammer还支持UART串口ISP烧录。这个模式在批量产线或者板子调试口被焊死时特别有用。关键配置STM32_Programmer_CLI.exe -c portCOM8 br115200 -w app.hex -v -rstportCOM8是串口号br115200是波特率。实际使用时要先把BOOT0引脚拉高让芯片进入系统存储器BootLoader模式再上电或复位。这一套流程已经有人把它集成到自动测试治具里Keil编译完自动切BOOT0、自动烧录、自动恢复Program模式全程无人值守。需要注意串口ISP对波特率很敏感尤其是外部晶振频率不准的时候115200可能会失败降到9600往往就好了。所以如果批量产线上出现几块板子连不上先排查晶振和BOOT引脚别急着怀疑固件。4. 外部Flash场景这招才是真正的刚需4.1 为什么Keil烧外部Flash总翻车STM32H7系列的高性能型号很多都支持外部Flash映射执行也就是XIP。程序放外部QSPI Flash上电后通过Memory-Mapped模式直接跑片内Flash反而只放BootLoader。这种架构的好处显而易见外部Flash便宜、容量大代码随便放。但Keil的默认Flash Download算法里并不包含外部Flash型号。哪怕你用STM32CubeMX生成了工程Keil里也要手动加FLM文件地址范围要和实际Flash大小完全匹配。很多人的翻车现场是算法加好了、地址也填对了烧录时却发现Keil根本不执行外部算法的初始化或者校验时老报“Verify Failed”。STM32CubeProgrammer处理这个问题的思路简单粗暴它不依赖Keil的FLM而是通过官方或第三方提供的.stldr外部Loader文件来连接外部Flashloader里包含了所有初始化时序。4.2 在自动烧录命令中加载外部Loader假设你的工程里app.bin是放到外部QSPI Flash的固件外部Flash型号的loader文件是MX25LM51245G_STM32H750B-DISCO.stldr那么完整的烧录命令是STM32_Programmer_CLI.exe -c portSWD modeUR resetHWrst -el C:\path\to\MX25LM51245G_STM32H750B-DISCO.stldr -w .\Build\app.bin 0x90000000 -v -rst这里比普通烧录多了一个-el参数后面跟外部Loader文件路径-w的烧录地址变成了0x90000000这是H750外部Flash映射地址。这个地址对应的是QSPI的Bank1区域需要和你实际硬件上Flash的片选、映射方式匹配。要注意外部Loader文件路径里带中文或者空格时命令很容易解析出错。我的建议是把所有工具链、工程路径统一放到纯英文路径下尤其是自动化脚本路径里的一个空格能让整个命令变得莫名其妙。烧录前最好先做一次外部Flash的擦除。可以用STM32_Programmer_CLI.exe -c portSWD modeUR resetHWrst -el C:\path\to\loader.stldr -e all也可以在-w参数前加-e all一起执行。先擦后写可以避免外部Flash里残留旧数据的边界问题这个习惯建议从头养成。5. 常见问题与排查技巧实录5.1 连接失败Error: Connection error这大概是出现频率最高的问题。CLI提示连接失败可能的原因有好几个ST-Link驱动没装好设备管理器里看STLink有没有感叹号。芯片进入了低功耗模式或者SWD引脚被复用解决办法是用modeUR强制连接确保复位引脚连到ST-Link。目标板供电不稳定CubeProgrammer对供电异常比较敏感外接电源同时插ST-Link供电时电平可能被拉得很低。ST-Link固件版本过旧可以打开STM32CubeProgrammer主界面在固件升级页面升级ST-Link固件再把CLI重试。我的排查顺序是设备管理器 - 换一个ST-Link - 改modeUR - 测NRST接线。多数情况下问题出在驱动或复位引线。5.2 烧录后校验失败Error: File download complete, verification failed校验失败意味着数据写进去了但读出来对不上。这种情况最常见于外部Flash的时序或者地址边界问题。先排查烧录地址。比如外部Flash实际只有2MB你把bin烧到0x90200000那就超了。再检查Loader型号是否匹配W25Q64和W25Q128的指令集大体兼容但擦除扇区大小、状态寄存器细节可能不同最好严格匹配型号。最后用-v校验之前先手动读一次外部Flash前64字节和bin开头对比确认loader读出来的是正常的。如果是内部Flash校验失败先看是不是Flash读保护开了。RDP等级一旦不为0内部Flash的内容就无法通过调试口完整读取校验自然失败。5.3 Keil输出窗口看不到烧录日志Keil的Build Output窗口对用户命令的输出显示非常吝啬经常只显示命令本身看不到STM32CubeProgrammer的完整打印。这个问题我在前面批处理脚本里已经给出了方案把CLI输出重定向到一个log文件然后让脚本把log内容type出来。另外Keil执行用户命令时有个超时设置虽然默认值一般不碰但如果烧录大文件加上低波特率串口可能命令还没跑完就被Keil判超时。这个在Options for Target - Utilities里没有直接选项需要关注一下脚本总执行时间必要时分两条命令拆开执行或者降低校验压力比如去掉-v。5.4 Keil自带的Flash Download报错No Algorithm found这其实不是STM32CubeProgrammer的问题而是很多人还在用Keil默认烧录时的经典报错。比如新拿到的H7芯片Keil Pack里还没有对应的FLM算法就会报这个错。既然你用STM32CubeProgrammer烧录这个报错就可以彻底绕开。操作很简单在Options for Target - Utilities选项卡里把Download Function改成“Use External Tool for Flash Programming”并不存在但你可以干脆不用Keil的Flash Download把Debugger设置里的Download选项取消勾选所有烧录都交给After Build命令去执行。这样Keil只负责编译和调试不负责烧录No Algorithm这类的烦恼就消失了。如果你需要保留Keil的Debugger在线调试功能比如打断点、看变量那么注意Debugger连接时依然会使用CMSIS-DAP/J-Link此时它和CubeProgrammer并不是同一套烧录链路。也就是说你可以用CubeProgrammer把固件烧进去再用Keil的Debugger连接芯片调试二者可以交替使用不冲突。6. 一些额外的小技巧最后分享几个我实际使用中觉得特别顺手的小技巧。第一给CLI命令加上--log参数可以把整个过程输出到log文件方便后期追溯。我自己在项目里固定这么写STM32_Programmer_CLI.exe -c portSWD modeUR resetHWrst -w app.hex -v -rst --log .\Build\flash.log这样即使Keil输出窗口不显示完整日志打开log文件也能看到每一步。很多时候产品出了问题客户说“没烧成功”我第一反应就是翻这个log往往一眼就能定位。第二Keil里的$(ProjectDir)、$(TargetName)这些宏在用户命令里是可用的可以把脚本写得更通用。比如$(ProjectDir)Tools\flash.bat $(ProjectDir) $(TargetName)脚本里接收两个参数工程目录和目标名hex路径自动拼成$(TargetName).hex。这样换工程时不用改脚本只复制脚本就能接着用。第三如果只是偶尔想要手动烧一次没必要打开GUI直接命令行最省事STM32_Programmer_CLI.exe -c portSWD modeUR resetHWrst -w .\Build\app.hex -v -rst甚至可以把它做成一个右键发送到桌面的快捷方式把参数固化在快捷方式的目标里。第四也是最容易被忽略的一点STM32CubeProgrammer的CLI对路径里的反斜杠处理比较敏感。建议在批处理脚本里统一使用正斜杠/或者确保反斜杠后没有意外的转义字符否则你会看到莫名其妙的“File not found”但文件明明就在那里。我在实际项目里把这个After Build联动方案做成了工程模板但凡新项目需要外部Flash或者是安全等级设计要求高的编译完自动烧录日志自动留档连产线上的工程师都说好。希望这篇笔记能帮你少走弯路把这套流程也揉进自己的工具链里。