ARTICLE DETAIL

资讯详情

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

I2C调试实战:从万用表、示波器到ACK应答识别

I2C调试实战:从万用表、示波器到ACK应答识别 上周帮同事调一块板子MCU 通过 I2C 读温湿度传感器读数永远是 0xFF。他先用万用表量了两根线SDA、SCL 都能量到电平觉得总线没问题可数据就是不对。我过去把示波器探头怼到 SDA 上触发设为下降沿抓了一帧波形放大一看地址字节发完后第 9 个时钟周期里 SDA 一直是高——从机压根没给出 ACK。这个问题很典型也暴露了一个常见误区万用表只能证明总线静态电平正常I2C 的真正问题经常藏在动态时序和应答位里。所以我把从万用表、示波器到 ACK 识别的一整套排查路径写下来给同样被 I2C 通信失败折磨过的开发者一个能直接照着做的流程。1. 为什么先从万用表开始静态电平、上拉电阻与短路筛查很多教程一上来就让你掏示波器但我的习惯是先拿万用表做一轮快速筛查价格便宜、操作快而且能把一大批低级问题直接排除掉。示波器和逻辑分析仪是抓动态问题的但如果你板子上的 I2C 总线压根没上拉电阻或者 SDA 被焊短路了上示波器反而容易看得一头雾水。1.1 万用表能确定的三件事电平、短路与上拉第一件事是测量空闲状态下的静态电平。把万用表拨到直流电压挡黑表笔接 GND红表笔分别点 SDA 和 SCL。I2C 总线在空闲时两根线都应该被上拉电阻拉到高电平数值应该接近 VDD。如果量到 SDA 被拉低到接近 0V说明有设备在占用总线或者某个从机异常拉死了 SDA。这种情况你直接上示波器看到的可能是一团乱波形甚至看不到任何边沿因为总线从头到尾都是低电平根本没有数据翻转。第二件事是断电后的通断测试。这里要强调一下必须断电最好把板子的电源完全断开再测。用万用表的通断挡从主控芯片的 I2C 引脚出发分别测到每个从机引脚的连续性。板子上多从机共总线时虚焊、断线、过孔不良都会导致某一路信号缺失。通断测试能在五分钟内把这种物理层问题找出来。第三件事是测量上拉电阻。断电后用电阻挡测 SDA 和 SCL 引脚对 VDD 的阻值对比原理图上的预期值常见的是 2.2k 到 4.7k。这里有个小坑如果总线上并联了多个设备电阻挡量出来的读数会比单个上拉电阻小因为等效电阻是并联关系。你量到 1k 左右不一定是上拉电阻焊错了可能只是两个 2.2k 并联的结果。所以这个测量只能做粗略参考别绝对化。1.2 万用表测不了动态时序别让它背锅万用表本质上是一个平均值工具它显示的是信号在一段时间内的统计结果对 I2C 这种边沿触发、事件驱动的协议几乎没有诊断能力。举个极端例子总线上一帧数据里 SDA 在高低电平之间来回翻转万用表会显示一个介于 VDD 和 GND 之间的电压值比如 1.6V。有些新手看到这个值会以为总线“状态不对”实际上这完全正常只是因为信号变化太快万用表积分出来的平均值落在了中间。反过来如果总线确实卡死在半电平万用表也会显示一个中间值但此时示波器能看到信号根本就没有满幅跳变。所以说万用表的读数只能回答“高低电平是否存在”回答不了“边沿是否按时出现、ACK 是否存在”这类动态问题。1.3 万用表测量时最容易出现的两个误判第一个误判是带电测电阻。板子还在供电时去测上拉电阻读数会被电路里其他通路干扰甚至完全错误。我见过有人带电测出上拉阻值只有几十欧以为电阻烧了结果只是 VDD 到 GND 之间有其他低阻通路。正确做法是彻底断电最好等板子电容放干净再测。第二个误判是忽略表笔接触电阻。I2C 测试点经常是细走线、过孔或者 QFN 封装的引脚普通表笔尖很难压稳稍微一动就接触不良量出来的电平会随机跳变导致你误判“总线不稳定”。我的做法是在测试点上直接焊一根短的杜邦线或者用夹子夹住确保接触可靠。这一点在测小封装芯片时尤其重要别让接触问题浪费你半小时。2. 示波器抓波形的三个关键设置触发、采样率与时基万用表筛查完确认静态电平、上拉电阻和通断都没问题之后才轮到示波器出场。示波器测 I2C 的核心不是把探头一夹然后看波形而是要让示波器在正确的位置停下来、以足够的分辨率记录数据。触发、采样率、时基这三个设置决定了你抓到的是能定位问题的波形还是一团没有意义的乱线。2.1 没有 I2C 触发时用下降沿触发抓 START高档示波器通常带 I2C 协议触发选件可以直接设置从机地址和读写方向触发到指定帧。但很多入门级示波器没这个选件这时候最实用的替代方案是把触发挂在 SDA 上用下降沿触发。原理很简单I2C 的 START 条件就是 SCL 为高时 SDA 从高到低跳变这一跳必然是下降沿。你只要抓到 SDA 的第一个下降沿接下来跟着的基本就是一帧完整通信。具体操作上我建议通道 1 接 SCL、通道 2 接 SDA这样两根线的时序关系一眼就能看清。触发电平设在 VDD 的一半左右触发模式选 Normal 或者 Single。总线空闲时间长的板子用 Single 模式手动触发一次最稳妥不然示波器可能会被其他边沿反复触发抓出一堆无关波形。还有一个小技巧如果示波器支持“释抑时间”Holdoff可以设置成稍大于一个字节的时间比如 100us 左右这样匹配触发器会跳过之前的边沿更容易直接停在目标帧上。2.2 采样率与时基怎么取舍单帧和间歇故障两套打法抓单帧波形和抓间歇性故障对采样率和时基的要求完全不同我先说结论以 100k 标准模式为例SCL 周期是 10us一个字节加 ACK 总共 9 个时钟周期大约 90us。抓完整帧时基放在 20us/格到 50us/格比较合适。采样率至少要有 2MSa/s也就是每个时钟周期至少采 20 个点这样才能看清 SDA 在第 9 个时钟的高低状态。如果你要排查的是偶发故障比如一小时出现一次通信失败那就要靠长时基加浅存储深度或者直接用逻辑分析仪挂机。普通示波器的存储深度一般是 4M 到 10M 点按 1MSa/s 采样只能记录大约 4 到 10 秒对于“几分钟才错一次”的场景远远不够。逻辑分析仪在这方面有天然优势几十 MSa/s 采样率连续记录几十分钟毫无压力而且解码 I2C 比示波器更直观。所以我的原则是单帧、看边沿、量时序用示波器长时间监控、频繁交互、数 ACK 用逻辑分析仪。两者互补不是替代关系。2.3 探头输入电容会悄悄改变上升沿很多人没注意示波器探头本身是有输入电容的。普通 10x 无源探头输入电容大约 10 到 15pF1x 探头更高可能到几十 pF。I2C 总线靠的是上拉电阻给寄生电容充电产生上升沿总线电容越大上升沿越慢。如果你总线上已经承载了多个从机、走线又长电容本来就接近临界值探头一接上去等效电容增加上升沿会变得更慢甚至导致原本能工作的总线开始出现偶发错误。这就产生了一个测量悖论你接上仪器去测一个“本来有问题”的波形仪器本身可能让波形变得更糟。不过实际排查中我不建议一上来就纠结探头电容因为大多数 I2C 故障的根因不是探头造成的而是板子本身。只有当你测到的上升沿时间非常接近规格上限时才需要怀疑探头电容的影响可以考虑换低电容探头或者用有源探头复核。另外一个细节测上升时间时多数示波器默认按 10% 到 90% 定义但某些 I2C 规格书里用的是 30% 到 70%对比参数时记得换算别直接拿数据比大小。3. ACK 到底长什么样从“第 9 个时钟”看从机的应答ACK 是整个 I2C 排查里最关键也最容易看漏的一环。地址发出去之后从机有没有响应、能不能继续通信就靠这一位来判断。你不需要完整读出所有数据字节抓到地址字节和后面的 ACK 位基本就能判断问题出在“从机不应答”还是“数据阶段出错”。3.1 从波形上认 ACK 与 NACK一个字节加第九个时钟I2C 协议里主机每发送一个字节8 个数据位从机要在第 9 个时钟周期内给出应答。具体表现是主机在第 8 个数据位结束后释放 SDA此时 SDA 会变高紧接着第 9 个 SCL 脉冲的高电平期间从机把 SDA 拉低并保持到时钟结束这就是 ACK。如果 SDA 在整个第 9 个时钟期间一直保持高电平那就是 NACK表示从机没有响应。识别 ACK 最靠谱的方法不是看波形长得像不像而是数时钟。从 START 之后开始数第一个字节的 8 个脉冲是地址和读写位第 9 个脉冲就是 ACK 位。常见误判是把某个数据位当成 ACK尤其当数据位本身就连续几个“1”时波形上看起来会有一段平台如果不数时钟很容易看错。我的习惯是把时基放大到每格几微秒用光标把第 9 个上升沿位置标出来然后直接读此时 SDA 的电平高就是 NACK低就是 ACK一目了然。3.2 逻辑分析仪里的“手动 ACK”设置是什么意思示波器看 ACK 靠肉眼逻辑分析仪则是靠解码算法自动判断。常见的逻辑分析仪软件比如 Saleae、DSView、PulseView在解码 I2C 时都会按标准协议解析 ACK 位。但某些场景下从机不响应解码器会在 ACK 处报错并且停止继续解析后面的字节这时候很多软件提供了一个选项翻译过来意思类似“手动 ACK”或者“忽略 ACK”。这个选项的本质是当软件检测到 NACK 时仍然强制把当前字节标记为完成然后继续解析后续字节。调试时这个功能很有用比如你想看某个从机在 NACK 之后是否还输出了数据、或者主机后续发了什么命令就可以开启这个选项让解码不中断。但我要提醒一句定位问题时别依赖这个功能它相当于容错处理会把错误吞掉。我更推荐在设置里开启严格的 ACK 检查让 NACK 直接标红报错这样哪个字节出了问题一眼就能看到。3.3 ACK 异常背后的四类常见根因从实际排查经验看ACK 异常基本可以归到四类。第一类是地址不匹配。I2C 从机地址有 7 位和 10 位两种模式很多芯片的地址引脚比如 A0、A1、A2决定低几位地址原理图上画得模棱两可贴片时焊错或者漏焊导致地址对不上。我记得有一次查一块 GT911 触摸屏的通信失败量波形时发现主机发的地址和芯片要求的地址差了整整一位GT911 的地址可以通过引脚配置成不同值初始化时序不对甚至会让芯片根本不进入有效的 I2C 模式表现出来就是第一个地址字节之后直接 NACK。第二类是从机供电、复位或使能问题。很多传感器上电后需要一段时间完成初始化如果主机在从机还没 ready 时就去读从机会直接 NACK。另外有些器件有复位引脚、使能引脚这些引脚电平不对从机就处于关闭状态自然不会应答。第三类是地址冲突。I2C 总线上挂了两个相同地址的从机时应答会非常混乱两个从机可能交替拉低 SDA表现时而 ACK 时而 NACK甚至总线数据错乱。排查这种问题要用逻辑分析仪长时间采样看每次应答对应的是哪个设备在驱动总线的电平。第四类是主机端配置错误。比如 MCU 的 I2C 外设时钟分频配错了导致实际 SCL 频率远超从机支持的范围从机跟不上就会 NACK。还有主机发送的寄存器地址、命令字不符合器件手册从机在数据阶段给出 NACK 作为“拒收”信号。这类问题别死磕硬件先回去把芯片手册里的寄存器读写流程再对一遍。4. 完整排查流程七步从现象直达根因前面几章其实是把工具和关键概念拆开讲了这一章我把它们串成一条可复现的流程。这套流程我自己在多个项目里用过从消费电子到工控板卡都适用核心思路是先排除物理层再观察协议层最后根据 ACK 定位根因。4.1 动手前的确认清单供电、电平域与器件地址正式测波形之前有几个信息必须先确认不然拿到波形也解读不出来。第一确认所有相关器件的供电。量 VDD 实际值很多 I2C 故障其实是电源纹波大或者电压偏低造成的从机会出现上电后偶发不响应。第二确认电平域。主控是 3.3V外部传感器是 1.8V 的话上拉电阻接在哪个电源域就很关键SDA 和 SCL 的高电平不能超过从机的 VDD 承受范围。第三查原理图确认每个从机的 I2C 地址和读写位很多芯片地址由引脚上下拉决定这个信息必须从具体板子上去核对不能只依赖芯片默认值。第四确认你用的时序模式是标准 100k、快速 400k 还是快速 1M这决定了后面时序参数的判定基准。4.2 七步排查链路的具体操作下面这七步是实际操作链路每一步都有明确判定条件和下一步去向万用表直流挡测 SDA/SCL 空闲电平。两个都接近 VDD 则通过任何一个为低先查哪个设备拉低了总线常见原因是从机死锁、上拉电阻没焊、或者 GPIO 配置错误。断电后测上拉电阻和引脚通断。阻值明显异常或者某一段不导通先修物理层修完回到第 1 步重新测。示波器抓一帧波形定位 START 和 STOP。确认波形确实是一帧完整的 I2C 事务排除抓错或者触发位置不对的问题。数地址字节的 8 个数据位核对地址和读写位是否正确然后看第 9 个时钟的 ACK/NACK。如果 ACK 正常继续核对数据字节的 ACK 和最后的 STOP 是否完整。数据阶段 NACK多半是寄存器地址或命令字不对。如果地址字节后直接 NACK按 3.3 节里的四类原因逐项排查地址配置、供电/复位、地址冲突、主机时钟频率。如果问题不是每次必现用逻辑分析仪长时间挂机采样记录多次事务的时间戳寻找偶发错误的规律。这套流程的关键是每一步都要有明确结论不要跳到下一步的时候还带着“这个可能没问题吧”的念头。4.3 一个 AT24C02 读失败的完整复盘拿最常见的 EEPROM 为例AT24C02 的 I2C 地址是 1010 加 A2/A1/A0 三个引脚电平再加读写位。写操作时控制字是 0xA0读操作时是 0xA1。有一次板子读 AT24C02 总是失败我按上面流程走万用表量空闲电平正常上拉电阻正常示波器抓波形发现主机完整发出来了 0xA010100000地址位没问题第 9 个时钟 SDA 却是高NACK。按 NACK 的排查顺序先检查供电正常再检查地址引脚结果发现 A2/A1/A0 三个引脚全部悬空既没接高也没接低手册里要求必须明确接入固定电平。补焊之后再抓波形第 9 个时钟 SDA 稳稳拉低ACK 出来了读写恢复正常。这类问题就是典型的静态电平和上拉都正常、但 ACK 才暴露出来的例子你不看 ACK 只看万用表永远找不到根因。5. 时序余量、上拉计算与总线负载藏在波形背后的底层细节很多时候I2C 波形“看起来”没问题但通信就是不稳定的偶发失败。这时候问题往往出在时序余量和总线负载上。这一章讲的是那些不直接体现在 ACK 上、却能让整个通信系统处在崩溃边缘的底层细节。5.1 100k 模式下的时序基准建立时间和保持时间怎么量I2C 规范定义了不同速率模式下的时序参数我整理了最常用的三档方便排查时对照参数标准模式 100k快速模式 400k快速 1MSCL 低电平时间 tLOW最小 4.7us最小 1.3us最小 0.5usSCL 高电平时间 tHIGH最小 4.0us最小 0.6us最小 0.26us上升时间 tr10%-90%最大 1.0us最大 0.3us最大 0.12us下降时间 tf最大 0.3us最大 0.3us最大 0.12us数据建立时间 tSU;DAT最小 250ns最小 100ns最小 50ns数据保持时间 tHD;DAT最小 0ns最小 0ns最小 0ns测量建立时间和保持时间时要把示波器两个通道分别接 SDA 和 SCL。数据建立时间指的是 SDA 变化到 SCL 上升沿之间的时间数据保持时间是 SCL 下降沿之后 SDA 保持的时间。很多时候从机采样出错、偶发读到错误数据就是因为主机在 SCL 上升沿附近才改变 SDA建立时间不够从机捕捉到了不稳定的数据位。示波器光标一量就能量化别只靠肉眼判断“应该来得及”。另外注意MCU 外设配置的 SCL 频率和实际抓到的 SCL 频率经常不一致。有些芯片分频配置写的是 100k但实际因为系统时钟的整除关系抓出来是 120k 甚至更高。这类超规格运行在多数情况下能工作但一旦总线电容变大或者从机响应变慢就会变成头疼的偶发 NACK所以波形抓出来之后建议顺手用示波器频率计测量一下实际 SCL 频率。5.2 上拉电阻的选择从最小值到最大值的计算路径上拉电阻不是随便选一个就行它的上下限都有约束搞清楚计算逻辑排查时会更有针对性。最小值约束来自 I2C 规范中 VOL 的要求也就是从机或主机在拉低 SDA 时引脚上的电压必须低于 0.4V在 3mA 灌电流条件下。如果上拉电阻太小拉低时的电流过大引脚电压可能抬升超过 0.4V逻辑低电平就不可靠了。计算公式是Rmin (VDD - 0.4V) / 3mA。以 3.3V 系统为例Rmin 大约是 (3.3 - 0.4) / 0.003 967Ω取整后用 1k 或 1.2k 都行。最大值约束来自上升时间要求。总线上的等效电容 Cbus 和上拉电阻 R 构成 RC 充电回路上升时间大约等于 0.8473 乘以 R 乘以 Cbus。以标准模式 tr 最大 1us 为例Rmax 1us / (0.8473 × Cbus)。如果总线上有三个从机加上走线寄生电容Cbus 按 200pF 估算Rmax 1us / (0.8473 × 200pF) ≈ 5.9k。所以 4.7k 上拉在这个条件下没问题但如果总线电容到了 400pF4.7k 的上升时间就可能超规格了。这也是为什么长走线、多从机系统里很多工程师会主动把上拉从 4.7k 降到 2.2k。5.3 总线电容、多从机与扩展器哪些事会让波形悄悄恶化I2C 总线上每多挂一个从机就会多几百皮法的引脚电容走线过长、过孔过多也会增加寄生电容。电容变大、上升沿变慢的后果是SCL 高电平时间可能被蚕食SDA 的数据建立时间被压缩从机在边沿处采样就容易出错。多个从机还有一个隐患是地址冲突。I2C 没有片选引脚所有从机靠地址区分两个设备用了相同地址总线必然出问题。排查手段是逐个从机扫描地址确认每个地址只有一台设备应答。另外设计上用 I2C 多路复用器或扩展器比如 TCA9548能解决地址冲突但也带来了新变量。扩展器本身也是一个 I2C 从机它在子通道上的信号质量取决于子总线的电容和上拉配置。我踩过一个坑切换通道后立即发数据结果子总线上第一个字节直接 NACK后来发现是通道切换后总线稳定需要一点时间加了几毫秒延时就好了。调试这类扩展芯片时先抓主总线的 ACK确认扩展器本身响应正常再抓子总线的波形分步骤定位别混在一起猜。5.4 别把 PMBus 和 HID over I2C 当普通 I2C 排最后提两个和 I2C 容易混淆的场景遇到它们时要先认清协议边界不然会浪费大量时间。PMBus 电气上基于 I2C但有自己的一套命令集和时序规则。它要求发送方在每帧数据里带上 PEC 校验字节支持 ALERT 引脚事件而且 SCL 最低频率限制在 1kHz 以下有些规范要求不能低于 1kHz。如果你拿裸 I2C 的方式去排查 PMBus看到 PEC 字节可能会当成未知数据位把 ALERT 当成普通 GPIO。正确做法是先把 PMBus 的命令帧格式搞清楚或者用支持 PMBus 解码的逻辑分析仪协议解析插件。另一个是 HID over I2C也就是 Windows 系统里触摸屏、键盘等设备通过 I2C 传输 HID 报文。如果设备管理器里报“I2C HID 设备找不到足够资源可以使用代码 12”多数情况下不是总线波形问题而是 I2C 控制器驱动、ACPI 资源分配、电源管理策略出了问题。这种问题你拿示波器测 I2C 波形大概率看不出异常应该先查系统的设备资源和驱动状态别把波形排查用在错误的层级。顺带澄清一个概念I2C 是主机驱动的总线从机不能主动往总线上发数据所以别指望从机“主动更新主机寄存器”。如果看到某些资料里提到从机主动通知那通常是在 SMBus/PMBus 场景下通过 ALERT 引脚实现的事件机制并不是 I2C 标准协议允许的从机主动传输。这个边界理清楚很多“为什么从机不发数据”的疑问自然就解开了。最后分享一个我自己的习惯抓 I2C 波形一定要先把帧头帧尾找出来再谈其他。很多人看到一串看似规则的脉冲就开始猜协议结果把 STOP 当数据位、把 ACK 当地址位越猜越乱。先把 START 和 STOP 在波形上标出来再数每个字节的 9 个时钟ACK/NACK 一目了然很多“诡异”问题其实只是没数清楚时钟而已。希望这套流程能帮你少走一圈弯路。
返回列表