ARTICLE DETAIL

资讯详情

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

嵌入式偶发故障排查实战:分层·取证·对照,解决串口蓝牙烧录难题

嵌入式偶发故障排查实战:分层·取证·对照,解决串口蓝牙烧录难题 做开发的人不管你是写单片机还是写Linux驱动最怕的不是那种一运行就崩的bug——那种bug固然让人抓狂但至少能复现真正让人头皮发麻的是那种偶发的故障串口打着打着就没了输出蓝牙连得好好的突然断线固件昨天还能烧进去今天就报错而且怎么试都稳定复现不了。我前段时间连着处理了几个这种案子串口假故障、蓝牙随机断开、新旧批次板子烧录表现不一致每一个都花了不少时间。回过头看这三个案子在思路上有很强的共通性而且都能总结成一套可操作的排查流程。今天这篇文章就记录一下这套方法论该换机排除的换机排除、该录屏取证的录屏取证、该做新旧批次对照的做对照希望能帮你少走点弯路。这篇文章不打算讲高深理论纯属实战记录适合正在被偶发问题搞到头秃的嵌入式工程师、学生创客以及做产品的开发者。1. 偶发bug为什么难缠先分清故障层级1.1 偶发问题不等于代码问题先说一个我的观点偶发的bug第一反应不应该怀疑代码至少不能只怀疑代码。为什么因为代码的执行逻辑是确定的同一份代码、同样的输入理论上结果是可复现的。如果它是必现问题那一定是你还没找到触发条件如果它真的是偶发那问题大概率出在不在代码控制范围内的环节——比如供电、时序、干扰、温度、驱动、操作系统调度。所以排查偶发bug的第一步不是打开IDE疯狂加日志而是先做故障分层把目标板和宿主环境分开。拿串口来说目标板就是MCU宿主环境是PC上的USB转串口工具、驱动、串口助手。蓝牙呢目标板是蓝牙模组和协议栈宿主环境是手机、电脑的蓝牙协议栈和射频环境。烧录呢目标板是你的MCU和下载接口电路宿主环境是Keil、J-Flash、下载器。每一层都有可能制造偶发故障但处理的办法完全不同。我见过太多人一遇到问题就冲进代码里改改了一圈没效果最后发现是电脑上两个串口工具在抢同一个COM口。这种时间浪费太可惜了。所以我现在给自己定了一条规矩接到偶发bug的前两个小时不动代码只做环境排查。1.2 把偶发翻译成条件偶发这个词我理解得越来越透之后发现问题的核心不在偶发在于你缺少触发条件的知识。一个故障要在某个概率下发生背后一定有一个或几个条件在起作用可能是电压掉到某个阈值以下可能是某个中断优先级发生了竞争可能是USB枚举时机不对也可能是外部干扰把波形拉坏了。我的建议是从接到这个bug的第一时间就开始记录所有环境参数什么设备和什么设备连接供电是USB还是外部电源环境温度固件编译时间和git版本号前一天改了什么这个记录最好是一张固定的表格因为偶发bug的信息往往是在你不经意的时候冒出来的等它消失了再去回忆全是模糊的。把感觉变成证据这一条在后面每个案例里都会反复出现可以说它是这篇文章真正想讲的让偶发问题暴露在证据链之下而不是靠直觉去猜。2. 串口假故障换机排除法怎么用才有效串口问题大概是嵌入式人每天都要打交道的事情。我在热搜词里看到串口调试助手ch340串口驱动ftdi串口驱动虚拟串口软件串口dma这些关键词说明串口相关的坑是所有人的共同记忆。我这次遇到的case很有代表性客户报修说设备串口经常无输出有时候重启就好客户觉得是固件bug。我拿到手之后先跑了一晚上一切正常。后来发现一个规律这是在生产测试环节报的问题而测试用的是车间的一台老电脑系统里同时装了三个不同的USB转串口驱动。2.1 假故障的三个伪装串口假故障最常见的三个伪装分别是驱动混乱、端口被占、电平不稳。驱动这块不必多说了CH340和FTDI这两大类芯片是USB转串口的主力但它们的驱动在不同Windows版本下表现差异非常大。尤其是系统自动更新驱动之后经常出现端口号改变、设备变成未知设备、或者可以识别但一打开就报端口被占用。更麻烦的是如果一台电脑上既有CH340又有FTDI还有虚拟串口软件生成的串口设备管理器里一大排COM口实际是哪个根本没准。车间那台老电脑就是这种状态串口助手打开COM3数据去的是Prolific芯片实际板子挂在CH340上能通才有鬼。端口被占也是高频问题。很多工控上位机软件、旧版本串口调试助手退出时没释放串口句柄再开其他软件就永远打不开同一个端口。这类问题有个典型特征重启电脑之后一切正常跑一会儿又出问题。你这时候去跟客户解释不是固件问题客户还不信因为在他的视角里设备就是工作一段时间后坏掉。电平不稳则是硬件层面的。标准UART电平是3.3V或5V但很多传感器模块、蓝牙模块是1.8V电平的如果你直接用3.3V去怼1.8V的UART高低电平的阈值判断就会出问题。典型表现是偶尔能收到数据、偶尔乱码、偶尔收不到而且和线长、温度、相邻导线干扰都相关。2.2 换机排除的标准流程换机排除不是随便换一台电脑试试而要控制变量。我这里列一下我惯用的步骤照这个顺序做基本能把宿主环境类的串口假故障扫干净。第一步换USB口。优先用主机后面板直连的USB口绕过USB Hub。USB Hub的供电和信号完整性都差一截我自己遇到过换了两个口都不行、换到后置直连口立刻正常的情况。第二步换机器。从正在用的电脑换到另一台确认有正常串口功能的电脑上。这一步如果恢复正常那问题就锁定在原有电脑的环境上板子本身没问题。第三步换线。串口线、杜邦线都要换特别是那种长时间插拔、焊点松动的杜邦线接触不良在低速下症状不明显。第四步换驱动版本。回退到旧版驱动或者卸载驱动后重新插拔设备让系统重装一次。第五步换串口助手软件。把厂商自带的、SSCOM、XCOM这些交叉着试。有些软件对新芯片的支持有问题或者DPI缩放导致界面显示错位也会让你误以为没收到数据。每一步做完都要记录结果不要跳过。很多你觉得应该不会吧的环节恰恰就是问题所在。2.3 电平转换与驱动两个容易被忽略的坑在串口相关的假故障里有两个坑很值得单独拿出来说。第一个是电平转换电路的设计。从热词里能看到串口3.3转1.8v电平转化三极管电路这个搜索词说明很多人在这一块踩了坑。常见的三极管电平转换电路有两种单向和双向的。单向电平转换如果用在双向UART上就会出现发送正常、接收丢字节/乱码的现象。因为MCU的TX到模块的RX是单向没问题但模块的TX回来时也需要把1.8V拉高到3.3V域如果不做双向电平转换回来的信号就只拉到了中间电平导致MCU误判。判断这个问题有个很朴素的办法用示波器看波形看TX方向波形是否干净、RX方向波形幅度是否足够、有没有慢边沿。如果只是拿万用表测电压你会看到电平好像是3.3V但带载后的瞬态响应完全不一样。第二个坑是三极管电路的静态工作点。某宝买的很多电平转换模块用三极管搭的集电极上拉电阻和基极电阻取值不合理换到负载较重的模块上波形就变形了。这种问题最阴的地方在于在A模块上好好的换到B模块就乱但换回A模块又正常让你一直怀疑是B模块的固件问题。第二个是虚拟串口软件和串口DMA的问题。虚拟串口软件比如USB转虚拟COM、网络串口服务器会引入额外的延迟和丢包这在普通调试时无所谓但在固定波特率、大数据量传输时很容易表现出偶发丢数据。如果你在调试时发现数据流偶尔有空洞先把虚拟串口排除掉用物理串口对比一次就知道了。串口DMA则是另一层问题。DMA模式下如果环形缓冲没有处理好或者使用了非阻塞发送但复用缓冲区会出现间歇性丢数据但这是软件的稳定性问题不是假故障别和宿主环境类问题混在一起排查。3. 蓝牙断开录屏取证把偶发变成可复现蓝牙问题的特点是看不见摸不着不像串口那样有线可以抓。尤其是HC05、杰理蓝牙、ESP32这类模块配对、连接、数据传输链路里任何一个环节出问题表现在最外层都是又断了。你问客户什么时候断的他说就是突然断的。你问断之前做了什么他说什么都没做。这就没法排查了。所以我的办法是录屏取证。3.1 为什么蓝牙问题必须录屏因为蓝牙断开的瞬间稍纵即逝如果你不在现场等回到工位只能看到断线结果根本不知道断开瞬间发生了什么。录屏能提供一份现场记录手机蓝牙设置页、串口日志窗口、板载LED状态三个画面同框录制。当断开发生时你可以知道断开前1秒板子和手机各自的状态。有人可能会说我有日志啊抓HCI日志、AT日志不都一样吗不一样。日志是抽象的而且很多情况下日志的写入频率不够日志里只有断开这两个字完全没有上下文。录屏提供的视觉信息能帮你建立对现场的直觉是不是手机息屏了是不是有人靠近了实验台是不是电源指示灯闪了一下这些信息是日志不会告诉你的。另一个现实痛点很多断开事件是低频偶发有时候一小时断一次。你不可能一直盯着屏幕而且人的注意力撑不了那么久。录屏就是要解放眼睛把盯变成录让偶发事件自己暴露在录像里。3.2 录屏取证的具体操作具体做法不复杂但有一些细节。第一步架好机位。手机用三脚架固定或者拿书顶起来对准实验台。第二步保证同框。画面里必须同时出现三样东西开发板/蓝牙模块的状态灯、串口监视器窗口、手机蓝牙设置页或者上位机连接界面。缺一样都不行因为你要记录的是同时发生的事件不同框就得靠时间戳对齐麻烦得多。第三步设置时间戳。手机屏幕自带的时钟、或者电脑右下角时钟必须入画。没有时间戳的录像价值打五折。第四步长时间录制。找块充电宝给录制手机供电开着录制放一边该忙什么忙什么。第五步事件发生后再回去翻录像定位断开的时间点。翻录像不用一秒一秒看可以先看串口日志的时间戳找到断开时间再到录像里跳转到对应位置看现场。录屏之前最好先把串口日志打开把AT指令输出、连接状态打印都开出来。这样录像里既能看见现象也能对应上日志里的时间线。两者对齐才能判断断开是协议层主动断开的还是链路物理消失的。3.3 从录像里找出断开前一秒录屏的价值最终体现在你能从录像里找出触发前状态。我举一个实际碰到的例子。某设备使用HC05模块客户反馈蓝牙不定时断开有时十分钟断有时一两天都不断。我按上面的方法录了三个小时回看录像时发现一个共同的细节断开前的几秒手机屏幕亮了或者手机有过一次通知推送。这个我称之为触发前状态。顺着这个线索去查最后定位到模块供电走的是MCU板上的3.3V LDO手机亮屏瞬间射频发射功率变化板子上的电源被拉出毛刺模块供电电压跌到2.9V以下射频链路就断了。还有一个例子ESP32的BLE连接断开总是上位机主动断的因为收到的数据校验出错、重试次数达到上限。单看日志只能看到Connection terminated这个结果但录像里能看到断开总是发生在某类特定数据操作之后。配合协议分析工具最后发现是广播数据里的某个字节在特定长度时会被分包成错误长度导致对端解析失败。如果没有录像我根本不会把断开和这类数据操作关联起来。这里多说一句蓝牙模块的供电是我见过的最容易毙掉蓝牙稳定性的点。HC05、杰理蓝牙这些经典模块工作电流峰值能到50mA以上瞬间电流更高。如果你用的是LDO加一个大电容这种比较粗糙的供电设计遇到射频突发就很容易掉电压。排查蓝牙偶发断开的顺位应该是供电、天线匹配、射频干扰、协议配置、上层逻辑。前三个属于硬件可以先于软件排查。4. 新旧批次对照烧录失败排查法4.1 同一个hex一批能烧、一批不能烧烧录失败是嵌入式开发里最常见也最烦人的问题之一。特别是这种情况同样的代码在老批次的板子上用Keil5或者J-Flash一点就烧进去新批次板子死活连不上或者烧到一半报错。这时候你的第一反应可能是新板子坏了但往往不是。能编译成功、烧录不进去说明问题出在烧录这个环节本身而不是代码。热词里keil5烧录失败jflash烧录程序esp32烧录方式flashdownloadtools烧录esp32海思烧录工具c6748串口烧录stm32usb烧录程序的步骤这些都是同一类问题的不同变体。不管什么芯片、什么烧录工具烧录失败的核心原因高度集中连接时序、供电、芯片配置位、固件地址。还有一个值得注意的是MOTOROLA S-RECORDS19固件烧录记录分解这个热词。S19/SREC格式和hex一样文件内部自带起始地址信息。如果你用J-Flash或者别的工具加载这类文件指定了错误的基地址那就是烧进去了但程序完全没跑到该去的地方表现为不上电、启动异常、偶尔能跑偶尔跑飞。这种问题特别隐蔽因为它不是烧录失败是烧录成功了但没烧对地方。4.2 对照实验该怎么设计新旧批次对照的核心是列出差异表。不是简单地把两块板子摆在一起看而是要把你能想到的每一个变量都列出来然后逐个排除。我的做法是这样一个流程第一步确认固件文件完全一致。用MD5校验hex或bin确保不是烧错固件版本。这一步比你想的重要我有一次排查了半天最后发现编译输出目录里有两个同名hex一个旧一个新命令行脚本烧的是旧的那个。第二步排除烧录环境变量。新板子先接到旧烧录环境旧电脑、旧下载器、旧线上试确认是不是新电脑新下载器新板子三个新变量叠加出的问题。这一步能快速缩小范围。第三步新板子换不同下载器、不同烧录软件交叉验证。比如SWD烧录不行换ISP/串口烧录看看J-Flash不行换Keil的Flash Download看看。如果不同工具都失败问题大概率在板子硬件如果只有特定工具失败那就是工具配置/兼容性问题。第四步对比新旧板子的原理图、BOM、芯片丝印。特别注意晶振、复位电路、BOOT引脚上下拉、电源纹波释放电容。芯片厂商换批次是很常见的事丝印上后缀不同可能就代表内部选项字节默认值不同、支持的工作电压范围不同、或者是同一个型号但工艺版本不同烧录时序的参数都有差异。第五步对半导体批次敏感的器件做记录。MCU本身、Flash芯片、下载器、晶振这几类器件的批次变化都可能引起烧录行为不同。我碰到过一个非常典型的案例新批次板子上MCU的BOOT引脚多了一个下拉电阻导致上电之后BOOT0电平不对每次上电有40%概率进入ISP模式而不是运行模式表现就是烧录能成功但一复位就跑飞或者烧录时读不到芯片ID。这种问题不对比新旧BOM是看不出来的而且位置极其隐秘。4.3 三种常见烧录失败的根因这里总结三个我遇到频率最高的烧录失败根因每个都有自己的坑。一是供电能力不足。下载器通过SWD/JTAG接口给目标板供电的情况很常见但如果目标板上有比较多的外围器件或者电源网络有微短路下载器那点电流就不够了。J-Flash报cannot connect to targetESP32的FlashDownloadTools卡在Connecting...很多都是这个原因。排查方法很简单用外部电源单独给板子供电再试烧录。二是时序和电平问题。SWD接口对时序敏感杜邦线超过20厘米就很容易失败。JTAG和SWD混用未配置、目标芯片电压域和下载器电平不一致也会导致连接不稳定。有时候你看到偶尔能连上、偶尔连不上多半是电平边界问题用示波器看下载接口的时钟线、数据线波形边沿如果不够陡峭就会在批量生产中出现概率性失败。三是固件地址配置问题。前面提过的S19文件还有Keil的Flash算法选择、ESP32的烧录地址分区表都容易踩坑。只看烧录成功远远不够要确认烧进去的内容落到了正确的Flash地址。特别是用FlashDownloadTools烧ESP32的时候地址设错了程序能烧进去但完全没有预期行为这个比烧录失败更迷惑人。5. 三类问题速查表与避坑清单5.1 速查表把文章里提到的三类问题整理成一张速查表日常排查时可以直接对着看。症状常见嫌疑快速验证手段串口偶发无输出/乱码驱动冲突、端口占用、电平转换电路设计问题换机、换USB口、换串口助手、示波器看波形串口正常一段时间后失效虚拟串口/上位机未释放串口句柄、USB进入省电模式重启电脑复现、关闭省电模式、更换物理串口蓝牙不定时断开供电瞬态跌落、射频干扰、协议栈主动断开录屏取证、串口日志时间戳对齐、示波器测模块供电同一固件新旧板烧录表现不一致BOOT引脚电平、芯片批次差异、下载器驱动能力新旧BOM对比、外部供电测试、换下载器和烧录软件交叉验证J-Flash/Keil报连接失败供电不足、SWD线过长、复位电路异常独立供电、缩短杜邦线、检查复位电容烧录成功但程序不运行固件地址偏移、BOOT配置错误、Flash算法不匹配核对hex/S19地址信息、检查BOOT引脚、确认Flash下载算法5.2 我的几个通用避坑习惯文章最后把我日常排查偶发问题的一些习惯也分享一下这些习惯帮我在这次梳理过程中少走了很多弯路。第一遇到偶发bug第一件事永远是建一个排查笔记。不用很正式手机上随便一个备忘录或者一个txt文件就行。记录问题现象、发生时间、当时的环境、你做了什么操作、结果如何。排查结束之后这个笔记就是你的结案报告。很多奇怪的问题其实是多个看似无关的偶然因素叠加导致的笔记能帮你把它们串起来。第二涉及到看不见摸不着的问题第一时间用录屏或者拍照把现场固定下来再动手排查。蓝牙断开、串口闪断、偶发复位都适用。眼睛不靠谱记忆更不靠谱证据才是唯一可靠的起点。第三尝试分离变量一次只动一处。尤其是排查偶发故障千万不要同时换电脑、换线、换板子、换软件。变量越多越不可能知道是哪一个因素起了作用。一次只换一个因素并且做记录才能慢慢逼近真相。第四不要轻视批次差异。芯片、Flash、晶振、下载器的批次差异都能引起偶发故障。生产过程中只要换了料不管供应商怎么说完全兼容都要做一次最小化的验证。第五借助工具更快定位。出于好奇我用过一个带串口记录功能的串口调试助手对排查偶发数据还会用多线程串口工具热词里也提到前端怎么打断点调试bug如何浏览蓝牙协议core_v5.3等词说明很多人也都在寻找更合适的工具。合适的工具比加倍努力更重要。我在实际操作中的体会是偶发bug最大的敌人不是bug本身而是懒得记录、急着动手的心态。你越是用主观感觉去猜越是容易原地打转。按照分层——取证——对照这个流程走一遍大多数问题都会在证据面前现出原形。当然我自己也还在不断踩新坑这套方法论后续还会继续补充。
返回列表