做电动工具控制板这几年,CW32L010 这类小封装、低成本的 MCU 用得越来越多,道理很简单:引脚够用、价格合适、外设也够跑方波驱动和无感换相。但几乎每个用过它的人都会在某个节点上被同一件事卡住——SWD 下载口被占用,调试器连不上,板子已经焊好了、电机也装上了,就是下不进程序。我第一次遇到这个问题时,手上一块已经打好胶的控制板,调试器插上去只回一句“no target connected”,那种感觉比电路画错还难受,因为电路是对的,只是固件把门从里面锁上了。
这篇内容就是把这类问题的来龙去脉讲透:SWD 口“被占用”到底有几种不同的形态、硬件上怎么提前给下载留后路、调试器侧怎么配合时序、固件里怎么留一个“下载窗口”,以及 SWD 彻底不通时的兜底手段。适合正在用 CW32L010 做电动工具控制板、电机驱动板、锂电工具主控的同行,也适合刚接手别人板子、手上只有一块成品板要救回来的朋友。不管你是刚上手这块芯片,还是已经调过几版板子,下面这些坑大概率你都会碰到,或者已经踩过了。
1. 先把问题看清楚:SWD 口“被占用”的四种完全不同的形态
很多人把“下载不了”笼统归成一句“SWD 被占用”,实际上这四种情况的原因、排查路径和处理手段差别很大。分不清类型就乱试,很容易在错误的路上浪费半天。我一般先按下面这套分类去套,基本三分钟内能定位到方向。
1.1 形态一:引脚复用占用,固件把调试脚改成了普通 IO
这是最常见的一种。CW32L010 这类 Cortex-M0+ 芯片的调试口默认只有 SWD 两根线(SWDIO 和 SWCLK,通常是 PA13、PA14 这一对,具体以你手上那份数据手册的引脚定义为准),没有 JTAG。芯片复位之后,这两个脚的复用功能默认指向调试口,所以“空片子”一定能连上。问题出在固件里:为了省引脚,很多人把这两根线复用成霍尔信号输入、LED 指示、扳机检测或者 PWM 输出。一旦固件执行到 GPIO 初始化那几行,把对应引脚的复用寄存器(AFR)切走,SWD 链路当场断开。
理解这一点很关键:不是调试器坏了,是芯片内部的“门”被固件从里面关上了。此时调试器再怎么发线序复位序列也没用,因为 SWDIO 已经被当成普通 IO 在驱动,甚至可能被固件拉成输出低电平,和调试器的输出直接顶牛。
这种形态的典型特征是:冷机第一次上电能连上(因为复位后到 GPIO 初始化之间有个几毫秒到几十毫秒的窗口),但只要你放手让程序跑起来,就再也连不上;或者连上之后一下载就断,因为下载过程中芯片复位、程序重新跑、又把脚切走了。
1.2 形态二:外部电路占用,引脚上挂了不该挂的东西
这一类经常被忽略。引脚复用没动,固件里 SWD 功能也保留着,但板子上这两个脚外面接了东西:LED 加限流电阻、按键上拉、RC 滤波电容、驱动芯片的输入脚、TVS 管、甚至直接并了一个几微法到几十微法的电容。
SWD 是同步串行接口,SWCLK 的频率在调试器里可以设到几百千赫兹到几兆赫兹。引脚上并一个 1μF 电容,边沿直接被拖成一条缓坡,调试器采样全错;串一个几 kΩ 的电阻,高电平被拉低,认不出逻辑 1;接一个强下拉(比如 1kΩ 到地),调试器内部那点驱动能力根本拉不上去。我给一个经验阈值:SWD 两根线上并的电容最好控制在几十皮法以内,串的电阻不要超过 100Ω,上拉用 10k~100k 这种弱上拉。超出这个范围,就该怀疑是电路在拖后腿。
还有个隐蔽情况:引脚同时接到了电机驱动芯片或者 MOS 管的栅极驱动上,板子一上电,那一路就在开关,SWD 线上叠加了几百毫伏的开关噪声,通信时好时坏。表现出来就是“十次能连上一次”,很多人误以为是接触不良,其实是干扰。
1.3 形态三:时序占用,固件跑得比调试器快
严格说这不是“占用”,是“抢跑”。调试器从上电到完成握手,需要一段时间:供电稳定、内部时钟起振、发送几十个时钟的线序复位序列、读 IDCODE、切换调试模式。如果你的固件上电后 2ms 就把所有外设初始化完,5ms 就把 SWD 脚切成 PWM 输出,那调试器基本没有机会。
电动工具控制板特别容易这样,因为产品逻辑要求“扣扳机立刻出转矩”,固件被优化得越短越好,启动延时能砍就砍。结果就是开发阶段勉强能下,量产版本一改启动流程直接连不上。这种情况的典型特征是:用调试器点“复位并连接”偶尔能成,但正常连接永远失败;把调试器时钟降到 100kHz 反而更容易连上,因为握手过程被拉长了,反而撞上了窗口。
1.4 形态四:状态占用,低功耗、复位、保护位把口封死了
最后一类更偏“状态”而不是“引脚”。比如固件进入深度休眠后调试口被关闭;比如复位脚(NRST)被配置成了普通 IO 输出并拉低,芯片一直处于复位态,调试器根本读不到 IDCODE;比如用户选项区里开了读保护,调试器能连上但一访问 Flash 就报错;再比如看门狗配置极短,芯片不停复位,每次刚握上手就被打断。
这四种形态在实际项目中往往同时出现两三种,所以我通常的做法不是一个个试,而是先做一次快速判定:调试器能不能读到芯片 ID。能读到 ID,说明物理链路和时序是通的,问题在固件或保护位;读不到 ID,说明要么引脚被切走了,要么复位异常,要么电路上有东西在捣乱。这一条判据能砍掉一半的无效尝试。
| 判定现象 | 指向的形态 | 下一步动作 |
|---|---|---|
| 冷机首次上电能连,之后连不上 | 形态一(引脚复用) | 查固件 GPIO 初始化,找 SWD 引脚配置 |
| 完全读不到 ID,万用表量引脚阻抗异常 | 形态二(外部电路) | 断开外围,量对地/对电源阻抗 |
| 降速能连、提速失败,偶发成功 | 形态三(时序) | 加启动延时窗口,配合复位连接 |
| 能连上但报保护/擦除失败 | 形态四(状态) | 全片擦除,检查选项字节与复位脚 |
2. 硬件侧:在画板阶段就给下载留一条后路
硬件上的事,画板之前想清楚,后面省一半麻烦;画完再改,尤其是已经灌胶或者装进壳子里的板子,就只能飞线了。我在电动工具控制板上吃过两次亏之后,现在固定会做几件事,成本增加几乎为零,但救板成功率极高。
2.1 SWD 两根线的外部电路排查清单
先说已经画好的板子怎么查。拿万用表打到电阻档,板子断电,黑表笔接地,红表笔依次点 SWDIO 和 SWCLK 两个测试点,读一个稳定值;再反过来红表笔接 VCC、黑表笔点引脚,读一个值。正常的板子,对地阻抗应该是几十 kΩ 到几百 kΩ 这个量级,对电源阻抗类似。如果量出来只有几百欧甚至几十欧,说明这一路挂了负载:可能是 LED 加限流电阻到地、可能是驱动芯片输入端的下拉、也可能是一颗被焊反的 TVS。
接下来查电容。用万用表的电容档(或者直接看原理图)确认这两根线上有没有并电容。有些设计为了防静电和滤波,习惯在每个 IO 上并 100nF,这个习惯用在 SWD 上就是灾难。我见过一块板子,四根调试线每根并了 1μF,结果调试器怎么都连不上,把电容拆了瞬间就好。经验值:SWD 线上不需要并电容,非要防静电就串 22~100Ω 电阻加 TVS 到地,电容一律不装。
再查串联电阻。有些设计在 SWD 线上串 1kΩ 甚至 4.7kΩ 做限流保护,这个阻值对 SWD 来说偏大,会让上升沿变缓。要串就串 33Ω 到 100Ω,这个区间既能抑制振铃,又不影响边沿。
最后查共用。这两根脚如果还接到了别的地方,比如和霍尔信号、扳机开关、调速电位器共用,那就要确认那些外围在下载时处于高阻态。判断不了就直接把外围断开试。
2.2 常见的“隐形杀手”:上拉电阻、滤波电容和驱动芯片输入
我列一下电动工具控制板上最容易出问题的几类外围,都是在实际板子上反复见过的:
| 外围类型 | 典型接法 | 对 SWD 的影响 | 处理建议 |
|---|---|---|---|
| LED 指示 | 引脚串 1kΩ 接 LED 到地 | 相当于对地挂了个二极管加电阻,低电平被拉 | 下载前断开,或改到别的脚 |
| 按键检测 | 引脚接按键到地,配内部或外部上拉 | 按下时直接短地,SWD 无法通信 | 按键不要占用调试脚 |
| RC 滤波 | 引脚并 100nF~1μF 到地 | 边沿被拖慢,高速下必然失败 | 电容移到别的信号,或改 22pF 以内 |
| 驱动芯片输入 | 引脚直接接栅极驱动或运放输入 | 输入阻抗低,且有开关噪声 | 中间加 100Ω 隔离,或改用缓冲 |
| 强上拉/强下拉 | 1kΩ 到 VCC 或 GND | 调试器驱动能力不足,电平拉不动 | 换成 10k~100k 弱上拉 |
| TVS 管 | 引脚对地接 TVS | 结电容通常几十 pF,一般可接受 | 选低结电容型号即可 |
这里我想多说一句“驱动芯片输入”这一类。电动工具控制板上,MCU 的引脚经常要直接驱动预驱或者栅极驱动芯片的使能脚,这些脚的输入电容不小,加上板子上大电流回路就在旁边,SWD 通信时叠加的噪声能把一个干净的低电平抬到 0.8V 以上。表现出来就是“能连上,但下载到 60% 报校验错误”。这类问题最坑,因为现象不像连接失败,像 Flash 坏了。
2.3 可量产的硬件后门设计:跳线、零欧电阻和测试点
下面这套是我现在画板的标准动作,成本增加不到一毛钱,但每次救板都靠它:
第一,SWD 四线(VCC、GND、SWDIO、SWCLK)必须留测试点,且必须是裸铜或者沉金的开窗焊盘,不要被阻焊盖住。板子小的时候可以只留 4 个直径 1.0~1.2mm 的圆焊盘,间距 2.54mm 或者 1.27mm 都行,能插杜邦针最好。灌胶或者三防漆的产品,测试点周围留一圈阻焊开窗,方便后期刮漆。
第二,NRST 一定要引出来。这是 connect under reset 的前提,也是救砖的最后一道门。很多设计为了省一个焊盘把复位脚藏起来,结果板子一锁死就只能拆芯片。NRST 引出来之后,调试器可以在复位期间接管,成功率提升非常明显。
第三,SWD 两根线上串 0Ω 电阻或者留跳线焊盘。量产版本如果这两个脚被复用成了别的功能,把 0Ω 电阻拆掉,物理上断开外围,调试器就能干净地接管。这比改固件快得多,也比飞线体面。
第四,电源测试点。单独留一个 VCC 和一个 GND 的焊盘,方便调试时给板子独立供电,不依赖调试器供电。这一点在电机板上尤其重要,原因后面第 3 章会讲。
2.4 复位电路和共地:两个被低估的细节
复位电路看着简单,实际上坑不少。常见的接法是 NRST 上拉 10kΩ 到 VCC,对地并 100nF。这个 RC 时间常数是 1ms,够用。我见过有人并 10μF 做“防抖”,结果上电复位时间被拉到 100ms,调试器那边等不了那么久,直接判定连接失败。复位电容建议 100nF,最大不要超过 1μF。
还有一种情况:NRST 被配置成了普通 IO 输出。有些产品为了省成本,把复位脚当成了一个普通输出用来驱动 LED 或者蜂鸣器。这时候芯片就再也进不了复位态,connect under reset 完全失效,只能靠“上电瞬间抢占”这种碰运气的办法。看到这种设计我一般会直接建议改板。
共地这件事更隐蔽。调试器的地线和控制板的地之间如果隔了一条长排线,或者中间串了别的板子,回流路径变长,SWD 的参考电平就飘。表现是低速能连、高速不稳。我的做法是:调试时用一根尽量短的杜邦线,单独把调试器的 GND 和控制板的 GND 连起来,不要依赖排线里的那根地。电机板调试时,宁可不接电机,也不要让大电流回路和调试地混在一起。
3. 调试器侧:连接参数和时序配合的正确姿势
硬件没法改的时候,就得靠调试器的设置把窗口抢出来。这一块很多人只知道“换个调试器试试”,其实调试器的连接策略、时钟速度、复位类型这几个参数组合起来,能解决相当一部分“连不上”。
3.1 Connect under Reset 到底在做什么
先把原理讲清楚,后面所有操作才有依据。Cortex-M0+ 的 SWD 是两根线:SWDIO 双向数据、SWCLK 时钟。调试器上电后要完成一套固定流程:先发至少 50 个时钟周期的高电平做线序复位,再发切换序列,然后读 IDCODE 确认目标存在,最后通过 AHB-AP 访问内存和 Flash。
问题在于,这套流程必须在芯片“活着”的时候做。如果固件的 GPIO 初始化把 SWD 脚切走了,或者芯片一直处于复位态,流程就断在中间。Connect under Reset 的思路是:调试器先把 NRST 拉低,让内核停在复位状态;此时所有 GPIO 都回到复位默认态,SWD 引脚的复用功能自动恢复成调试口;调试器在这个状态下完成握手、接管内核;然后再释放复位,程序才开始跑。
这个机制的成立有两个前提,缺一不可:NRST 必须真的连到调试器并且能被拉低;芯片在复位期间,SWD 引脚必须处于可被外部驱动的状态(一般来说,复位默认是输入或者复用调试功能,这是符合的)。
实际操作中经常遇到的失败是:NRST 没引出来,或者调试器的复位输出脚没接,于是“复位连接”变成了软件复位,而软件复位对已经切走引脚的固件没用。所以第一件事是确认硬件上 NRST 真的通了。
3.2 时钟速度、复位类型和那些容易忽略的选项
连接参数我总结了一张表,按从快到慢的顺序试,不要一上来就用最高速:
| 参数 | 起手值 | 说明 |
|---|---|---|
| 时钟频率 | 100kHz ~ 500kHz | 先低速确认能连,连上后再逐步提速 |
| 复位方式 | Connect under reset(硬件复位) | 首选,成功率最高 |
| 备用复位方式 | 软件复位 / 系统复位 | 硬件复位不可用时退而求其次 |
| 复位后行为 | Halt(停下) | 让内核停在断点,不要直接运行 |
| 擦除方式 | 全片擦除 | 有保护位时先全擦 |
| 校验 | 先关校验下载一次 | 干扰大的板子上可临时关掉验证通信链路 |
有一点很多人不知道:降低时钟频率不只是为了抗干扰,它还能拉长握手过程的时间,让你更容易撞上固件启动前的那个窗口。我在一块启动极快的板子上,用 4MHz 怎么都连不上,降到 200kHz 之后反而稳定能连,就是因为握手时间从几十微秒拉长到了几百微秒,赶在 GPIO 初始化之前完成了接管。
还有一个参数值得试:“复位后立即暂停”。有些调试器默认是“连接上之后直接运行”,这等于连上就撒手,还没来得及擦除,固件已经把脚切走了。手动设成“暂停”,成功率会高不少。
3.3 手动配合上电时序:人和工具赛跑
调试器本身的自动流程搞不定的时候,就得手动插手时序。这一步看着原始,但成功率极高,我把它当成标准操作:
先不插调试器,把板子断电;用镊子或者杜邦线把 NRST 短接到地,保持住;插上调试器,点“连接”,这时候调试器会尝试拉低复位并握手;在调试器报超时之前,把短接线松开,让 NRST 回到高电平。整个动作要在两三秒内完成。
原理上就是把“复位保持”这件事从调试器手里拿过来,人工保证芯片在握手期间一直在复位。成功的标志一般是调试器弹出一个“检测到目标”的提示,或者能读出芯片 ID。读出来之后立刻做全片擦除,把固件清掉,这块板子就救回来了。
这个操作有个小技巧:短接 NRST 之后,先给板子上电,再点连接,比先点连接再上电成功率高。因为上电顺序决定了芯片内部的上电复位电路是否已经完成,先上电再连,芯片内部状态是确定的。
3.4 供电关系:调试器那点电流真的不够
这一条必须单独说,因为它在电动工具控制板上出现频率极高。通用 DAP 类调试器的目标供电输出一般只有几十到一百多毫安,而电动工具控制板上有大电容(电机母线上动辄几百微法甚至上千微法)、有预驱芯片、有降压电路。调试器一上电就要给这些电容充电,瞬间电流超出能力,调试器内部的电源直接跌落复位,于是你看到的现象是“调试器灯闪一下就灭了,一直连不上”。
我一般的做法是:控制板用独立电源供电(稳压电源或者电池),调试器只接 SWDIO、SWCLK、GND 三根线,VCC 线不接。两边共地,但不共用电源。这样调试器不会被大电容拖垮,也不会因为电源倒灌出问题。
还有一种情况是电池供电的板子电压偏低。锂电池放电到 2.8V 以下时,有些调试器的 IO 电平识别阈值就踩线了,怎么都连不上。调试时用稳压电源给到额定电压,别拿快没电的电池试。
4. 软件侧:在固件里留一个“下载窗口”
硬件和调试器都折腾完了,如果还是不稳定,那就得从固件上解决。这是最治本的一招,因为只要固件是你写的,你就能决定上电之后先干什么、后干什么。
4.1 上电延时窗口:最朴素也最有效的一招
原理很简单:芯片复位之后,GPIO 处于复位默认态,SWD 引脚还是调试功能。只要固件在配置 GPIO 之前多等一会儿,调试器就有机会连上来。这个“等一会儿”不需要很长,50~200ms 对调试器来说已经很宽裕了。
/* 注:寄存器名与时钟使能位以对应型号的头文件为准,这里只体现结构 */ static void boot_download_window(void) { /* 上电后先什么都不做,保持所有引脚为复位默认态 */ /* 这段时间内 SWD 引脚仍然是调试功能,调试器可以接管 */ for (volatile uint32_t i = 0; i < 400000; i++) { __NOP(); } } int main(void) { boot_download_window(); /* 必须放在所有外设初始化之前 */ system_clock_config(); /* 时钟配置:这一句之后引脚复用才开始生效 */ gpio_config(); motor_init(); while (1) { /* 主循环 */ } }注意几个细节。第一,这个延时必须放在所有时钟和 GPIO 初始化之前,放在后面没有意义。第二,延时循环里的变量要加volatile,不然编译器优化直接给你删了。第三,延时长度要实测:太短了没效果,太长了影响产品上电响应。电动工具要求“扣扳机就转”,但上电到可用状态有个一两百毫秒用户是感觉不到的,因为用户手指按下去还需要时间。我一般用 100ms 左右,既够调试器握手,又不影响体验。
这个窗口有个副作用值得提:量产固件里如果保留这段延时,每次上电都会慢一拍。我的处理是用条件编译区分调试版和量产版,调试版保留窗口,量产版关掉。
4.2 引脚状态自检:按住某个键才进下载模式
比固定延时更聪明的做法是:上电时先检查某个不冲突的引脚状态,如果检测到特定电平(比如某个按键被按住),就停在一个死循环里等待下载;否则正常启动。这样量产版本也不会有启动延时,只有维护时才进入下载模式。
/* 用一个不影响 SWD 的普通 IO 作为进入下载模式的判定脚 */ static void check_force_download(void) { gpio_input_init(DL_KEY_PORT, DL_KEY_PIN); /* 配成上拉输入 */ if (gpio_read_pin(DL_KEY_PORT, DL_KEY_PIN) == 0) /* 按键按下为低 */ { /* 关键:这里不要配置任何与 SWD 相关的引脚 */ /* 保持调试口默认状态,然后原地等待 */ while (1) { __NOP(); } } }这个方案要注意两点。第一,判定用的引脚绝对不能是 SWD 那两根线,否则一配置就把门关上了。第二,判定要在 GPIO 初始化之前做,而且这个引脚的初始化要独立、简单,不能牵连到其他外设。我一般会挑一个上电后本来就是输入态的引脚,比如某个检测脚或者没用的引脚,配成上拉输入,按下拉低,逻辑最干净。
如果板子上实在没有多余的引脚,可以用“组合条件”:比如上电时同时检测电池电压和扳机状态,两者组合成一个不常出现的状态,作为进入下载模式的暗号。这个方法不优雅,但能救命。
4.3 运行中收回 SWD:把调试口“还回去”的技巧
还有一种场景:固件必须长时间占用那两个引脚做别的事,但你又希望调试器偶尔能连上。这时候可以用“周期性恢复”的办法:在主循环里,每隔一段时间把 SWD 引脚临时切回调试复用功能一小段,给调试器一个连接窗口。
/* 调试版固件专用:周期性把 SWD 引脚还回去 */ static void swd_window_tick(void) { static uint32_t cnt = 0; if (++cnt < 500) /* 大约每 500 次主循环进入一次窗口 */ { return; } cnt = 0; motor_output_disable(); /* 先停掉会干扰的外设输出 */ gpio_set_af(SWDIO_PORT, SWDIO_PIN, SWD_AF); /* 切回调试复用 */ gpio_set_af(SWCLK_PORT, SWCLK_PIN, SWD_AF); for (volatile uint32_t i = 0; i < 20000; i++) { __NOP(); /* 保持窗口一段时间,让调试器有机会握手 */ } gpio_set_af(SWDIO_PORT, SWDIO_PIN, FUNC_AF); /* 再切回业务功能 */ gpio_set_af(SWCLK_PORT, SWCLK_PIN, FUNC_AF); }这个技巧的前提是:调试器在窗口期内能完成握手。实际操作时,把调试器设成“持续尝试连接”,它就会一直重试,总能撞上窗口。缺点是窗口期内业务功能会短暂中断,所以只能用在调试版固件里,量产版必须关掉。
我个人更推荐 4.2 的方案,因为它不影响正常运行;4.3 更适合已经烧进去、无法重新编译的板子做临时抢救。
4.4 低功耗、看门狗与复位循环对下载的影响
CW32L010 这类芯片在深度休眠时,为了省电会关掉内部调试时钟。这时候调试器连上去,芯片是“半死”状态,能读到 ID 但访问不了内核。处理办法:用 connect under reset,让芯片复位后再连,不要指望唤醒一个正在休眠的芯片。
看门狗也是常见障碍。如果看门狗超时时间设得很短(比如几十毫秒),而调试器下载一页 Flash 需要的时间比这长,那就会不停被打断,现象是“下载到一半复位重启”。调试阶段先把看门狗关掉,或者把超时时间设到几秒,量产再改回来。
还有一种更隐蔽的:固件里有异常处理,一旦进 HardFault 就复位。调试时因为引脚冲突或者时序问题,芯片一启动就 HardFault,然后不停复位。这种情况看起来像“完全连不上”,实际上是复位循环太快。处理办法同样是 connect under reset 加上电时序配合。
5. 兜底方案:SWD 彻底不通时还能怎么救
上面所有办法都试过还是不通,说明要么引脚被彻底焊死在外围上,要么芯片进了保护状态。这时候还有几条路可以走,按代价从低到高排列。
5.1 走芯片自带的引导程序,用串口下载
CW32L010 这类芯片出厂时 Flash 里预置了一段引导程序(Bootloader),上电时如果检测到特定的进入条件,就会停留在引导模式,通过串口接收固件。这条路完全不依赖 SWD,是救砖的首选。
操作上需要几样东西:一个 USB 转 TTL 模块,接到芯片的串口引脚(具体是哪两个脚,一定要去查对应型号的编程手册,不同封装和型号不一样,不要凭经验猜);然后按手册要求,在上电的瞬间把进入引导的引脚拉到指定电平;再打开上位机下载工具,选择串口、波特率,点下载。
这条路的坑在于:进入引导的引脚往往是复用的,可能是某个普通 IO,也可能需要特定的时序。我第一次操作的时候,手册看了三遍才对上时序,原因是那个引脚在复位后默认电平就是“不进入引导”,必须在极短的时间里手动拉一下。后来我用一个按键加 RC 延时搞了个小电路,一键进引导,省事很多。
还有个前提:引导程序可能被之前的操作擦掉过。如果之前用调试器做过全片擦除,把引导区一起擦了,那这条路也走不通了。
5.2 全片擦除与选项字节恢复
如果调试器能连上但报错,第一时间做全片擦除,而不是反复尝试读写。全片擦除会把 Flash 和选项字节一起恢复到出厂状态,读保护、写保护都会失效。
具体操作上,大多数调试器工具里都有“擦除整片”或者“解除保护”的按钮。注意的是:有些工具在做擦除之前会先读芯片 ID 和 Flash 大小,如果因为读保护读不到,它会直接报错退出。这时候要选“忽略保护并擦除”之类的选项,或者用专门的擦除模式。
擦除之后,芯片就回到了全新的状态,固件没了,SWD 引脚也回到复位默认的调试功能。这时候立刻用一个最简单的空程序把芯片点亮,验证链路通了,再慢慢往上加功能。
5.3 物理隔离与最后的换片
如果引脚被外部电路焊死,比如直接接了驱动芯片的输入,且中间没有隔离电阻,那唯一的办法就是物理断开。用热风枪或者烙铁把那一侧的引脚翘起来(如果封装允许),或者把串联的电阻拆掉。
小封装芯片(比如 QFN20)翘脚基本不可能,那就只能拆芯片。拆之前先确认板子上有没有留测试点,能不能从别的地方引线。我印象最深的一次是,一块已经灌了胶的板子,SWD 引脚上并了一个滤波电容,怎么都连不上,最后是用刀片刮开三防漆,找到那颗电容,用烙铁挑掉一个焊盘,才把程序下进去的。
所以还是那句话:预防的成本远低于抢救。画板阶段多留两个测试点、多串两个零欧电阻,能省下无数个加班的晚上。
| 兜底手段 | 前提条件 | 成本 | 成功率 |
|---|---|---|---|
| 串口引导模式下载 | 引导程序完好,串口引脚可用 | 低 | 高 |
| 全片擦除恢复 | 调试器能握手 | 低 | 中高 |
| 物理断开外围 | 有隔离电阻或可翘脚 | 中 | 高 |
| 拆换芯片 | 有备件和返修能力 | 高 | 高 |
| 飞线接测试点 | 板上有可用焊盘 | 中 | 中 |
6. 常见问题速查与踩坑实录
最后这一部分是我这几年在这个问题上积累的速查表和一些具体经历,都是常规文档里不会写的东西。
6.1 问题速查表
| 现象 | 最可能的原因 | 快速验证动作 | 处理办法 |
|---|---|---|---|
| 调试器提示找不到目标 | SWD 引脚被固件切走,或未供电 | 万用表量 VCC 和 GND,量引脚阻抗 | 用 connect under reset,或加启动窗口 |
| 冷机首次能连,之后不能 | 启动太快,窗口被吃掉 | 降速到 100kHz 试 | 固件加延时窗口或按键进入下载 |
| 能读到 ID 但无法 halt | 芯片在休眠,或复位被拉住 | 检查 NRST 电平 | 硬件复位后再连 |
| 下载到中途报校验错误 | 电源跌落,或干扰大 | 示波器看 SWD 波形和 VCC | 独立供电,短地线,降速 |
| 擦除报保护错误 | 选项字节有读保护 | 看工具是否能读 Flash 大小 | 选忽略保护全片擦除 |
| 下载成功但不运行 | 时钟配置错误,或看门狗 | 单步调试看停在哪儿 | 检查时钟树,关看门狗调试 |
| 十次能连上一次 | 干扰,或时序碰运气 | 换短排线,断开电机 | 加启动窗口,硬件滤波 |
6.2 三段踩坑经历
第一段是关于“以为芯片坏了”。某次一块新板子,怎么都连不上,我一度怀疑是买的芯片有问题,换了三片还是一样。后来拿万用表一量,SWDIO 对地只有 200Ω,顺藤摸瓜发现原理图上那个脚接了一个 LED 加 220Ω 限流电阻到地。LED 的正向压降加上电阻,把 SWDIO 的低电平钳在 0.7V 左右,调试器读出来一直是低。把 LED 挪到别的脚之后,一次就连上了。这件事教育我:下载不了先量阻抗,别急着换芯片。
第二段是关于“固件跑太快”。有个电动工具项目,开发板上下载没问题,装到成品板上就怎么也连不上。查了半天发现成品板的固件版本经过了优化,把所有初始化压到了 1ms 以内,而开发板上跑的是调试版,带了一堆打印和延时。解决方案很简单,在初始化最前面加了一个 80ms 的空循环,问题解决。同一个固件在不同版本上的启动时间可能差好几倍,这是很多人忽略的变量。
第三段是关于“供电打架”。一块带大电容的板子,调试器一插上去灯就暗,反复重启。后来用稳压电源单独给板子供电,调试器只接地和两根信号线,立刻就正常了。这个坑我踩过不止一次,因为现象看起来像“调试器坏了”,实际上是调试器的过流保护在起作用。
6.3 批量生产与售后阶段的延伸考虑
最后说几句超出“下载”本身、但和这个主题强相关的事。量产阶段,SWD 口通常会被复用掉,产线用一次性烧录夹具,烧完就不再碰。这时候要注意:烧录夹具的探针要压在专门的测试点上,不要压在会被固件配置成输出的引脚上。我见过产线夹具压在 PWM 输出脚上,结果夹具一压上去,板子就开始驱动电机,场面相当尴尬。
售后返修阶段,如果板子已经灌胶,SWD 基本没法接了,这时候串口引导模式就是唯一的救命稻草。所以我建议产品在设计阶段就把串口引导的两个引脚引到外壳内侧的测试点上,哪怕平时不用,返修时能省下整块板的成本。
还有就是程序版本管理。调试版和量产版最好用不同的编译宏区分,调试版保留下载窗口、保留 SWD 功能、关掉看门狗;量产版反过来。我见过有人图省事,把调试版直接烧进量产板,结果板子功耗偏高、启动偏慢,查了很久才发现是调试代码没关。
我个人在实际操作中的体会是,这类问题的核心从来不是“哪个工具更强”,而是你有没有在固件启动和硬件电路之间,主动留出那个几毫秒的缝隙。留了,什么问题都没有;没留,就得靠镊子、稳压电源和运气去补。画板的时候多留两个焊盘,写代码的时候多写三行延时,后面能省掉的事远比想象的多。