1. 先把工具链的定位讲清楚:为什么是 J-Link Commander 和 JFlash
1.1 三种烧写方式的真实差别
做 STM32F103C8T6 开发的人,手上大概率同时存在三套下载通道:IDE 里点一下的下载按钮、串口 ISP 的 flash loader,还有 J-Link 这一套。很多新手会觉得"我 Keil 里点 Download 就完了,为什么还要折腾 J-Link Commander 和 JFlash"——这个问题我当年也问过,直到产线上要烧两百块最小系统板,Keil 一块一块点,点到怀疑人生,才明白这两种工具的定位完全不同。
IDE 内置下载的本质,是把 J-Link 或者 ST-Link 的驱动当作一个普通调试器调用,烧写流程被 IDE 封装死了:编译、下载、复位、启动全部打包,你只能看到结果。它的好处是顺手,坏处是你根本不知道到底发生了什么,一旦报 "Flash Download failed - Target DLL has been cancelled",就只能干瞪眼。J-Link Commander 是 SEGGER 官方提供的命令行交互工具,它把"连接目标、擦除、写入、校验、复位、运行"这些动作拆成一条条独立的命令交到你手上,每一步成功还是失败都清清楚楚。JFlash 则是同一套底层引擎的图形化封装,适合批量生产、需要保存工程配置、或者不习惯敲命令的场景。
换句话讲,J-Link Commander 解决的是"可控"和"可脚本化",JFlash 解决的是"可复用"和"可批量"。STM32F103C8T6 这块芯片本身没有太多烧写上的花样,64KB Flash 从 0x08000000 开始,SWD 两条线加复位和地就够用,正因为简单,才特别适合拿它来把这两个工具彻底摸透。摸透之后,你换成 STM32F407、换成 GD32 或者国产替代型号,思路是一致的,只是器件名和 Flash 算法换一下而已。
1.2 什么时候你一定会用到这两个东西
我梳理了一下自己实际遇到的场景,大概有这几类:第一,程序里误把 PA13、PA14 配置成了普通 GPIO 或者复用成了别的功能,导致常规方式连不上芯片,这时候需要在连接方式上动脑筋;第二,板子上没有留串口,也没有 ST-Link,只有一根 J-Link 的排线;第三,需要把别人给的一个裸 .bin 文件烧进去,手上根本没有工程源码,Keil 里连"下载"按钮都没法点;第四,产线小批量,需要把烧写动作做成一条命令交给操作员,甚至需要按序列号写入不同的东西;第五,怀疑芯片被读保护锁了,或者需要主动给程序加上读保护。
这几类场景里,前两类是调试阶段的常态,后三类是工程化和生产阶段绕不开的。JFlash 自带一个 Flash 工程文件(.jflash),把器件型号、接口类型、速度、Flash 算法、连接方式全部固化下来,下次双击打开就能直接烧,哪怕换个人来操作也不会设错参数。J-Link Commander 则更适合写进批处理脚本,配合-CommandFile或者-CommanderScript参数,一句命令跑完全流程,出错了还能看日志。这两种用法的差别,我后面会用具体命令和界面参数讲清楚,包括哪些参数是必须改的、哪些保持默认就行。
另外提一句,STM32F103C8T6 的最小系统板在市面上流通量极大,板子质量参差不齐,我遇到过 USB 口虚焊、3.3V 稳压芯片输出只有 2.9V、复位电容焊成了 100nF 导致上电复位不干净等情况。这些问题在 IDE 里表现为"偶尔能下载偶尔不能",在 J-Link Commander 里会表现得更直接,反而更容易定位——这也是我更推荐用命令行先做一次连通性验证的原因。
2. 硬件侧的准备:接线、供电和最小系统板上的坑
2.1 J-Link 与 STM32F103C8T6 的接线对照
STM32F103C8T6 的 SWD 接口只有两根信号线,加上电源和地,一共四根就能工作,但真正接的时候有几个细节决定了你能不能一次连上。JTAG 那套 20 针排线在最小系统板上根本没有对应插座,所以必须用 20 针转 SWD 的转接小板,或者用杜邦线直接从 J-Link 的 20 针插座上引出来。
标准接法是这样的:J-Link 的 pin1(VTref)接目标板的 3.3V,pin7(SWDIO)接 PA13,pin9(SWCLK)接 PA14,pin4、pin6、pin8、pin10 等接地脚接目标板的 GND,pin15(nRESET)接目标板的 NRST。VTref 这根线特别关键,它不是一个可选的"参考电压",而是 J-Link 用来判断目标板是否上电、以及按照什么电平标准驱动信号的依据。很多人只接了 SWDIO、SWCLK 和 GND 三根线,结果 J-Link Commander 里一直提示 "Cannot connect to target",就是因为 VTref 空着,J-Link 认为目标板没供电。我实测下来,把 VTref 接到 3.3V 之后再连,成功率立刻从一半变成稳过。
| J-Link 20 针脚位 | 信号名 | 接到 STM32F103C8T6 |
|---|---|---|
| pin1 | VTref | 3.3V(必须接) |
| pin4 / pin6 / pin8 / pin10 | GND | GND(至少接两根) |
| pin7 | SWDIO | PA13 |
| pin9 | SWCLK | PA14 |
| pin15 | nRESET | NRST(建议接) |
| pin5 | 可选 | 一般悬空 |
关于 nRESET,我的建议是必须接。STM32F103C8T6 在程序运行起来之后,如果固件里把 SWD 引脚复用掉了、或者进了某种低功耗等待状态,SWD 接口可能会响应不上。这时候只要有 NRST 控制权,就能在连接时把芯片按住复位再接管总线,成功率天差地别。另外有些板子的 NRST 上并了一个 100nF 电容,这个电容对 J-Link 的复位驱动来说属于轻负载,问题不大,但如果有人焊了 10uF,复位信号边沿会变得很慢,可能导致连接不稳定。
2.2 供电、BOOT 跳线和共地问题
供电这件事看着简单,实际上是我踩过最多次的坑。常见做法有两种:一是目标板自己通过 USB 或外部电源供电,J-Link 只接 VTref、SWDIO、SWCLK、GND、NRST;二是直接用 J-Link 输出的 3.3V 给目标板供电。第一种做法更安全,但要求两个电源必须共地,否则信号电平没有公共参考,通信会时好时坏。第二种做法省事,但要注意 J-Link 的 3.3V 输出电流能力有限,最小系统板本身加上一个 OLED 或者几个 LED 大概一百多毫安还能撑住,如果板子上还挂了电机驱动、WiFi 模块这类耗电大户,就千万别指望 J-Link 供电,会表现为烧写中途失败或者校验不过。
BOOT0 跳线是另一个隐蔽的坑。STM32F103C8T6 上电时根据 BOOT0 和 BOOT1(PB2)的电平决定从哪里启动,BOOT0 接 3.3V 进入系统存储器启动,也就是串口 ISP 模式。如果你上一次做串口下载把跳线帽挪到了 1 的位置忘了挪回来,J-Link 还是能连上,也能擦除和写入,但写完复位之后程序不跑,你会以为是烧写失败,其实是芯片压根没从 Flash 启动。我自己定了个习惯:只要用 J-Link 烧写,先把 BOOT0 跳线帽短接到 GND 那一侧,再开始操作,能省掉大量"明明烧进去了为什么不亮"的排查时间。
还有一点关于杜邦线长度,这个属于实战经验。SWD 在 4MHz 下对线长和线材质量比较敏感,市售那种几十厘米的彩色杜邦线,随便盘成一团再接到板子上,很容易出现 "RDDI-DAP Error" 或者 "Could not connect to target"。我的做法是把线剪到 15 厘米以内,SWCLK 和 GND 尽量挨着走,实在需要长线就把速度降到 1000kHz 甚至 500kHz,牺牲一点烧写时间换稳定,批量烧写时这点时间完全可以接受,因为一个 64KB 的固件在 500kHz 下也就两秒左右。
2.3 连接方式的选择:普通连接和 connect under reset
J-Link 连接目标有两种典型策略。一种是普通连接,J-Link 直接把芯片 halt 住然后接管 SWD;另一种是复位下连接,即 J-Link 先拉低 NRST 把芯片按在复位状态,在复位释放的瞬间抢占总线。两者的区别在芯片"跑飞"或者固件里有异常配置时才体现出来。
我举个例子:曾经写过一段测试代码,把 PA13 配置成了普通的推挽输出,用来点灯验证引脚复用,结果代码下载进去之后,第二次连接就开始报错。这种情况在普通连接下基本无解,因为芯片一上电就跑进你的程序,几毫秒内就把 SWD 引脚改成了 GPIO,J-Link 根本没有窗口期抢到总线。此时在 JFlash 的工程设置里把连接方式改成 "Connect under Reset",或者在 J-Link Commander 里用connect命令时配合硬件复位、甚至用-JTAGConf之类的参数调整,问题就能解决。JFlash 界面里对应的选项通常在 Target Interface 页面的 Reset 策略下拉框,可选 "Normal"、"Reset & Halt"、"Connect under Reset" 等,实测 "Connect under Reset" 对付这类情况的成功率最高。
提醒:如果芯片已经被读保护锁死,普通连接和复位下连接都可能失败,这时候需要走解保护流程,那个过程会整片擦除 Flash,具体操作我放在第 5 节讲。
3. J-Link Commander 命令行烧写全过程
3.1 连接与器件选择的关键交互
安装好 J-Link 的官方软件包之后,在安装目录下能找到 JLink.exe,直接双击就进了交互界面。第一步永远是把固件和芯片型号对上号再连接,顺序错了会浪费很多时间。输入connect回车,工具会依次问你三件事:器件型号、目标接口类型、接口速度。
器件型号这一栏,输入STM32F103C8即可,注意很多老教程写的是STM32F103C8T6,实际上 SEGGER 的器件库里通常只登记到 C8 这一级,T6 是封装和温度等级后缀,不影响内核和 Flash 结构。如果拿不准填什么,输入一个问号?会弹出一个选择列表,可以在里面搜 STM32F1 系列;实在找不到完全匹配的,退一步选Cortex-M3也能连上,但 Flash 算法需要另外指定,不太推荐。
接口类型这里选S,也就是 SWD。JTAG 需要五根线以上,最小系统板没这个必要,而且 SWD 引脚少、抗干扰相对好一些。速度这一栏,默认给出的是 4000kHz,接线短的板子可以直接回车;线比较长或者板子上有干扰源,就手动敲1000或者500。这三项确认完,如果连接成功,你会看到一串设备信息,包括 CoreSight 组件、AP 索引、Flash 容量之类;如果失败,会明确告诉你卡在哪一步,比如 "Could not find core in Coresight setup" 或者 "Cannot connect to target"。
连接成功后,第一件事建议先跑一条erase,把整片 Flash 擦干净。STM32F103C8T6 是 64KB 空间,页大小 1KB,全片擦除耗时大约一两秒。这么做的原因是:你手上的 .bin 文件很可能不是全片镜像,只覆盖了前面一部分地址,尾部残留着上一版程序的代码,如果只用局部擦除,会有脏数据留下,某些情况下会干扰运行。全片擦除最省心,代价只是多等一秒。
3.2 烧写、校验、运行三步走
擦除完成后就可以写入了。命令格式是loadbin <文件路径>, <起始地址>,注意中间有空格,地址部分习惯写成十六进制并带 0x 前缀:
J-Link> loadbin C:\fw\demo.bin, 0x08000000 Downloading file [C:\fw\demo.bin]... Comparing flash [100%] Done. Erasing flash [100%] Done. Programming flash [100%] Done. Verifying flash [100%] Done. O.K.这里有个细节值得说一下:J-Link Commander 的loadbin在写入之后会自动做一次校验,所以一般不需要额外再敲verifybin。但如果你的固件是别人给的、来源不太可靠,或者传输路径上经过了网络共享目录,我还是建议再手动跑一次verifybin做双重确认,命令格式和 loadbin 一样,只是把动作换成比对。
写完之后不要急着拔线,还要让程序跑起来。r是复位,go是继续运行。这两条一般连着用,r之后芯片停在复位向量处,go才真正开始执行。我见过有人只敲了loadbin就拔线,结果程序没启动,跑来问我为什么烧录失败——其实一点都没失败,只是芯片还停在调试器拉住的状态。另外如果想停下来检查内存,可以用h让芯片 halt,再用mem <地址>, <个数>查看内容,比如mem 0x08000000, 8看 Flash 开头的几个字。
3.3 读回数据与常用调试命令
J-Link Commander 里我最常用的一个命令是savebin,它能把目标芯片里的内容读回来存成文件。做逆向分析、比对两块板子固件是否一致、或者怀疑烧写数据被改,这招都很管用。格式是savebin <文件路径>, <起始地址>, <字节数>,例如读回整片 64KB:
J-Link> savebin C:\dump\readback.bin, 0x08000000, 0x10000 Reading 65536 bytes from address 0x08000000读回来之后用任意二进制比较工具跟原始文件对比,字节完全一致才算真烧进去了。这里有个前提:如果芯片启用了读保护,读回会全部是 0 或者直接报错,这是正常的保护行为,不是工具问题。
还有几个命令值得记住。w4 <地址>, <数据>是写 32 位字,调试时临时改个变量或者改个跳转很方便,但要注意它写的是 RAM 还是 Flash,写 Flash 需要先擦页。unlock这个命令在老版本里用于解锁某些型号的芯片,STM32 系列不一定支持,用之前建议先看当前版本的帮助。exit和qc都是退出,区别是qc会静默关闭,适合写在脚本最后一行。另外每次连接都会自带一些信息输出,把窗口内容重定向到日志文件,对排查间歇性故障特别有用。
3.4 脚本化与自动化:一条命令跑完整个流程
真正的效率提升来自把命令写成脚本。J-Link 支持两种脚本方式,用错了参数会白折腾半天,我把它们的区别讲清楚。第一种是-CommandFile,它的内容是连接完成之后依次执行的命令,适合你已经在命令行里把器件和接口都指定好了的场景;第二种是-CommanderScript,它模拟的就是你在交互界面里从头敲的过程,所以脚本里第一行通常要写connect以及后续的型号、接口、速度选择。
我常用的写法是前者,命令行一次性把参数带全:
JLink.exe -device STM32F103C8 -if SWD -speed 4000 -autoconnect 1 ^ -CommandFile flash.jlink -ExitOnError 1对应的 flash.jlink 内容如下:
erase loadbin C:\fw\demo.bin 0x08000000 verifybin C:\fw\demo.bin 0x08000000 r go qc这里-autoconnect 1让工具启动后自动连接,省去了交互输入;-ExitOnError 1保证任何一步失败就退出并返回非零错误码,方便上层批处理判断结果。批量烧写时我会在外面套一层 bat 脚本遍历固件目录,把每个文件都跑一遍,日志统一输出到一个文本文件里。
注意:
loadbin后面的路径如果带空格,一定要用引号括起来,否则参数会被截断,报找不到文件。
4. JFlash 图形化烧写:从建工程到批量生产
4.1 新建工程与参数设置
JFlash 的界面比 Commander 友好很多,第一次用它建一个 STM32F103C8T6 的工程,大概三分钟就能完成,之后这个 .jflash 文件就固化了所有配置,传给同事或者产线操作员直接双击即可。
打开 JFlash,选择 File → New Project,会进入一个向导。第一步选器件,输入 STM32F103C8 搜索,选中之后下面的 Flash 大小、页大小、RAM 信息都会自动带出来,注意确认 Flash 是 64KB。这里我要多说一句:市面上流通的 STM32F103C8T6 里,有相当一部分实测可用容量超过标称的 64KB,社区里也常有讨论。但工程上不要依赖这个现象,选芯片时老老实实按 64KB 规划,测试阶段可以用 savebin 从 0x08010000 往后读一下看看有没有内容,作为了解即可,产品设计上千万别越界。
第二步选接口,也就是 SWD 和速度。速度我在图形界面里通常填 1000 到 4000kHz,如果现场连接不稳,就降到 500。同一页还有复位策略,前面提到的 "Connect under Reset" 就在这里设置。第三步是 Flash 算法,选中 STM32F103C8 之后算法一般会自动匹配,如果没匹配上,手动在列表里找 STM32F10x 系列对应的算法文件添加。全部设置好之后点 Test Connection,能读回芯片 ID 就说明通了,这时候把工程保存成 .jflash 文件。
| 设置项 | 推荐值 | 说明 |
|---|---|---|
| 器件型号 | STM32F103C8 | 不要写全称 C8T6,后缀会影响匹配 |
| 接口类型 | SWD | 两线制,接线最省 |
| 接口速度 | 1000~4000kHz | 线长时降到 500kHz |
| 复位策略 | Connect under Reset | 固件占用 SWD 引脚时必备 |
| Flash 算法 | STM32F10x 对应算法 | 选完器件一般自动带出 |
4.2 加载固件与烧写校验
工程建好之后,接下来就是打开固件。File → Open Data File 选择 .bin 文件,JFlash 会弹出一个对话框问你地址,填 0x08000000,这一步填错的概率很高,有人顺手填了个 0x00000000,烧进去之后程序完全不跑,因为 Flash 映射在 0x08000000,从 0 地址启动是别的东西。填完之后,界面上会显示出固件在地址空间里的占用范围,我可以直观看到这份固件大概有多大,如果显示长度明显超过 64KB,那就得回头看看用的芯片型号是不是选错了。
烧写就是点 Target → Program & Verify,或者直接按快捷键。JFlash 会依次完成擦除、编程、校验,进度条走完弹出一个成功提示。它的一个好处是日志区域会给出详细耗时和每一步的结果,出问题时比 IDE 里的那句"下载失败"信息量大得多。如果想在烧完之后立刻看到效果,可以在工程设置里勾选 "Start Application after programming",或者手动点 Target → Reset & Run。
关于校验,我建议一直保留 Verify 这个动作。JFlash 默认就是 Program & Verify,别为了省那零点几秒把校验关掉。实测校验能抓出相当一部分隐蔽问题,比如目标板供电不稳导致个别字节写入失败、杜邦线接触不良导致数据错位,这些问题如果不校验,程序可能能跑但存在偶发异常,排查起来极其痛苦。
4.3 生产模式与命令行自动化
JFlash 有一个专门的 Production 页面,这个功能对做小批量的人非常有用。它可以把烧写流程配置成一键操作:连上板子,点一个按钮,自动完成擦除、编程、校验、复位,然后弹出"请更换下一块板"的提示,操作员按空格继续。它还支持序列号自动递增,可以写到芯片内部的某块区域或者选项字节里,做产线溯源用。虽然 STM32F103C8T6 的选项字节空间有限,但如果只是存一个递增编号到指定的 RAM 或 Flash 保留扇区,完全没有问题。
自动化方面,JFlash 同样支持命令行启动,典型写法是把工程、固件、自动执行、退出这几个参数串起来:
JFlash.exe -openprjC:\proj\stm32f103c8.jflash -openC:\fw\demo.bin,0x08000000 -auto -exit参数之间的空格和逗号位置比较讲究,-openprj后面直接跟文件路径不加空格,-open后面的地址用逗号分隔。不同版本的参数支持不太一样,写脚本之前先用-?看一下本机帮助,以实际输出为准,不要照抄网上的老教程。在产线环境下,这一条命令可以写进批处理文件,配合扫码枪读入固件路径,实现不同产品共用一套烧写工位。
经验:如果要把烧写工位交给不熟悉技术的人操作,建议把 .jflash 工程和固件路径都固定好,写成 bat 脚本双击运行,日志自动写到带日期的文件里。一旦出现批量不良,翻日志能快速判断是工具问题还是板子问题。
5. 选项字节、读保护与"加密"那些事
5.1 读保护到底保护了什么
很多人问 STM32F103C8T6 怎么加密,其实这块芯片没有一个真正意义上的硬件加密引擎,所谓"加密"通常指的就是 Flash 读保护,也就是 RDP。它的作用机制很直接:一旦置位读保护,通过 SWD 或者 JTAG 读取 Flash 内容时,返回的数据会被硬件屏蔽,同时禁止从 RAM 启动、禁止调试器查看代码区。但要注意,读保护只是防止别人把固件读出来复制,它并不能阻止别人整体擦除芯片,也不能阻止别人重新烧一份自己的程序进去。所以如果你的诉求是"防止竞争对手抄板抄代码",读保护能用,但别指望它坚不可摧;真正的商业保护还得靠外置加密芯片、唯一 ID 绑定之类的组合手段。
STM32F103C8T6 内部有一个全球唯一的 96 位 ID,存放在系统存储区,地址在 0x1FFFF7E8 附近。一个很常见的做法是:固件启动时读取这个 ID,用自家算法做一次映射,把结果和某个存储位置里预先写入的校验值比对,不匹配就不让主程序跑起来。这样即使固件被完整复制到另一块芯片上,因为 ID 不同,程序也不会正常工作。这个方案不需要额外的硬件,成本为零,我做过好几个小项目都在用。
5.2 加保护与解保护的实际操作和代价
在 JFlash 里,读保护的开关在 Target 菜单下的选项字节区域,一般叫 Option Bytes 或者 Security 相关条目。操作方式是先在 Target → Connect 连上芯片,然后打开选项字节编辑界面,把读保护相关的位勾上,写入并确认,芯片会自动复位生效。在 J-Link Commander 里也可以直接对选项字节区域做读写,STM32F1 的选项字节在 0x1FFFF800,可以用mem命令读出来看看当前状态,但写入涉及解锁序列,操作不当有一定风险,新手建议还是走 JFlash 的图形界面。
解保护的代价必须说清楚,这是最容易出事的地方。解除读保护的同时,芯片硬件会强制擦除整片 Flash,也就是说你加锁的固件会一起消失,而且这个过程不可逆。我见过同事为了对比两块板子的固件,随手点了解除保护,结果把一块已经调试好的成品板清空了,只能重新烧。所以加保护之前一定要留好源码和固件备份,解保护之前要确认这块板子上的程序不需要保留。
还有一个细节:加了读保护之后,用 savebin 读回来的数据会全部是零或者直接报错,这不是工具坏了,是硬件在起作用。同样,加了读保护的芯片,J-Link 连接时可能会提示一些额外的警告信息,比如提醒你目标芯片受保护,这是正常现象。
提醒:给量产板加读保护之前,先在废弃板或者空板子上练习一遍加锁、解锁的完整流程,确认你能熟练解除,再上真实产品。这一步花十分钟,能省下很多麻烦。
6. 常见问题速查与排查思路
6.1 连接类报错逐条拆解
连接问题占了实际故障的七成以上,我把常见的几条按出现频率排一下。第一条是 "Cannot connect to target",绝大多数情况下是接线问题:VTref 没接、GND 没共地、SWDIO 和 SWCLK 接反了、或者杜邦线中间断了。排查方法是拿万用表量一下 J-Link 的 pin1 到目标板 3.3V 之间是否导通,再量 pin7 到 PA13、pin9 到 PA14 是否导通。我遇到过一根杜邦线外皮完好但内部铜丝断了的情况,量了才发现,这类问题没有任何软件手段能解决。
第二条是 "RDDI-DAP Error" 或者 "Could not find core in Coresight setup",通常是速度太高或者线太长。把速度从 4000kHz 降到 1000kHz,再不行降到 500kHz,多数能解决。另外目标板供电电压偏低也会触发这个错误,尤其用 J-Link 直接供电时,板子上挂的负载一多,电压被拉到 3.0V 以下,SWD 时序就开始出问题。这时改用外部电源供电,只保留信号线和共地。
第三条是程序烧进去之后连不上了,常见于固件把 PA13、PA14 改作他用或者进了深度睡眠。解决办法是切换到 Connect under Reset 模式,或者在连接时按住板子的复位键,点下连接按钮再松手,人为制造一个抢占总线的窗口。这个方法土但有效,我救过好几块被自己代码锁死的板子。
| 报错信息 | 高概率原因 | 优先处理动作 |
|---|---|---|
| Cannot connect to target | VTref 未接、未共地、线序错 | 逐根量通断,补接 VTref |
| RDDI-DAP Error | 速度过高、线过长、供电低 | 降速至 500~1000kHz |
| Could not find core | 芯片未上电、复位异常 | 量 3.3V,检查 NRST |
| 烧录后再次连接失败 | 固件占用 SWD 引脚 | 改用 Connect under Reset |
6.2 烧写与校验类报错
烧写阶段的错误相对好定位,因为工具给的信息比较具体。出现 "Programming target failed" 时,先看是不是 Flash 地址超出范围,比如器件型号选成了容量更小的版本。STM32F103C8T6 是 64KB,如果误选成 STM32F103C4 那种小容量型号,写到 0x08004000 之后就会报错。反过来,选成了 128KB 或者更大的型号,工具不会报错,但写到超出真实容量的地址时,数据实际上是丢掉了,这时候必须靠 verifybin 才能发现。
校验失败 "Verify failed" 的原因分成两类:数据类问题和硬件类问题。数据类包括固件文件本身损坏、路径指向了旧版本文件、地址填错;硬件类包括供电不稳、Flash 擦除不干净、芯片本身有坏块。我遇到过一块二手最小系统板,反复校验失败,换了三根线、两个 J-Link 都没用,最后用 savebin 读回对比,发现固定某一段地址写进去的值和原值差一位,判断是芯片那个扇区有问题,直接换板子解决。这种硬件缺陷靠软件折腾是没用的,学会读回比对能省很多时间。
还有一个隐蔽的坑:部分国产替代型号或者翻新片子,在擦除和写入时序上跟原厂存在细微差异,用原厂参数烧写偶尔会失败。遇到这种情况,可以试试降低速度、增加擦除次数,或者在 JFlash 里给 Flash 算法加一点延时参数。如果确认是替代型号,最好在 J-Link 的器件库里直接选对应的型号,识别率和烧写稳定性都会更好。
6.3 一些没人告诉你但很关键的实操心得
第一条心得,永远保持一份可回退的固件。每次烧写前用 savebin 把当前芯片内容读出来备份,尤其是板子上的程序已经没有源码的时候。这个操作只要几秒钟,但价值极高。我自己养成了一个习惯,给每块工作板在本地建一个目录,按时间戳存 dump 文件,出错时能立刻对比"上次正常的是什么样"。
第二条心得,把 J-Link 的固件更新提示看清楚再点。J-Link 会提示固件版本与软件不匹配,需要升级。原厂设备升级一般没问题,但一些非官方渠道的仿真器升级后可能无法识别,这个风险是存在的,升级前先确认手头设备来源是否可靠。如果你只有一块设备,又不确定,可以先在一台闲置电脑上验证,不要在主工作机上贸然操作。
第三条心得,烧写速度不是越快越好。产线上追求节拍,很多操作员喜欢把速度拉满。实测 4000kHz 对一个 64KB 固件的总耗时影响很小,反而是速度过高导致的偶发连接失败,会让单块板子的平均处理时间更长。我的经验是 1000kHz 是个甜点值,连接稳定、速度够用。
第四条心得,学会看 J-Link 的连接日志。JFlash 下面的日志窗口和 Commander 的输出,会告诉你具体在 CoreSight 的哪一步失败、读到的 ID 是什么、电压检测结果是多少。这些信息比报错本身有价值得多。我习惯把 JFlash 的日志自动保存到文件,出现批量问题时,翻一次日志就能判断是共性还是个别。
第五条心得,给烧写工位准备一份"环境说明"。写在纸上贴在工作台旁边,内容就是:J-Link 型号、软件版本、器件型号、接口速度、是否勾选 Connect under Reset、工程文件路径。看起来啰嗦,但换人操作、或者隔了三个月自己再上手的时候,这份说明能让你五分钟回到状态,而不是重新试错半小时。
最后分享一个我用了很久的小技巧:把 J-Link Commander 的脚本和 JFlash 工程各准备一套。脚本用于快速验证和自动化,工程文件用于给别人用和长期存档。两者用的底层引擎是同一套,往往一个连得上另一个就连得上,遇到疑难杂症时两边交叉验证,能很快判断是工具配置问题还是板子硬件问题。我在实际使用中发现,绝大多数"J-Link 怎么又连不上"的情况,最后查出来都是那根十厘米的杜邦线、或者那个忘了挪回来的 BOOT0 跳线帽。