
上周拿到一块 SR5E1E7 的定制板样板贴完片第一次上电我信心满满地把 ST-Link 接到 SWD 排针打开工程点 Load进度条走了一小截弹出的却是那句让嵌入式工程师头皮发麻的error: flash download failed - cortex-m3。紧接着又是cannot access memory又是erase failed折腾到晚上十点才把程序成功 load 进 FLASH。这个标题看起来像新手提问其实背后藏着一整套关于启动模式、调试链路、Flash 控制器和工具链配合的工程问题。这篇文章就把 SR5E1E7 定制板加载程序到 FLASH 的完整链路拆开讲从硬件连接、IDE 配置、报错排查到无调试器方案全部过一遍适合正在调 SR5E1E7 或类似 MCU 定制板的工程师也适合被各种 flash download 报错折磨的新手。1. 定制板的“烧录拒绝症”先定位到底是哪一段断了1.1 一条完整的烧录链路程序文件要从 PC 进入芯片 FLASH不是简单拖个文件就完事。这条链路通常长这样PC 上的 IDE 或烧录工具通过 USB 连接调试器调试器再把下载算法和程序数据通过 SWD 或 JTAG 送到芯片的调试端口芯片里的 CPU 内核执行一段 Flash 下载算法把数据写入内部 FLASH。任何一环出问题最后都会在 IDE 里变成一句笼统的flash download failed。报错信息里出现cortex-m3很多人第一反应是“芯片型号不对”其实恰恰相反这通常说明调试器已经识别到了目标内核只是 Flash 编程阶段出了问题。这就像一个快递已经送到你家小区门口但快递员找不到具体楼栋所以报“派送失败”。搞清楚这个区别排查方向就不会跑偏。所以第一步永远是确认调试器能不能识别芯片。如果连 IDCODE 都读不到那就是物理链路问题跟 Flash 本身没关系。如果 IDCODE 读到了但 Flash 写不进去那才是配置、地址、算法或芯片状态的问题。这两类问题在下面的章节里会分别展开。1.2 定制板和评估板的差异为什么同一个工程在官方评估板上能烧在定制板上就失败这是很多人的困惑。原因在于评估板帮你把所有“脏活累活”都干完了而定制板把这些变量全部暴露给你对比项官方评估板定制板调试器板载插 USB 即可需外接接线靠自己供电USB 稳压干净可靠LDO 直出纹波和带载未知复位电路已配置 RC 参数可能漏焊、参数错误启动模式跳线帽明确可能悬空或接错SWD 走线专业布线短线优可能过长、过细、受干扰评估板上的板载调试器还承担了供电和电平转换的职责定制板外接调试器时VCC 参考电压、GND 共地、NRST 连接都要自己处理。我之前遇到过一块板子NRST 引脚的电容焊错了容值导致芯片一直处于复位状态调试器死活连不上。这类问题在定制板项目中非常典型不是软件能解决的。1.3 调试器选型与连接拓扑SR5E1E7 这类 MCU 通常支持 SWD 和 JTAG 两种调试接口。我的建议是优先用 SWD只需要两根数据线加一个地定制板布线压力小连接也简单。JTAG 引脚多在引脚紧张的板子上不值得。调试器选择上ST-Link/V2 或 V3 是首选价格便宜官方工具链支持好。J-Link 兼容性最强特别是当你需要在多个厂家的芯片之间切换时。CMSIS-DAP 也能用但驱动和工具链支持相对弱一些。SWD 连接至少要四根线SWDIO、SWCLK、GND、VCC。注意 VCC 的作用是提供电平参考不是给板子供电。NRST 建议也接上某些复位时序问题可以靠调试器的硬件复位来解决。实操中有几个容易踩的坑线序接反SWDIO 和 SWCLK 交叉、忘记共地、SWD 线超过 20 厘米导致信号质量下降。每次换完连接线第一件事永远是重新扫描调试器确认能识别目标芯片再谈烧录。2. 把 SWD/JTAG 链路逐段打通从读 IDCODE 开始2.1 先别急着 Load先确认调试器能看见芯片这是我在排查烧录问题时最强调的步骤。不要一上来就点 Load那样只会得到一句模糊的失败信息。先用调试器工具扫一遍目标用 STM32CubeProgrammer 打开后选择 ST-LINK端口选 SWD点击 Connect。如果能看到芯片的 Device ID 和 CPU 信息说明物理链路已经通了。如果连接失败请先检查SWDIO、SWCLK 是否接反调试器 VCC 检测电压是否符合目标板电平目标板是否真正上电芯片 NRST 是否被拉死用 J-Link 的话可以在命令行里直接连接验证J-Linkconnect DeviceSR5E1E7 Select target interface: S Target interface speed: 4000如果看到Found Cortex-M3之类的输出恭喜你链路通了。如果提示Cannot connect to target那就是上面几个硬件点的问题先把它们解决不要急着进 IDE 里折腾配置。2.2 电源、复位和时钟三个容易被忽略的硬件点连不上目标芯片时很多人会反复换调试器、换软件版本其实大概率是硬件这几个点没伺候好。第一电源。MCU 一般有多个供电域比如 3.3V 主电源和 1.2V 内核电压很多定制板漏焊了内核电压的滤波电容或者 LDO 选型带载能力不足导致芯片上电后不稳定。用万用表量芯片各供电引脚对地电压示波器看纹波确认在规格范围内。第二复位。NRST 在正常工作时应该是高电平如果调试器连上后一直拉低或者板级 RC 电路参数不对导致复位脉冲异常芯片会一直处于复位状态Flash 当然没法操作。测试方法是量 NRST 引脚电压正常应该接近电源电压。第三时钟。很多 MCU 内部有 HSIFlash 下载算法一般用内部时钟就能跑所以晶振问题不一定会导致烧录失败。但如果外部晶振没起振程序烧进去跑起来后访问 Flash 读取指令会失败表现就是能烧录但程序不运行。这一点在定制板上尤其常见检查时用示波器看晶振脚是否有波形。2.3 用 STM32CubeProgrammer 手工连一次我建议所有烧录问题都用 STM32CubeProgrammer 做一次基准测试因为它每一步都能给出明确反馈比 Keil 里那种笼统的弹窗信息友好得多。步骤很直接打开 STM32CubeProgrammer点击右上角 ST-LINK 图标。Port 选 SWDFrequency 先选 800 kHz。点击 Connect能连上会显示 Device ID 和 CPU 信息。如果失败把频率降到 400 kHz 甚至 100 kHz 再试。连上后先 Read 读回芯片信息确认通信稳定。然后 Full chip erase再写入 hex/bin 文件最后 Verify。降低频率这个操作对定制板特别有效。原因很简单SWD 信号在长走线、高寄生电容下容易失真官方评估板的 PCB 布线干净高速没问题定制板就不一定。先用低速确认能烧再逐步提速这是做定制板的基本素养。2.4 命令行烧录绕开 IDE把问题暴露得更清楚有时候 IDE 里报错你根本不知道是 IDE 配置问题还是硬件问题。这时候命令行工具是最诚实的裁判。STM32CubeProgrammer 的命令行版本用法# 连接 SWD不复位 STM32_Programmer_CLI.exe -c portSWD modeUR # 全片擦除 STM32_Programmer_CLI.exe -c portSWD -e all # 写入固件并校验 STM32_Programmer_CLI.exe -c portSWD -w app.hex -v参数说明-c是连接参数modeUR表示下载后不自动复位避免下载算法执行完立刻跑应用导致验证失败-e all全片擦除-w写入-v回读校验。如果你在 IDE 里失败但命令行成功那问题就在 IDE 的 Flash 下载配置上如果命令行也失败那问题在硬件或芯片状态。这个二分法能帮你在十分钟内定位到问题域而不是瞎调各种参数。3. FLASH 地址、选项字节与链接脚本的连锁反应3.1 链接脚本里的 FLASH 地址必须和烧录工具一致调试链路通了烧录工具也能连上芯片了还有一个隐蔽的坑程序被写到了错误地址。SR5E1E7 内部 Flash 的起始地址以数据手册为准常见 MCU 一般从 0x08000000 开始。你需要在三个地方保持地址一致链接脚本、IDE 的 Flash Download 配置、烧录工具里手动指定的起始地址。最常见的问题是工程为了给 bootloader 留空间把链接脚本的 FLASH 起始地址改成了 0x08004000但 Keil 里 Flash Download 页面还是默认从 0x08000000 开始。烧录工具把代码写到 0x08000000程序能写进去但一运行就进 HardFault因为向量表不在芯片启动时默认读取的地址。排查这类问题很简单烧录完成后用 STM32CubeProgrammer 读回 Flash 内容对比 elf 文件里代码段实际地址看是不是对应得上。如果对不上就是地址配置不一致。3.2 选项字节和读写保护芯片“锁死”的原因MCU 的选项字节区域控制着很多行为包括读保护等级 RDP、写保护 WRP。如果你的芯片之前被设置过读保护调试器可能连访问 Flash 的权限都没有如果设置了写保护擦除和编程都会失败。这种情况在反复测试的工程样片上很常见。有同事可能为了做加密测试把 RDP 等级调到了 1然后忘了改回来你拿到的板子就变成“只能看不能写”。处理方式在 STM32CubeProgrammer 里进入 Option Bytes 页面查看 RDP 等级如果显示 Level 1改成 Level 0 然后 Apply。这里要特别提醒RDP Level 2 是不可逆的一旦设置为 Level 2芯片的调试接口和读保护永久锁死只能通过重新擦除整个芯片来恢复甚至可能无法恢复。所以在动选项字节之前先确认你不是在开启 Level 2。3.3 为什么全片擦除会失败erase failed这条报错信息很具有迷惑性它看起来是“擦除功能有问题”实际往往是别的地方出了问题。我整理了一个排查顺序按这个顺序查基本能覆盖绝大多数情况电源带载能力Flash 擦除瞬间电流比正常运行大如果 LDO 输出不够或线路过细电压跌落超过 5% 就会导致擦除失败。写保护选项字节里 WRP 覆盖了目标扇区擦除操作被硬件拒绝。低功耗模式芯片在擦除前进入了睡眠或停止模式Flash 控制器无法正常工作。下载算法不匹配IDE 里选的 Flash 算法与芯片型号不一致比如用错了 Flash 容量参数。连接不稳定SWD 信号在擦除过程中受干扰导致下载算法和调试器之间的通信中断。经验告诉我最常被忽略的是第 1 条。很多定制板用 1117 这类 LDO 供 3.3V擦除瞬间电流一起来电压就往下掉。示波器夹在芯片 VDD 引脚上点一下擦除如果看到明显的电压跌落就是电源问题换低阻供电或加大电容往往就解决了。4. 高频报错逐个拆解从 cortex-m3 download failed 到 OpenOCD server4.1 error: flash download failed - cortex-m3这大概是 Keil 用户最熟悉的报错之一。字符串里的cortex-m3是调试器识别到的内核名这本身不是错误它说明连接阶段已经通过问题出在后续的 Flash 编程阶段。排查顺序在 Keil 的 Options for Target - Debug - Settings 里看 SW Device 区域如果列出了 Cortex-M3 并显示 ID Code说明连接没问题。检查 Flash Download 页面看 Programming Algorithm 是否包含了对应芯片的 FLM 文件起始地址和容量是否填对。很多情况下这里会残留默认的 Flash 算法和实际芯片不匹配。把 Download 选项里的 Erase Full Chip 改成 Erase Sectors有时候全片擦除时间太长会触发调试器超时。降低 Debug 设置里的 SW 时钟频率。还有一个容易忽略的点如果你同时开着多个调试器工具比如 STM32CubeProgrammer 和 Keil它们会争抢调试器资源。以前遇到过一次诡异的失败最后发现是 CubeProgrammer 还开着连接把调试器占用了。关掉所有调试工具只留一个再试。4.2 cannot access memory / target dll has been cancelledcannot access memory这个报错比上面那个更底层它表示调试器虽然连上了 CPU但访问某个内存地址时没有收到有效响应。常见原因访问了不存在的地址空间比如链接脚本把 RAM 起始地址写错。芯片进入了低功耗模式调试时钟被关闭此时访问 Flash 和 RAM 都无响应。芯片电压过低Flash 读取不稳定。另一类报错target dll has been cancelled更像软件问题和硬件关系不大。常见于系统里安装了多个调试器驱动或不同版本的 KeilDLL 冲突导致目标访问被取消。处理方式卸载多余调试驱动重装 Keil别用 USB Hub 连接调试器直接插主板 USB 口。4.3 erase failed! cannot access memory internal command error flash download fai这条报错在串口烧录和部分命令行工具中比较常见erase failed和cannot access memory同时出现说明擦除动作已经发起但 Flash 控制器没有正确响应。我的经验是这种情况优先怀疑电源和复位。一个真实的排查案例板子用 12V 转 5V 再转 3.3V 的两级供电5V 和 3.3V 之间的走线很长。烧录小固件没问题但擦除大扇区时必现erase failed。用示波器一量擦除瞬间 3.3V 跌到 2.9V超过规格。加了两个 100uF 电容在芯片电源脚附近问题消失。所以碰到这种组合报错先看示波器再看配置不要闷头改代码。4.4 cant perform jtag flash, because openocd server is not running!如果你在 VSCode 或 Eclipse 里用 OpenOCD 调试和烧录这个报错的意思很直白OpenOCD 服务器进程没有运行或者运行了但客户端无法连接。排查顺序看一下后台进程确认 openocd.exe 是否在运行。有时候配置错误会让 OpenOCD 启动后立刻退出你根本不知道。检查端口占用OpenOCD 默认监听 3333如果被别的进程占用客户端连不上。确认配置文件里 Flash 相关的flash bank命令是否正确。如果 OpenOCD 不认识 SR5E1E7 的 Flash 控制器它会回退到用普通内存写方式或者直接报错。在终端手动启动 OpenOCD看输出日志有没有红色错误这是最直接的排查方式。OpenOCD 配置示例示意具体以实际芯片为准source [find target/swj-dp.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME sr5e1e7 } transport select swd adapter speed 1000 # 这里需要按实际 Flash 控制器类型配置 flash bank internal_flash stm32f1x 0x08000000 0x100000 0 0 0注意flash bank里的驱动名称要与你芯片实际的 Flash 控制器匹配用错驱动会导致“能连接但擦除失败”的诡异现象。5. 没有调试器怎么办UART bootloader 与分区升级方案5.1 Boot 引脚和启动模式不是所有场景都有调试器可用。批量生产、现场维护、样机分发这些时候用 UART 串口烧录更实际。绝大多数 MCU 出厂时内置了一段系统 bootloader通过 BOOT 引脚的电平组合选择从系统 bootloader 启动。SR5E1E7 这类 MCU 的 BOOT 引脚配置要参考数据手册但工程实践上的思路是一致的断电把 BOOT 引脚设置成指定电平上电芯片就进入 bootloader 模式等待从 UART 接收固件。这里有一个定制板特别容易踩的坑画 PCB 时没有把 BOOT 引脚引出来或者只引了但没做上拉/下拉电阻导致生产时无法进入 bootloader 模式只能开盖飞线。我的建议是定制板上至少留一组 BOOT 跳线或 0 欧电阻焊盘这是成本最低的保险措施。5.2 用串口和官方烧录工具下载固件以 STM32CubeProgrammer 的 UART 模式为例完整流程如下断电把 BOOT 引脚设为从系统 bootloader 启动。用 USB-TTL 模块连接芯片的 UART TX、RX、GND注意 RX 接 TX、TX 接 RX很多新人第一次在这里接反。确认 USB-TTL 和板卡共地否则通信会各种乱码。上电。运行命令STM32_Programmer_CLI.exe -c portCOM3 -w app.bin -s 0x08000000 -v参数-c portCOM3指定串口号-w写文件-s指定写入起始地址-v回读校验。如果连接失败优先检查 USB-TTL 的驱动是否安装、串口号是否正确、RX/TX 是否交叉。波特率方面默认 115200 通常没问题但如果你的板子时钟不准确晶振偏差大可以降到 9600 提高稳定性。5.3 先烧 bootloader再做应用分区如果产品有现场升级需求串口 bootloader 烧录还有一个更优雅的变体先用调试器或串口烧录一个自定义 bootloader之后的应用升级完全通过 bootloader 接收协议完成不再依赖系统 bootloader 的固定协议。这个方案的核心是 Flash 分区。典型布局区域起始地址大小内容Bootloader0x0800000032 KB启动/升级程序App0x08008000剩余用户应用升级标志App 尾部4 B保存升级请求标记应用里需要设置中断向量表偏移SCB-VTOR 0x08008000;这一步很多人会漏掉。如果不设置向量表偏移程序跳转到 App 后中断一来就会跳到错误地址表现就是程序跑起来但按键、定时器全都没反应。Bootloader 和 App 各维护一个通信协议App 收到升级指令后写入标志并复位Bootloader 启动时检查标志进入接收模式写入新固件到 App 分区完成后跳转。这套方案在工业产品和汽车电子中非常常见SR5E1E7 本身面向高可靠场景这类功能值得提前规划。6. 一份可以直接抄的烧录脚本和几条铁律6.1 最小化的烧录验证脚本我习惯在每个项目里放一个烧录脚本统一所有成员的下载行为避免“为什么我这边能烧你那边不能烧”这种低效争论。Windows 批处理 STM32CubeProgrammer CLI 就能实现echo off echo SR5E1E7 Flash Program STM32_Programmer_CLI.exe -c portSWD modeUR -e all if errorlevel 1 goto fail STM32_Programmer_CLI.exe -c portSWD modeUR -w build\app.hex -v if errorlevel 1 goto fail echo Flash OK. pause exit /b 0 :fail echo Flash FAILED, check SWD connection and power. pause exit /b 1这个脚本做了三件事连接并全片擦除、写入并校验、失败时给出明确提示。产线上用这一套逻辑能减少很多人为操作带来的差异。6.2 量产阶段的烧录注意点定制板小批量或量产时烧录环节有几个容易被忽视的问题烧录工位建议用同一个型号的调试器不同版本的驱动对 Flash 下载算法的行为有细微差异。统计烧录失败率如果超过 1%优先怀疑 PCB 生产质量比如 SWD 走线短路、芯片虚焊、电源滤波电容漏焊而不是烧录工具配置。产品序列号、MAC 地址等信息的写入建议在烧录固件后单独执行不要混在主固件烧录流程里方便排查问题。6.3 我踩过这些坑之后的几条铁律所有烧录问题先确认调试器能不能识别芯片。连这个都做不到后面全白搭。不要同时给调试器和板卡插两个 USB 供电很容易形成地环路轻则烧录失败重则烧板。每次改完 PCB 连接线先跑一次读 ID再开始烧录省得浪费时间。把工程里 Flash 的起始地址和大小以注释形式写在链接脚本和烧录配置旁边防止别人改链接脚本时悄悄破坏配置。遇到诡异报错先停手用示波器看电源和复位波形。我见过太多人遇到烧录失败就去重装软件最后发现是板子供电电容虚焊。最后分享一个小体会烧录问题看起来是软件配置问题本质上大部分是硬件问题。把 SWD 链路当做一个硬件接口来对待用示波器量信号、用万用表量电压比在 IDE 里反复试参数靠谱得多。SR5E1E7 定制板第一次烧录失败真的不用慌一步一步排查程序迟早会进 FLASH。