拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

嵌入式偶发Bug排查实战:串口假故障、蓝牙断连与烧录失败定位

嵌入式偶发Bug排查实战:串口假故障、蓝牙断连与烧录失败定位 做嵌入式开发和硬件联调这几年我最怕的不是那种必现的崩溃而是“偶发的 bug”——串口偶尔收不到数据、蓝牙用着用着突然断开、烧录十次里有一两次失败。这种问题最折磨人因为不好复现工程师的直觉和经验往往派不上用场只能靠一个个变量去排除。最近正好处理了三个典型的偶发问题分别涉及串口假故障、蓝牙断开的取证以及新旧硬件批次带来的烧录差异。今天这篇就把这三条排查链路完整拆开说说我是怎么用换机排除、录屏取证和“新旧批次对照”三种方法把它们定位并解决的顺便聊聊偶发 bug 通用的排查框架。1. 偶发 Bug 为什么最让工程师头大先建立自己的排查框架1.1 偶发问题的本质复现概率低、干扰因素多、有效信息少偶发 bug 最恶心的点在于“不确定”。必现问题你打断点、加 log、二分代码半天就能锁定偶发问题你怀疑 A它偏偏不出来你怀疑 B它又冒出来了。本质上偶发问题是一个多变量系统频率、时序、温度、供电、电磁干扰、设备批次甚至操作人的手速都会影响结果。信息越少猜测越多最后就容易变成玄学排查。所以处理偶发问题我给自己定了一条铁律在动手改代码之前先花 80% 的精力把“现象”变成“证据”。证据包括时间戳、日志、录屏、串口抓包、烧录工具的错误码、硬件批次信息。没有证据的排查是碰运气有证据的排查才是工程。1.2 三个典型场景的共性与差异这次涉及的三个问题恰好覆盖了偶发 bug 的三种常见形态问题类型现象特征关键排查工具最大难点串口假故障时通时断、乱码、无响应串口助手、USB分析、电平测量分不清是硬件、驱动还是软件蓝牙断开使用中随机掉线、重连后正常录屏取证、协议栈日志、抓包无法复现缺少现场时间线烧录失败偶发校验错误、烧录后跑不起来烧录工具日志、批次记录新旧硬件差异被忽略表面上看这三个问题风马牛不相及但底层逻辑一致都要求你先稳定收集现场信息再把变量逐个隔离出来。下面我按实际处理的顺序把每条链路拆开讲。1.3 排查前的工具链准备日志、录屏、版本档案工欲善其事必先利其器。接到偶发 bug 的第一件事不是打开代码编辑器而是把这几样东西准备好带时间戳的串口日志工具我常用的是 PC 上的串口调试助手但必须开“时间戳”功能这样每一条收发都能对齐到毫秒级方便和蓝牙断开时间、烧录失败时间做交叉比对。录屏工具手机上的屏幕录制、PC 上的 OBS 或系统录屏都行。录屏不是给测试看热闹用的是为了留住操作序列和 UI 状态。硬件版本档案表包括芯片丝印、PCB 版本丝印、固件版本、烧录工具版本、日期码。这个往后细说但请记住没有批次信息的偶发 bug 报告等于废纸。2. 串口假故障换机排除法的实操细节2.1 现象描述串口“假死”和“假故障”怎么区分这次的串口问题很典型设备在产线上跑着跑着串口就不输出了或者输出乱码。看现象特别像单片机死机但复位设备后立刻恢复而且恢复后功能完全正常。这就很诡异——如果是真死机复位后应该还会复现如果是真硬件损坏也不会“休息一下就好”。我把这类问题叫“串口假故障”硬件没坏、软件没崩但链路就是通不了。常见的诱因包括USB 转串口芯片CH340、FTDI 等的驱动状态异常串口线接触不良或焊接虚焊受震动后偶发断开电平不匹配3.3V 设备接 5V 串口导致门限临界供电不足设备启动时拉低电压导致串口芯片复位。2.2 第一轮排查线序、电平、供电先排除低级问题在启动换机流程之前我习惯先把“物理层”过一遍这能省掉无数次无效换机线序验证拿万用表蜂鸣档测 TX、RX、GND 通断确认没有虚焊。很多“偶发断连”其实是一根杜邦线内部断了表笔一动就通、一松就断。电平确认如果对方的串口是 5V TTL而你的设备是 3.3V需要加电平转换电路。临界电平下信号在高低电平阈值附近抖动就会出现间歇性乱码。常见的 3.3V 转 5V 用三极管电路就能搞定但要注意上拉电阻的值太大翻转速度跟不上太小功耗又上去了。示波器看波形用示波器抓 TX 引脚的波形确认波特率误差。如果用的是 11.0592MHz 晶振配 9600 波特率误差很小但用 12MHz 晶振跑 9600 会有 0.16% 左右的误差长时间通信下来累积错位就会出现“偶发乱码”。2.3 换机排除法的正确打开方式一次只换一个变量我见过很多人做“换机排除”上来就换电脑、换线、换模块、换芯片结果问题依旧什么都证明不了。正确的换机排除法是这样的第一次换机换 USB 口/换电脑。如果故障消失基本锁定是 PC 端 USB 控制器或驱动的兼容问题如果故障依旧说明和电脑无关。注意换电脑的时候要同时观察是否安装了不同的 CH340 或 FTDI 驱动版本。CH340 驱动在 Windows 下有多个版本某些版本在高版本系统上会有偶发睡眠后无法识别的问题。第二次换机换 USB 转串口模块。把公版 CH340 换成 FTDI FT232 模块或者反过来。如果换完故障消失说明是模块自身供电/晶振/芯片个体差异导致。第三次换机换设备端串口芯片或整板。如果这时候才消失那问题大概率在设备端硬件或接线。这里有个关键点每次只换一个变量并且记录结果。哪怕只是从 USB 口 A 换到 USB 口 B也要在表格里记下来。我见过有人“顺手”把线也换了、把软件也重装了最后问题解决了他也不知道是哪个变量生效的。这就不是排查是碰运气。2.4 串口相关的更深一层的坑DMA、USB 虚拟串口、Linux 丢数据换机排除法解决的是“链路通不通”的问题但还有一种“假故障”藏得更深发生在软件数据链路层。串口 DMA 配置问题在 STM32 上使用串口 DMA 时如果 DMA 缓冲区大小设置不当或者没有处理半传输/全传输中断数据量一大就会偶发丢包。这种问题在低速场景下完全看不出来一旦跑高波特率或者长时间收发就会暴露。USB 虚拟串口STM32 的 USB CDC 虚拟串口在 Windows 上经常被识别成 COM 口但它的行为和一个硬件串口并不完全一样。USB 枚举失败、休眠唤醒后连接断开都会表现为“串口假死”。排查时要打开设备管理器看 COM 口是否消失而不是只看串口助手。Linux 串口接收丢数据Linux 下串口驱动默认的环形缓冲区如果被应用层读得太慢tty 层就会丢数据。常见表现为设备明明发了 100 字节应用层只收到 90 字节而且丢的位置不固定。这种情况首先要查应用层有没有用read循环及时读再看串口是否被配置为非规范模式必要时调大内核 tty 缓冲区或改用 DMA 方案。回到这次的串口问题最终定位结果是产线电脑的 USB 供电不稳导致 CH340 模块偶尔进入异常状态。解决办法也简单给模块换一个独立的 USB HUB 供电口问题就再没出现。但如果不做换机排除光看代码可能要把串口驱动重写一遍才能找到。3. 蓝牙断开的录屏取证从“听说断开”到“实锤”3.1 为什么必须录屏没有时间线的 bug 报告毫无价值蓝牙偶发断开是另一类非常难搞的问题尤其当产品是移动端 App 配合 HC-05、杰理蓝牙模块或者 ESP32 做 BLE 透传时。用户的反馈通常是“用着用着就断了”你如果问具体几分钟断的、当时在做什么操作、App 界面显示什么对方往往答不上来。所以我给测试同事定下规矩上报蓝牙断开问题必须附带录屏。录屏的价值不是给开发看画面而是把三件事关联起来操作动作的时间点用户点了什么按钮、切了什么界面App 界面状态的变化蓝牙图标、连接状态、日志显示断开发生前后 30 秒的细节是否有信号弱提示、是否有掉电重启。有了这个时间线你才能去比对系统蓝牙日志里的断开原因否则就是大海捞针。3.2 录屏的正确姿势不只是手机屏幕还要抓系统日志录屏取证听起来简单实际操作有几个细节手机录屏设置打开“显示触摸操作”这样能看出来是用户点了哪里以及触摸时间点是否和断开吻合。如果没有触摸操作问题可能是系统后台杀掉进程或者进入了低功耗模式。PC 端工具录屏如果调试的是电脑端蓝牙用系统自带的“录屏”“问题步骤记录器”都行关键是录屏要能覆盖到系统托盘里的蓝牙图标状态。系统日志同步抓取Android 手机用adb logcat -v time抓带时间戳的日志重点过滤BluetoothDevice、BluetoothGatt、bt_btif等关键词Linux 环境可以用btmon或hcidump抓 HCI 层的数据能看到底层断连原因比如Supervision Timeout、远程设备主动断开Remote User Terminated Connection还是本地控制器报错。App 内日志导出让 App 在 Debug 版里把蓝牙回调事件、错误码、重连尝试次数都打成日志并且提供一个“一键导出日志”的功能。这一点很关键没有日志的蓝牙 bug 报告基本只能靠猜。3.3 案例拆解HC-05 模块的连接断开和杰理蓝牙的电源抖动这次遇到的蓝牙断开问题初步看就像普通的信号干扰。用户 A 反映手机和 HC-05 模块透传距离 3 米左右就会断用户 B 反映稍微隔一堵墙就断。如果只看表面大多数人会去调发射功率、换天线。但把录屏和日志放在一起看出现了一个关键细节用户 A 断开之后手机蓝牙设置里 HC-05 直接消失几秒钟后才重新出现。这其实是模块重启了而不是蓝牙链路断开。也就是说问题不在射频而在模块供电。HC-05 这类经典蓝牙模块对供电很敏感瞬间掉电到阈值以下就会复位表现就是“断开-消失-重新被发现”像极了接触不良。再往下查模块供电来自主板的 3.3V LDO而这个 LDO 的输入是 5V 适配器适配器本身纹波偏大。当模块发射瞬间电流尖峰超过 LDO 的限流能力时输出电压跌落模块复位。解决办法换一个静态电流裕量更大的 LDO或者在模块供电引脚加一个大电容比如 100uF 钽电容 0.1uF 陶瓷电容。另一个案例是杰理蓝牙模块在车载环境下的偶发断开。这里的问题更隐蔽断开时间和车辆的某个用电设备启动吻合但模块本身供电没有问题。最后定位到是蓝牙天线附近的一个电源走线在特定频率下产生了干扰导致接收灵敏度骤降。这种问题不看协议栈日志根本定位不到因为底层上报的多是“连接超时”看起来像距离问题。3.4 蓝牙协议栈与工具从证据定位到射频层、电源层还是协议层如果你手头有抓包工具比如 Ellisys 或者 Frontline当然能看到最底层的数据包但对大多数嵌入式项目来说这些工具太贵也不常用。我更推荐先用系统的协议栈日志做初步分层如果断开码是0x08Supervision Timeout说明链路在一段时间内没有任何有效数据包链路监控超时了。这种最可能是距离远、天线干扰、或者对端设备进入了深度睡眠导致没有及时回应。如果断开码是0x16Connection Terminated by Local Host说明是本地主动断开要看本地是不是执行了disconnect或者系统内存不足杀掉了蓝牙进程。如果日志里根本没有任何断开记录但 App 显示断开那很可能只是 App 层没有处理好回调蓝牙其实还连着。这里有一个非常容易踩的坑很多 BLE App 会在蓝牙断开后尝试自动重连重连成功的瞬间会触发系统通知但不会更新 UI。如果录屏里发现“界面显示未连接但另一台设备能收到数据”那就要考虑是通信双方状态机不一致。这次的最终结论是HC-05 是供电问题杰理蓝牙的偶发断连则是天线布局干扰。两条线都不是靠“猜”猜出来的而是靠录屏和日志锁定了断开瞬间的上下文再针对性地去查电源和射频。蓝牙问题如果没有取证这一步就算你把蓝牙协议栈翻个底朝天也没用。4. “新旧批次对照”的烧录排查烧录失败背后的隐藏硬件差异4.1 现象同一套代码新板子怎么烧都失败旧板子一次成功第三个问题是烧录类的偶发 bug。现象是这样的生产线上用同一台电脑、同一个烧录工具烧录旧批次的板子成功率 100%换到新批次的板子就偶发失败——报校验错误、擦除失败、或者烧录后程序跑飞。代码没变工具没变唯一变的是硬件批次。这个问题特别容易引发“代码信仰危机”因为你可能反反复复检查工程配置、烧录算法、时钟初始化都没问题但新板子就是不听话。实际上问题几乎都出在硬件微小的差异上比如 Flash 芯片批次、主控芯片批次、电源时序差异、晶振负载电容差异等。4.2 建立“批次档案”不是记流水账而是记差异我的习惯是每拿到一批新板子先建立一份“批次档案”内容包括PCB 版本丝印和修改记录主控芯片丝印尤其是日期码/批号比如 STM32 芯片第 5 位字母代表批次外部 Flash 芯片型号和批次晶振型号、负载电容值电源方案LDO 还是 DCDC启动时序是否调整过烧录方式SWD、JTAG、UART 还是专用烧录器。听上去很繁琐但在排查偶发烧录失败时这份档案就是“对照组”。没有它你无法回答“新旧批次到底哪里变了”这个问题。4.3 Keil5、J-Flash、Flash Download Tools 与 ESP32 烧录失败的隐藏差异Keil5 烧录失败最常见的是“Cannot access Target”。如果旧板子能进、新板子偶发不能进先查复位电路和 SWD 引脚的上拉电阻。新一批板子如果省掉了 SWDIO/SWCLK 的上拉或者复位电容容值变大就会导致连接不稳。再一个容易被忽略的点是 Keil 的“Flash Download”配置里Programming Algorithm 要根据芯片具体型号选Flash 容量变了算法没换就会偶发地址溢出失败。J-Flash 烧录失败J-Flash 用 J-Link 烧录时如果目标板供电是 J-Link 提供的新板子电流需求变大J-Link 的 LDO 可能过流保护导致烧到一半断开。排查时看 J-Flash 日志里的电压信息确认 Vtarget 是否稳定。ESP32 烧录失败ESP32 使用 UART 下载时最经典的偶发问题就是“A fatal error occurred: Failed to connect to ESP32”通常和 EN 引脚复位时序、GPIO0 拉低时序有关。新旧批次如果改了 RTS/DTR 电平转换电路或者换了不同型号的 USB 转串口芯片时序就会不同。Flash Download Tools 的波特率如果设太高旧板行新板不行也要考虑芯片内部 ROM 引导的时序裕量变化。S19 固件烧录如果你用的是 S19Motorola S-record格式固件偶发烧录失败要格外注意地址段对齐。S19 文件里的地址是逻辑地址烧录器要根据芯片实际映射来写入。新旧板子如果更改了启动模式配置比如从片内 Flash 启动改成外部存储器启动S19 里的地址可能对不上表现为烧录成功但运行不正常。另外还有一个非常常见的元凶烧录电压和内核电压不匹配。很多芯片支持宽电压但内部 Flash 写操作对电压有严苛要求。新批次板子如果电源设计余量不足烧录瞬间电压跌落超过 Flash 写电压范围就会偶发校验失败。这不是烧录工具能解决的必须用示波器看烧录瞬间的电源波形。4.4 “新旧批次对照”的完整操作流程排查这次烧录问题时我用的对照流程可以复用把新旧板子放一起分别用同一根线、同一个烧录器、同一个软件版本烧录 10 次记录成功率交换变量旧板子用新板子的电源、新板子用旧板子的电源看故障是否跟着电源走对比 Flash 读 ID 结果烧录器读出来的 Flash ID 如果和算法里不匹配就是 Flash 批次差异对比芯片复位波形用示波器同时抓新旧板子的 NRST 引脚烧录时看复位时序是否一致。新批次板子如果加了大电容复位下降沿变缓会导致烧录器时序不满足。我这次遇到的情况最终定位结果是新批次板子更换了 Flash 芯片厂家虽然 ID 读到的一样但擦除时间更长导致原本的烧录超时阈值不够用偶发擦除失败。解决方法是把烧录器的擦除超时时间从默认的 3 秒调到 10 秒问题直接消失。这个案例告诉我们当代码没变、工具没变只有硬件批次变了时第一嫌疑人永远是硬件本身。不要急着改代码先把新旧批次的硬件差异列一遍。5. 排查偶发 Bug 的几条保命经验5.1 每次只改一个变量并做好记录这条我前面反复强调但还是要单独列出来因为它是偶发 bug 排查里最容易破防的一条。人脑的直觉在处理单变量问题时很靠谱多变量时就容易产生“我改的这个应该有用”的错觉。所以我在工位贴了一张便签“一次只动一个东西动了就要记”。改线、换模块、更新驱动、调整参数所有这些操作都要记录时间和结果。最后问题解决时你回看记录就知道到底是哪个变量起效而不是“稀里糊涂修好了”。5.2 记录一切log、截图、批次号、环境温度偶发 bug 最怕信息丢失。我处理过一个问题设备偶发重启后来靠客户提供的一张照片才定位到设备放在窗边中午阳光直射导致温度升高电源芯片过温保护。这种问题你让客户描述他只会说“机器会重启”但你让他拍照、记环境温度、记时间点就能发现规律。所以我的建议是给现场人员一个“信息收集清单”而不是一句“有问题联系我”。清单包括出现问题的时间点当时的环境温度、湿度、供电方式软件版本和硬件批次拍照丝印复现次数和频率当时的操作步骤日志、截图、录屏文件。5.3 让测试人员学会“按格式报 bug”测试人员往往是第一个接触现场的人如果他们的报告是“串口不通”“蓝牙断了”“烧录失败”开发根本没法开始。我整理了一个 bug 上报模板只有三个要点现象出现什么问题最好附带截图/录屏环境什么设备、什么版本、什么批次、什么供电方式操作序列出现问题的前一步做了什么。不要小看这个模板。它能把“偶发问题”快速缩小到“特定条件下的偶发问题”排查效率能翻一倍。尤其在跨部门协同时比如硬件说是软件的问题、软件说是硬件的问题有了格式统一的报告大家才能在同一张时间线上讨论。5.4 最后再分享一个我自己的习惯怀疑一切但先用证据淘汰变量处理完这三个问题我最大的体会有两点。第一偶发 bug 很少是“玄学”只是变量太多、证据不足。你如果能把录屏、日志、批次信息、环境数据收集齐再配合换机排除法一次隔离一个变量最后基本都能归因到某个具体的硬件差异、驱动状态或配置参数上。第二排查策略要按问题类型选择切入点。链路层问题用换机排除“做减法”交互层问题用录屏取证“补时间线”版本/硬件差异问题用批次对照“找变化点”。三种方法本质上都是制造对照组让问题从“偶发”变成“可复现”。我自己现在接到偶发 bug第一件事永远是先问一句现场有没有录屏、日志和批次照片有我大概率能当天搞定没有那我先让现场补证据再说。这不是推卸责任而是我用无数次熬夜排查换来的经验没有证据链的偶发 bug 排查注定是在浪费所有人的时间。
返回列表