拓冰建站拓冰建站
首页 / 资讯中心 / 正文

嵌入式I2C通信失败排查全流程:从万用表静态检查到示波器NACK定位

做嵌入式这几年隔三差五就会碰到 I2C 通信失败的求助。两根线、一个上拉电阻看起来已经是总线协议里最简单的一种可真到了排查现场问题往往不是“信号有没有”而是“信号对不对”。我见过有人拿万用表量了半天电平最后发现是示波器触发电平没设对也见过有人用示波器抓了一整晚波形却没发现 SDA 在第 9 个时钟根本没有被从机拉低——也就是 ACK 缺失。这篇文章想把这套完整的排查流程走一遍万用表如何做静态体检示波器的触发、时基、探头怎么设ACK 在波形上怎么确认设备不响应时该按什么顺序缩小范围最后用一个真实案例收尾。无论你是刚入行的硬件工程师还是被 I2C 折腾到失眠的嵌入式软件调试党都可以把这里的方法当成一份可以直接复现的排查清单。1. 万用表先做静态体检电平、上拉与短路检查1.1 上电状态先看两根线的空闲电平I2C 是开漏结构SDA 和 SCL 在空闲时都应该被上拉电阻拉到高电平也就是对应 IO 电源的电平常见的是 3.3V 或 5V。上电后什么都不做把万用表打到直流电压档黑表笔接板子的公共地红表笔分别点 SDA 和 SCL正常情况下两支笔的读数都应该接近 VCCIO。如果某根线读数是 0V说明这根线在空闲状态下被某个设备拉低了或者存在对地短路。这时候不要急着怀疑协议先把线上的设备一个一个断开断开哪个之后电压恢复了问题就在哪个设备。这个方法在只有两个设备的总线上尤其快。我实际遇到过一块板子SCL 空闲电平只有 0.4VSDA 倒是 3.3V 正常。一开始以为是芯片输出坏了后来把挂在 SCL 上的一个电平转换模块断开电压立刻回到 3.3V再查发现是那个模块的输入端对地漏电。这种问题示波器也能看出来但用万用表点一下就能定位根本不需要上示波器。所以别嫌万用表“太初级”排查 I2C 的第一步永远是它。1.2 断电状态量上拉电阻和线路通断把板上所有电源关掉万用表切到电阻档量 SDA 到 VCC 之间的阻值正常应该看到上拉电阻的标称值常见的有 1kΩ、2.2kΩ、4.7kΩ、10kΩ。如果读数远小于标称值比如量出来才几十欧大概率有器件损坏或者焊连。然后再量 SDA 到 GND正常应该是开路或者阻值很大如果接近 0Ω说明有短路。同理把 SCL 也量一遍。别小看这几步我遇到过好几块“I2C 通信失败”的板子最终都是在这里发现焊盘连锡。上拉电阻值并不是随便选的。I2C 的上升时间要求和总线上挂的电容强相关标准模式 100kHz 要求上升时间不超过 1000ns快速模式 400kHz 要求不超过 300ns快速模式加强1MHz要求不超过 120ns。总线上每个芯片引脚、每厘米走线、每个连接器都会贡献电容整体 Cb 很容易到 100-200pF。用 tr 0.8473 × Rp × Cb 估算400kHz 总电容 200pF 时上拉电阻最多只能取到约 1.77kΩ这时候如果板子上放的是 4.7kΩ边沿就会变得很慢从机可能根本没法规整地采样到数据。这也是很多人换了更高速率之后通信突然不稳定的常见原因。1.3 万用表的边界哪些问题它永远查不出来万用表能确认的是静态状态有没有供电、有没有短路、上拉电阻对不对、线路有没有断。但它看不到时间维度上的东西比如 START 条件是否出现、SCL 时钟是否真的送到了从机、第 9 个时钟上 SDA 是否被拉低。这些信息必须交给示波器。另外补充一句有些老师傅习惯用指针式万用表比如 MF50量电压没问题但电阻档的刻度读法和数字表不同初次使用时要多对照几次免得读错量程。日常调试我基本只用数字万用表通断档带蜂鸣查连锡和断线非常顺手。用万用表把静态问题排除干净再上示波器你会发现自己看波形时脑子清楚得多。2. 示波器这样设触发、时基、探头三个关键点2.1 探头选择为什么我很少用 1x 档测 I2C第一件事不是按 AUTO而是把探头检查好。优先用 10x 衰减档因为 1x 档的探头电缆电容通常有几十到一百多皮法直接挂到 SDA 上等于往总线上加了一个不小的电容边沿会被拖慢本来能用的系统可能因为你的测量动作反而出问题。10x 探头输入电容一般只有 10-15pF对总线的影响小得多。带宽方面I2C 本身是低频协议但边沿是高速的一台 100MHz 带宽的示波器配 10x 探头看 100kHz 到 1MHz 的 I2C 都绰绰有余。地线还有一个容易被忽略的点地线夹尽量用短的弹簧地不要拖一根长长的鳄鱼夹线否则探头本身就会引入振铃毛刺看着像真故障其实是你测量方式造成的。我见过有人在电源轨上测出了几十毫伏的“纹波”最后发现是地线太长纯粹是测量伪影。I2C 这种低速总线虽然不像高速信号那么敏感但同样的道理一样适用。2.2 触发条件抓 START 而不是抓时钟I2C 的起始条件是 SCL 为高时 SDA 发生下降沿这也是主机发起一次通信的第一个动作。所以示波器触发要设为 SDA 的下降沿触发这样一按单次触发抓到的就是一整段完整事务从 START 到地址、数据、ACK、STOP 都在屏幕上。如果误把触发设在 SCL 上画面里随机落在一个时钟沿前后内容都是半截的看起来非常乱。触发电平一般设在 VCC 的一半左右比如 3.3V 系统取 1.65V这个值要避开信号的低电平和高电平区域否则触发点会抖。时基怎么选100kHz 模式下每一位时间是 10µs一个字节加 ACK 是 9 位也就是 90µs。要看完整的一帧操作时基放到 100µs/div 到 500µs/div 比较合适能同时看到地址字节和后面几个数据字节。如果只是想放大看 ACK 细节把时基收到 10µs/div 左右聚焦在第 9 个时钟脉冲上。幅度档位3.3V 总线下用 1V/div5V 总线下用 2V/div保证满幅显示又不会削顶。2.3 解码功能的正确打开方式现在绝大多数台式示波器都带 I2C 协议解码不少中端以上机型基本都有。打开解码后画面上会直接标出 START、地址、R/W 位、ACK/NACK、数据字节和 STOP排查效率比纯看波形高一大截。但解码出错时要先怀疑阈值而不是信号。很多示波器的 I2C 解码器需要你手动指定 SCL 和 SDA 的通道以及逻辑阈值电压。阈值设得不对比如 3.3V 总线设成 2.5V 阈值解码器可能把正常的低电平识别成高电平导致整个帧解析失败。我调试时习惯先把阈值设成 VCC 的一半波形上能看到明显的交叉点再微调直到解码稳定。另外提一个进阶技巧如果测试量很大需要长时间重复抓波形可以通过网口或 USB 连接示波器用 SCPI 指令远程控制。各家型号的指令格式略有差异比如力科的触发、采集指令和鼎阳的命名风格就不同但思路一致先预设触发条件发单次触发命令等采集完成后导出波形数据。脚本化的好处是可以连续跑几千次读写把偶发的不稳定通信抓个正着人不用一直盯着屏幕。3. ACK 缺失怎么看从波形到根因的完整定位链路3.1 先认识 ACK 在示波器上的样子I2C 的 ACK 机制很简单主机发送完 8 个位地址加 R/W 位或者一个字数据之后会释放 SDA让上拉把 SDA 拉高随后的第 9 个 SCL 时钟如果从机正常工作并且愿意继续接收它必须把 SDA 拉低保持到 SCL 高电平结束。从机在第 9 个时钟没有拉低 SDA就相当于给你回复了一个 NACK。示波器上怎么确认把画面放大到第 9 个时钟的高电平期间看 SDA 的电平。注意要在 SCL 上升沿之后去判断因为数据线在 SCL 为高时必须是稳定的——这是 I2C 的基本约定。如果 SDA 在第 9 个时钟的高电平区间是低电平说明 ACK 正常如果一直是高电平说明从机对这个地址和数据没有响应。3.2 地址阶段 NACK按这个顺序排查地址阶段收到 NACK是 I2C 排查里最常见的场景。按下面的顺序过一遍大部分问题都能定位地址对不对。这里有个经典坑7 位地址和 8 位地址。主机发地址时实际是 7 位地址加 1 位读写标志组成 8 位发出。很多芯片驱动里写的是“左移一位”后的值有些代码又直接填了 7 位原值。查 datasheet 时要先确认它给出的地址是 7 位还是 8 位格式再对照驱动的写法。地址脚有没有配好。很多 I2C 芯片通过 A0、A1、A2 或者复位期间某个引脚的电平来配置地址比如触摸芯片 GT911 的地址就和复位时的中断引脚电平有关。示波器上能看到主机确实发了一个地址而且从机也上了电但如果从机的地址配置脚没拉到位它当然不会应答。这一步经常是原理图里看着对、实板上却走了别的地方。从机是否真的在工作。检查从机供电、复位脚、使能脚有没有按 datasheet 的时序拉起来。GT911 这类触摸芯片对复位时序有严格要求如果复位脚一直被拉低芯片根本没启动SDA 上自然永远不会出现 ACK。总线是否被拉死。如果 SDA 或 SCL 空闲电平是 0V那这根线可能被某个设备或者短路拉住了ACK 无从谈起。先回到万用表那一步做静态检查。上拉电阻是否合理。前面说了边沿过慢会导致从机无法正确采样。把示波器时基收窄看 SDA/SCL 的上升沿是否明显倾斜超过规格上限就要重新算上拉。3.3 数据阶段 NACK和地址阶段是两回事地址阶段有 ACK但发数据时收到 NACK这时候问题往往不在总线而在从机的状态。最常见的两个原因一是从机正忙比如 EEPROM 在内部写周期里这期间它不会应答新的写数据二是当前操作不符合从机内部逻辑比如写入的寄存器地址超出了范围或者使能了写保护引脚芯片上的 WP 脚或内部寄存器里的保护位。还有一种情况是从机支持时钟拉伸它在内部处理时主动拉住 SCL如果主机驱动不支持等待也会表现为通信异常。示波器看这种情况非常直观SCL 在线路上停住不动比正常一位时间长很多那就是从机在告诉你“等一下”。排查 NACK 时还有一个很实用的软件手段让主机在启动时对 0x08 到 0x77 的全部合法 7 位地址做扫描每发一个地址就观察 SDA 上有没有 ACK。用代码写就是这样一个循环uint8_t addr; for (addr 0x08; addr 0x78; addr) { if (i2c_probe(addr)) { printf(device found at 0x%02X\n, addr); } }这个“地址扫描”本质上利用的正是 I2C 从机的 ACK 应答机制能快速找到总线上所有活动设备。如果扫描到了多个设备再看它们的地址是不是有冲突如果一个都扫不到那问题大概率在总线电气层或从机供电侧。配合示波器抓一次扫描过程你可以亲眼看到主机一轮一轮发地址、从机在哪一个地址上做出了应答。4. 逻辑分析仪做减法长时捕获与协议解码4.1 什么时候该换逻辑分析仪示波器的短板有两个一是通道少二是深存储贵。如果一条总线上挂了多个 I2C 设备你想同时看主机对每一个设备的访问两通道示波器就有点力不从心或者你想抓一段几毫秒甚至几十毫秒的长事务示波器的深存储模式要么慢、要么贵。逻辑分析仪刚好补上这两个短板。一个普通的八通道 100MHz 采样率的逻辑分析仪跑 I2C 绰绰有余。使用方法也简单SCL 接一个通道SDA 接另一个通道共地然后把解码器配置成 I2C告诉它哪一个通道是 SCL、哪一个是 SDA再设好阈值电压。我用的逻辑分析仪采样率通常设 25MS/s 到 50MS/s缓冲 1M 采样点时可以连续抓 20-40ms 的完整总线上电初始化过程这在示波器上很难做到。4.2 从波形问题变成数据问题逻辑分析仪的最大价值是它把“电压波形”变成了“数据流”。在软件里你直接能看到 START 条件、地址、每个字节、每个 ACK/NACK哪里断的直接标红。排查多设备总线冲突时逻辑分析仪可以同时观察多个从机的应答比如你怀疑有两个设备地址冲突抓一段主机广播地址的波形如果看到了两个设备都在 ACK那就是地址冲突。这在示波器上是很难分辨的因为波形上只有一个 SDA 信号无法区分应答来自哪个从机。4.3 三种工具的定位对比工具能快速确认什么局限性万用表供电、空闲电平、短路、上拉阻值、线路通断看不到时序、协议、毛刺示波器完整时序波形、边沿质量、ACK 电平、毛刺捕获通道少、深存储价格高、协议解码范围有限逻辑分析仪长时间协议解码、地址扫描、NACK 准确位置看不到真实电压幅度无法判断边沿质量日常排查我建议的顺序先用万用表排除供电、短路、上拉等静态问题再用示波器确认时序和 ACK如果问题表现为偶发或者需要持续观测再上逻辑分析仪。不需要反过来一上来就接一堆仪器反而容易迷失在细节里。5. 一次 GT911 通信失败排查从波形异常到根因确认这个案例我说过很多次因为它的每一步都很有代表性。一块触摸板用的是 GT911 触摸控制器主机端 I2C 枚举不到设备系统里触摸完全没反应设备管理器里也可能出现 HID-over-I2C 设备无法启动之类的报错。先用万用表做静态检查SDA 和 SCL 的空闲电平都是 3.3V上拉电阻 4.7kΩ 也正常GT911 的 VDD 3.3V 正常。静态检查没看出问题。接示波器触发设在 SDA 下降沿单次触发抓主机启动时的枚举事务。画面显示主机确实在 SCL 上发出了时钟SDA 上也有地址数据但到了第 9 个时钟SDA 一直是高——典型 NACK。到这里问题已经锁定在“有主机动作但从机不应答”。按地址阶段的排查顺序先怀疑地址配置。GT911 这类芯片的地址并不是出厂写死唯一的它在复位时序期间会根据某个引脚的电平状态来锁存地址。读驱动代码里面用的是地址 A看原理图复位引脚和这个地址配置引脚的连接看起来也没问题。于是用示波器双通道同时抓 GT911 的复位脚和中断脚对照 datasheet 的上电时序要求发现复位信号释放的时机比 datasheet 要求得晚而且中断脚在复位期间没有稳定到预期的电平。结果就是芯片上电后锁存了一个和驱动期望不一致的地址。根因确认后调整了复位脚的上电时序并修正了中断脚在复位期间的默认电平再次抓波形第 9 个时钟上 SDA 稳稳地被拉低ACK 出现主机枚举成功触摸功能恢复。这个案例想说明的其实是I2C 排查里ACK 只是结果不是原因。当你看到 NACK重要的是顺着“从机为什么不应答”这条线去检查从机的复位、供电、地址配置而不是反复去改主机侧的驱动参数。顺便多说一句这类触摸控制器的 I2C 问题很多时候系统日志里只会提示“I2C 通信失败”或者 HID 设备无法启动很多人第一反应是去重装驱动但实际上波形上一看完全是硬件时序问题。软硬件配合排查能少走很多弯路。6. 排查经验清单值得记住的细节和几个坑最后整理几条我的习惯做法都是实际项目中反复验证过的。第一永远先怀疑静态再怀疑动态。I2C 通信失败供电、地、短路、上拉这四件事占了大头。示波器接上去之前花五分钟用万用表把电平、阻值量一遍有时候省下一晚上的调试时间。第二示波器乱码先查阈值再查信号。解码器如果能出波形但解不出帧大概率是阈值没设对剩下的小概率是触发位置没抓到 START。不要一上来就怀疑从机。第三看到 NACK 时先分清是地址阶段的 NACK 还是数据阶段的 NACK。地址阶段 NACK 基本指向地址配置、从机供电、复位、上拉数据阶段 NACK 基本指向从机状态、写保护、寄存器范围。两者排查方向完全不同。第四用已知良品做对照实验。如果手头有一块确定能用的 I2C 器件比如一颗 AT24C 系列 EEPROM先让它挂在总线上用同一个主机代码去读写。能通信说明主机侧和总线上拉没问题问题在目标从机侧不能通信先把主机侧和总线侧查清楚再回头找从机。这个对照法在多层硬件故障叠加时特别管用。第五I2C 看似慢但测量时要注意探头电容、地线长度这些“测量本身引入的干扰”。我在一个项目里就遇到过设备原本通信正常用了一根带长地线的示波器探头去测量后总线开始偶发错误撤掉探头就恢复。后来确认是 1x 探头和长地线把边沿搞坏了。测量这件事本身也会改变被测系统。以上这些经验总结起来就一句话排查 I2C先静态后动态、先主机后从机、先总线再从机、先波形后数据。把这四层顺序理清楚绝大多数 I2C 问题都能在半小时内定位。最后再分享一个小习惯每次修好一个问题我会顺手把当时的波形截图和根因记录到本项目的调试笔记里下次再遇到类似 NACK翻笔记比重新查 datasheet 快得多。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门