ARTICLE DETAIL

资讯详情

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

STM32烧录报错Contents mismatch?五大排查步骤详解

STM32烧录报错Contents mismatch?五大排查步骤详解 做嵌入式开发的朋友十有八九都见过Keil MDK烧录STM32时突然弹出来的一串红字报错。编译、链接都过了代码看着也没问题一点Download前面“Erase”“Programming”都顺利走完最后“Verify”却来一句Contents mismatch at: 08000000H (Flash0x00 Required0x55) !。我第一次遇到时也懵了一下明明写入过程没报错怎么到最后校验就翻车了这个报错简单说就一句话MCU Flash里实际读回来的数据和你要写进去的数据对不上。它不像“No target connected”那么直白也不像“Programming error”那样发生在写入阶段而是在烧录流程的校验阶段才暴露所以排查起来容易绕路。尤其是刚接触STM32项目、或者正在被烧录问题折磨的朋友很容易误判成“芯片坏了”或者“调试器废了”。这篇文章我就结合自己踩过的坑把这个报错拆成5个排查步骤从软件配置到硬件接线都过一遍希望能帮你少走弯路。1. 先搞懂“Contents mismatch”到底在说什么1.1 这个报错是在烧录流程的哪一步冒出来的Keil MDK的烧录流程并不是简单把文件丢进芯片就完事。在Flash Download阶段Keil会调用调试器比如ST-Link或J-Link和目标芯片里的Flash加载算法配合按“擦除—写入—校验”三步走。先擦除目标区域让Flash恢复到全0xFF状态然后把HEX或AXF文件里的内容分块写入写完后调试器会把Flash中的数据重新读出来和PC端暂存的数据逐字节比较。一旦任何一个地址的Flash值与期望写入值不一致就会抛出一句类似“Contents mismatch at: 0x08000000H (Flash0x00 Required0x55) !”的提示。括号里的Flash就是芯片读回的当前值Required就是程序原本要求写入的值。0x08000000刚好是STM32内部Flash的起始地址所以绝大多数报错都从那里开始。后面还可能跟着一串地址表示校验失败的具体位置范围。这里要注意的是Keil报这个错之前擦除和写入步骤通常没有报错所以很多人的第一反应是“Keil有病吧”实际上校验阶段才是真正检验结果的时候。烧录器把数据写进去了但芯片里存的不是那个数据问题就出在这个“不是”上。1.2 为什么“读回来的和要写的不一样”会这么难查我做了这么久开发感觉这个报错最麻烦的地方在于它既可能是软件配置问题也可能是硬件连接问题还有可能是芯片本身的状态问题。它不像“Cannot access target”那样直接指向连接失败因为大多数情况下芯片是能响应的调试器也能正常通信问题藏在“擦除是否真正干净”“写入时序是否稳定”“芯片的保护状态是否允许正确读回”这些环节里。用一个生活化的类比你以为把一个东西放进了抽屉但抽屉本身带了锁或者抽屉型号不对放进去的东西自然和你的清单对不上。排查的时候千万别只盯着代码要把软件配置、硬件连接、芯片状态三个层面一起看才能定位到真正的原因。2. 排查步骤一先核对Flash编程算法和Target配置2.1 芯片型号与Flash算法不匹配是头号嫌疑“Contents mismatch”最经典的高发原因就是Flash编程算法没选对。Keil里叫Flash Download Algorithm也有人叫编程算法或Flash Loader。你在建立工程时选的芯片型号决定了Keil默认使用哪套算法但如果你后续换过芯片、或者建工程时随便选了个相近型号这个配置就可能对不上。举个例子工程原本是STM32F103C8T6属于中密度产品Flash共64KB现在量产板换成了STM32F103RCT6高密度产品Flash共256KB但Flash Download里仍然用中密度算法。对于高密度芯片来说这套算法的扇区大小、地址布局、擦除命令全都不匹配写进去的内容大概率读不回来。反过来用高密度算法去写小容量芯片也可能因为访问了不存在的地址区域而出现奇怪行为。这个错误的本质是FLASH的扇区划分和操作命令序列错了。Keil调用算法擦除时可能只擦除了一部分或者根本没有擦除写入时又把数据放到了错误的位置校验时读回自然对不上。2.2 怎么正确配置Flash Download想检查这个配置点一下魔术棒“Options for Target”进入Debug页确认右侧Use选择的是你手上实际的调试器比如ST-Link Debugger或J-LINK/J-Trace。接着点旁边的Settings在弹出的对话框里切到Flash Download页。这里能看到一个Programming Algorithm列表里面列出了当前工程使用的Flash算法。正确的做法是选中列表里不匹配的条目点Remove删掉再点Add从弹出的算法列表里选择目标芯片对应的算法。STM32F1系列常见的包括STM32F10x Med-density Flash、STM32F10x High-density Flash、STM32F10x Connectivity line Flash等F4系列又有单独的STM32F4xx Flash算法。选完之后建议把Reset and Run、Program、Verify都勾上Erase模式一般用Erase Sectors日常调试不需要每次全片擦除。如果Add列表里找不到你需要的算法多半是芯片支持包没装完整。去Keil官网下载对应系列的Device Family Pack比如STM32F1系列对应Keil.STM32F1xx_DFPSTM32F4系列对应Keil.STM32F4xx_DFP。装完之后算法列表才会完整。缺了这些包很多芯片型号在Keil里可能压根创建不了工程或者烧录行为很怪。2.3 一个让我印象深刻的算法选择案例有一次同事拿过来一块STM32F103ZET6开发板说Keil能连上芯片但每次烧录都报Contents mismatch at 0x08000000HFlash0xFFRequired是个非0xFF的值。这很有代表性Flash值读到0xFF说明那片区域根本没有被成功写入或者写完又被某种机制还原了。我打开他的工程一看Flash Download里的Programming Algorithm列表居然是空的。这就等于Keil不知道该用哪套算法去操作这个芯片虽然表面上能“连上”但实际写入动作根本没执行正确。Add之后选择STM32F10x High-density Flash问题当场消失。这个案例后来我分享过好几次每次说大家都很惊讶原来这么简单的配置就能引发这种玄学报错。3. 排查步骤二检查芯片的读保护与写保护状态3.1 读保护怎么会让校验数据对不上第二个要重点怀疑的是Flash保护状态。STM32芯片出厂时默认读保护等级是Level 0即无保护。但有的板子在被烧录出厂固件时厂商会顺手打开Level 1读保护或者你自己在调试某个低功耗项目时误开了保护。一旦芯片进入Level 1读保护外部调试器通过SWD读Flash时地址内容会被替换成0x00或0xFF而不是真实数据。这时候表现就很魔性你能连接、能擦除、能写入但读回来的数据永远是假的校验就不可能通过。写保护类似WRP会对某个扇区设置保护写入时被芯片静默忽略扇区里还是旧数据最后校验也会报mismatch。如果你手里的芯片来自二手拆机件、或者通过一些特殊渠道买的样片这个概率明显更高。3.2 用STM32CubeProgrammer确认并解除保护遇到这种情况最靠谱的办法是换官方工具来看。下载STM32CubeProgrammer连接方式选ST-Link或你手上的调试器点Connect。连接成功后切到Option Bytes页签找到Read Out Protection这一项。正常情况下应该是AALevel 0如果显示Level 1就需要改成Level 0并Apply。这里会有一个重要提示降低读保护等级会触发全片擦除因为这是STM32硬件层面的机制。不同系列行为略有差异但本质上都是把Flash内容清空再解除保护所以别指望还能保留里面的数据。如果里面有需要保留的固件提前用其他方式读出来备份再执行解除操作。3.3 操作顺序和注意事项我的习惯操作顺序是先用CubeProgrammer连接确认能读到芯片ID然后切到Option Bytes页签把当前的配置截图或记下来再把RDP从Level 1改成Level 0并Apply等擦除流程跑完断开连接重新上电。之后回到Keil再次Download会发现原先的mismatch报错彻底消失。如果CubeProgrammer连接时提示No STM32 target found不要马上放弃。可以把板子上的BOOT0引脚拉高让芯片从系统存储器启动然后用串口UART方式连接同样能执行解除保护的操作。这种模式下SWD可能被Level 1保护挡住但系统存储器里的Bootloader仍然允许ISP烧录。具体哪个引脚、哪组串口看板子原理图就行不同板子位置不一样。4. 排查步骤三检查复位模式、SWD接线和供电4.1 Connect under Reset为什么能救场第三个方向是硬件连接和复位模式。Keil调试设置里Settings对话框Debug页有一个Connect选项默认是Normal。如果你的板子跑过一段会进入休眠、看门狗咬人、或者用户程序把SWD引脚复用掉的代码调试器下一次连接时可能就不稳定。具体到烧录场景就是写到一半芯片被复位或者Flash编程时序被干扰最后校验失败。把Connect改成under Reset可以解决大部分这类问题。工作方式是调试器先拉低复位引脚把MCU按在复位状态然后建立SWD连接再释放复位进入调试。这样用户程序还没来得及跑起来调试器就已经占领了芯片的控制权非常有效。另外烧录完成后是否勾选Reset and Run也值得注意有些系列的老版本Flash算法在勾选后行为异常如果反复在最后一步失败可以试着取消勾选烧完后手动按复位键。4.2 SWD接线和供电的细节接线是另一个容易翻车的点。很多新手习惯用杜邦线把ST-Link/J-Link和板子连起来SWDIO、SWCLK、GND三根线就够了。但杜邦线如果太长比如超过10cm或者接触不良在较高的SWD时钟下很容易出现数据错误。这种数据错误不一定会立即让写入阶段报错因为Flash编程本身有时序要求编程器会等芯片完成内部操作但最终校验阶段一定会暴露。除了线长和接触问题供电也很关键。调试器的3.3V输出一般是板载线性稳压器给的电流能力有限从几十mA到几百mA不等。如果板子上带着多个LED、传感器模块或者有大容量滤波电容上电瞬间电流会很大电压可能被拉低。MCU内部Flash编程对电压波动很敏感电压不稳写入内容就可能出错。我建议有条件的朋友尽量用外部电源给板子供电调试器只接SWDIO、SWCLK、GND三根线另外再补一根GND给调试器和板子共地不要用调试器供电来驱动整块板子。4.3 把SWD频率降下来做快速验证想快速验证是不是接线问题不用换线也能试。在Debug设置里有一个Max Clock下拉框把默认的4MHz或1.8MHz往下降比如降到1MHz甚至500kHz。SWD协议对时序的容错性会随着频率降低而增加偶尔丢一帧也能自恢复。实测下来很多低端调试器在长线下还跑4MHz确实会偶发校验失败降到500kHz后一切正常。这个现象不是调试器坏了而是信号完整性不够。如果你的板子必须用很长的线连接优先保证SWCLK和SWDIO不要绑在一起和电源线、地线尽量保持距离减少串扰。这个降频测试我几乎每次排查烧录问题都会做一遍成本最低、见效最快。5. 排查步骤四检查时钟和Option Bytes状态5.1 时钟异常如何影响Flash写入时钟和Option Bytes这个问题很多人容易忽略。Flash编程需要MCU内部时钟正常工作最基本的条件是内部HSI振荡器可控。如果芯片被前一段代码配置成从外部HSE启动而板上又没有外部晶振或者晶振起振失败MCU可能压根没有正常进入调试模式或者时钟频率极不正常Flash编程器发来的时序就对不上数据自然写错。还有一种情况是用户程序在低功耗模式下关闭了调试时钟或者配置了DBGMCU的某些寄存器导致下一次调试连接异常。这类问题往往有间歇性有时能连上连上后烧录又校验不过时好时坏。如果你遇到这种“玄学”现象时钟和调试配置是重点怀疑对象。5.2 查看和恢复Option Bytes的实操方法Option Bytes是一个独立的非易失区域主要配置启动模式、读保护等级、BOR阈值等选项。通过STM32CubeProgrammer的Option Bytes页签可以直观查看。如果发现nBOOT0、nBOOT1这些位和出厂默认值差距很大且你确认之前没刻意改过可以先记录下来然后全部恢复默认值。要注意的是F1系列的默认值会因封装和型号不同而有差异比如nBOOT0在部分型号默认是0在另一部分默认是1。千万不要照抄网上某篇帖子的“默认值”正确做法是打开目标芯片的参考手册找到Option Bytes章节对照出厂配置逐一核对。恢复Option Bytes后可能会触发一次擦除因为Option Bytes修改和Flash保护等级是联动的所以操作前最好先确认不需要保留板子上现有固件。6. 排查步骤五用官方工具交叉验证二分定位问题6.1 用STM32CubeProgrammer做一次全片擦除和重新写入当你把前面四步都排查完还是不解决那就别在Keil里死磕了换官方工具做一次完整擦除是最快的定位方法。用STM32CubeProgrammer连接目标点击右侧的Full chip erase等待进度条跑完。然后再用Read功能把全片读一遍确认地址区间都是0xFF。如果读出来有很多不是0xFF的数据说明擦除流程本身被什么东西截断了可能是写保护可能是Option Bytes异常也可能Flash本身有问题。擦干净后再随便烧一个最简单的LED闪烁程序比如经典的点灯程序。如果点灯程序也失败那问题基本不在Keil层面而是硬件层面的稳定性。如果点灯程序成功再回到Keil烧目标固件只要配置正确一般都能过。这一套二分法能帮你快速缩小问题范围避免在错误方向上反复试。6.2 用J-Flash烧录对比验证手上有J-Link的朋友还可以试试J-Flash。打开J-Flash新建工程时选对芯片型号比如STM32F103RE然后File→Open打开同一个HEX文件Target→Connect连接再依次执行Manual Programming里的Erase和Program。J-Flash会明确显示它用了哪个Flash loader每一步是成功还是失败提示信息比Keil具体得多。如果J-Flash报“Failed to erase chip”或“RAM check failed”说明问题出在芯片端外部工具连擦除都做不了。如果J-Flash烧录成功那大概率就是Keil的某个配置项有问题。我有一次就是Keil里算法选错但J-Flash全自动选对了两边结果一对比问题立马定位。6.3 回到Keil前还要检查这两个隐蔽设置从J-Flash切回Keil之前还有两个隐蔽位置要确认。Flash Download设置其实有两处入口一个是Debug→Settings里的Flash Download另一个是Utilities→Settings里的Flash Download两者逻辑上对应同一个烧录流程但配置不一致时Keil有时不会直接报错而是以奇怪的方式失败。还有一个地方是Debug页右侧的调试器下拉框要确保选的是你实际使用的设备。比如你插着ST-Link但选项里还停留在ULINK2Keil会按ULINK的方式去操作自然各种不对劲。这两个地方的配置我每次排查烧录问题都会过一遍别看它们不起眼坑起人来一点都不含糊。7. 常见现象速查表与个人踩坑记录7.1 不同报错表象对应的排查方向现象优先排查方向每次都在0x08000000H固定地址报mismatchFlash算法选错、芯片型号不匹配、擦除没生效地址随机不固定有时成功有时失败SWD接线不稳、供电不足、SWD频率过高报错前出现过Cannot access target芯片跑飞、休眠、看门狗、需要切换Connect under Reset之前烧过其他程序换板子就报mismatch读保护Level 1、写保护WRP、二手芯片换了算法、换了工具仍然失败Option Bytes异常、时钟配置问题、Flash本身故障7.2 我真实踩过的几个坑第一个坑是二手芯片翻车。从某平台买的STM32F103C8T6价格很便宜一开始烧录就mismatch换了好几个调试器都没用。最后用CubeProgrammer一看读保护Level 1降级后一切正常。这类芯片大概率来自旧设备拆机出厂时被写过程序并开了保护不解除保护根本没法正常用。第二个坑是长杜邦线。我把SWD线从桌面一侧拉到另一侧线长超过20cm4MHz频率下烧录偶发失败一开始还以为是芯片体质问题后来把频率降到500kHz再也没出过事。后来我干脆把线剪短换成双头镀金杜邦线问题彻底根除。第三个坑是手贱断电。一次在Flash Download里勾了Full Chip点完看进度条半天不动我以为卡死了直接断电。结果Flash处于半擦除状态之后怎么烧都报mismatch最后只能全片擦除重新来。后来我明白了大容量芯片全片擦除确实要等一阵子那是正常的耐心等就好。第四个坑是供电不足。调试器供电给整块板子板载LED模块和无线模块一起工作电压被拉到2.9V左右烧录时偶发失败。开始怀疑各种软件配置最后用万用表一量才发现是电压问题改成外部3.3V供电后问题再也没有出现过。如果你也遇到类似问题先别急着怀疑芯片坏了按这个顺序过一遍算法配置、保护状态、复位方式、接线供电、时钟选项大多数情况下都能找到答案。
返回列表