ARTICLE DETAIL

资讯详情

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

I2C 总线排查全链路:万用表、示波器与 ACK 时序定位

I2C 总线排查全链路:万用表、示波器与 ACK 时序定位 很多人遇到 I2C 通信异常第一反应是抓逻辑分析仪或者打开示波器猛戳结果波形乱跳、触发设不对反而越查越懵。我见过不少同行拿着万用表量了半天 SCL、SDA 电压看着 3.3V 觉得好像没问题结果问题其实藏在 ACK 时序里。I2C 信号看起来简单就两根线但真要系统性地测明白需要把万用表能做什么、示波器怎么触发、ACK 意味着什么串成一条完整的排查链路。这篇就基于我实际调试的经验把从静态测量到动态时序、从电平到 ACK 的完整过程拆开讲清楚无论你是刚接触 I2C 的新手还是被总线锁死折磨过几次的工程师都应该能从这里找到一套可复用的排查思路。1. 先把话说清楚I2C 上到底有哪些可测的信号在做任何测量之前建议先花两分钟想清楚一个问题I2C 总线上我们关心的物理量到底有哪些只有把测量对象先定义清楚后面选工具、看波形才不会抓瞎。1.1 总线上真正需要关心的物理量I2C 是两根线的协议SCL时钟和 SDA数据都是开漏结构加上拉电阻。开漏意味着设备只能主动把线拉低不能主动推高高电平全靠上拉电阻提供。这个特性决定了你在总线上能观测到的信号形态。从物理层面拆你需要关心的东西无非这几类静态电平总线空闲时 SCL、SDA 是否被上拉到正常的逻辑高电平。对 3.3V 系统来说正常应该在 3.3V 附近5V 系统同理。如果量出来只有 1V 甚至 0.5V说明有设备在偷偷拉低总线或者上拉电阻根本没接。动态波形通信过程中 SCL 的时钟翻转、SDA 的数据变化是否符合协议时序。这需要示波器或逻辑分析仪才能看到。时序参数起始条件、停止条件、建立时间、保持时间、时钟频率。数据是否在 SCL 高电平期间保持稳定是否在低电平期间变化这些决定了通信是否正确。ACK 响应从机在收到地址或数据后是否在第 9 个时钟周期把 SDA 拉低。这一点是排查设备为什么不响应的分水岭。很多人在排查时会陷入一个误区上来就怼着波形看时序参数把数据手册里的建立保持时间逐项核对结果查了半天发现只是地址写错了。我个人的习惯是先确认静态电平再抓动态帧格式最后才扣时序细节这样排查效率最高。1.2 工具能力对照什么场景用什么家伙不同工具能回答的问题是完全不同层级的。我遇到过有人拿万用表去测 ACK这从原理上就说不通因为 ACK 是一个动态的、发生在特定时钟边沿的行为万用表只能告诉你电压的平均值或瞬时值根本看不到第 9 个时钟发生了什么。这里我整理了一个简单的工具对照表方便你快速判断当前该拿什么工具排查目标适用工具为什么总线空闲电平是否正常万用表静态电压一次读数就能判断有无设备拉死总线万用表通断档/电压档总线一直为低时能快速定位拉低来源上拉电阻是否生效万用表电阻档断电状态下直接量阻值波形是否存在、频率是否正常示波器/逻辑分析仪需要看动态翻转时序细节是否合规示波器带宽足够时需要精确的时间测量ACK/NACK 判断示波器/逻辑分析仪要看第 9 个时钟周期的 SDA 状态多字节帧的协议解析逻辑分析仪带协议解码直接看地址、寄存器、数据内容效率高工具没有绝对的优劣关键是匹配当前要回答的问题。静态问题用万用表时序问题用示波器协议内容用逻辑分析仪这基本是一个固定的思路。接下来我会按从静态到动态的顺序逐个展开。2. 万用表能测什么、不能测什么以及怎么用才不算白测万用表是排查 I2C 的第一个工具也是很多人用得最糙的工具。很多情况下你并不需要把示波器搬出来万用表就能解决一大半问题前提是你知道该测什么、怎么判读。2.1 静态信号电平、短路、上拉强弱I2C 出问题很多是静态层面的硬故障比如虚焊、短路、上拉电阻错位、地址线冲突。这些问题在示波器上反而不好抓因为波形可能根本不出现而万用表一量就清楚了。第一件事断电状态下用**通断档蜂鸣档**分别量 SCL 和 SDA 对地以及两根线之间的阻抗。正常情况应该都是开路如果蜂鸣器响了说明某根线对地短路或者两根线焊在一起了。这个检查 30 秒完成能排除掉至少三成的基础故障。第二件事上电后量 SCL 和 SDA 的空闲电压。I2C 空闲时两根线都应该是高电平。注意这里有一个容易忽略的细节如果是 3.3V 系统但某个从机芯片是 5V 容忍引脚量出来的电平可能正常可如果上拉电阻接到了错误的电源轨比如该接 3.3V 的接成了 1.8V空闲电压就会偏低。用万用表直流电压档量一下正常应该在 VDD 的 90% 以上明显偏低就说明上拉路径有问题。第三件事用电阻档量上拉电阻本身。很多 I2C 模块会板载上拉电阻但有些开发板的上拉电阻是可配置的通过跳线或焊盘漏焊或者跳线没贴就会导致总线浮空。断电状态下直接量上拉电阻两端确认阻值在 1k 到 10k 之间并确认确实接到 VDD 上。还有一个被很多人忽视的检查总线上是否有设备把 SDA 拉低。如果上电后发现 SDA 电平一直为 0而 SCL 是高通常有两种可能——某个从机处于异常状态占用了 SDA或者主机的 I/O 配置错误把 SDA 引脚设成了推挽输出且输出低电平。这时候可以试着把可疑设备的供电断开看 SDA 是否会恢复高电平。用万用表配合断开法往往比示波器逐点排查更快。2.2 万用表永远答不了的那一类问题说句实在话万用表在 I2C 排查里能做的也就是上述这些静态检查。它回答不了波形长什么样数据对不对从机有没有回 ACK这些问题。 提示很多工程师习惯拿万用表量到 SCL 和 SDA 有电压跳变就觉得总线在工作这是一个典型误判。万用表的电压档是平均值响应的就算总线在高速翻转你量到的也只是某个有效值或平均值根本看不出时序是否正确。要判断通信是否真正建立必须看到完整的帧结构——起始条件后跟的地址字节、寄存器地址字节、数据字节以及第 9 个时钟的 ACK 位。这些信息万用表的刷新率和采样方式决定了它根本无法捕捉。所以当你确认静态电平正常、上拉电阻也 OK、但通信还是不通时就该把示波器拿出来了继续纠结万用表没有任何意义。3. 示波器上怎么抓 I2C触发、探头和读数习惯示波器是 I2C 排查的核心工具。很多人觉得示波器难用其实最大的障碍不是不会读波形而是不会设触发——波形在屏幕上乱闪你根本看不清楚。只要把触发设对I2C 的帧结构可以非常直观地呈现在屏幕上。3.1 触发和通道设置让波形停下来而不是一闪而过抓 I2C 波形推荐用两通道示波器CH1 接 SCLCH2 接 SDA。探头的地线夹子要夹在离总线最近的地上越近越好否则引入的噪声会影响边沿判断。触发设置是关键。I2C 的起始条件START是 SCL 高电平期间 SDA 产生一个下降沿所以最常用的触发方式是在 SDA 通道上设置下降沿触发。具体操作是把触发源选到 CH2SDA触发电平设为 VDD 的一半左右比如 3.3V 系统设为 1.6V触发方式选下降沿。这样每次主机发起通信时SDA 的起始沿就会把波形稳定在屏幕上。时基怎么选这取决于你的 I2C 速率。标准模式 100kHz一个时钟周期是 10us一帧完整的写操作起始 地址 ACK 寄存器 ACK 数据 ACK 停止大约 27 个时钟周期也就是 270us 左右。所以我一般先把时基设在 50us/div 左右看到完整帧之后再放大到 5us/div 去看细节。另一个很多人忽略的问题是探头带宽。普通无源探头带宽如果只有 50MHz去测 400kHz 的 I2C 其实够用但如果你去测 1MHz 以上的快速模式或者总线上有很尖锐的边沿探头带宽不够会把波形圆化影响你判断建立时间。我实测下来100kHz 标准模式完全不用担心带宽问题400kHz 快速模式也基本没问题但如果波形边沿异常比如上升沿缓先检查探头补偿是否调好再去怀疑芯片。3.2 读懂一帧起始位、地址、数据和 ACK/NACK示波器抓到波形以后怎么读它我建议按下面这个顺序来第一步识别起始条件和停止条件。SCL 为高电平期间SDA 从高跳变为低是起始SCL 为高电平期间SDA 从低跳变为高是停止。找到这两个标记你就知道一帧从哪里开始、到哪里结束。这也是在示波器上最容易辨认的两个特征因为它们发生的时候 SCL 都处于高电平和普通的数据位SCL 高时 SDA 必须保持稳定完全不同。第二步确认地址字节。起始条件之后第一个字节的前 7 位是从机地址第 8 位是读写方向0 表示写1 表示读。这个地址要在 SCL 上升沿时去采样 SDA。示波器上怎么数你可以把波形停住然后用光标沿 SCL 的上升沿逐位去读 SDA 的电平。过程有点繁琐但第一次排查时值得做一遍因为你可能发现主机发的地址和从机的 7 位地址对不上比如忘了左移一位。第三步也是最关键的——看第 9 个时钟周期的 ACK 位。在第 9 个 SCL 脉冲的高电平期间SDA 应该是低电平ACK如果 SDA 保持高电平NACK说明从机没有正确响应。这里有一个容易混淆的地方ACK 位期间 SDA 由从机驱动而数据位期间 SDA 由主机驱动。如果 SDA 在第 9 个时钟没有变低不要急着下结论从机坏了先确认地址是否正确、从机供电是否正常然后再做判断。我给新手一个建议不要试图用示波器去数完整的 27 个时钟来人工解码一帧效率太低也太容易数错。示波器的作用是让你看到波形形态正不正常、ACK 在不在如果要解出具体的数据内容交给逻辑分析仪更合适。示波器负责从模拟域确认信号质量逻辑分析仪负责从数字域解码协议内容两者各司其职。3.3 从波形上推断谁在拉低总线示波器除了看时序还有一个非常实用的功能判断总线是谁拉低的。I2C 是开漏结构主机和从机都能拉低 SDA/SCL一旦总线卡在低电平你需要知道是谁在拖着不放。操作手法是把示波器时基拉大比如设成 1ms/div 甚至 10ms/div观察 SCL 或 SDA 在停止条件之后是否一直保持低电平。如果总线空闲后 SCL 被拉低而 SDA 恢复高电平大概率是从机在时钟拉伸clock stretching或者从机异常。如果 SDA 被拉低则可能是从机处于忙状态也可能是主机 I/O 配置成输出低。更精细的做法是分路断电测试。把总线上各个设备的供电独立控制逐路断开同时用示波器观察总线是否恢复高电平。哪个设备断开后总线恢复哪个就是肇事者。这个方法看起来笨但定位问题的速度极快比我见过很多人用逻辑分析仪逐个设备查固件状态要高效得多。4. ACK 才是排查的分水岭从机制原理到五个典型失败模式如果说前面的电平检查、波形确认是排查的基础动作那 ACK 的判断就是整个排查的分水岭——ACK 正常说明物理层和地址层没问题问题大概率在数据内容或后续逻辑ACK 异常则说明设备根本没有正确参与通信需要回头查硬件和配置。4.1 ACK/NACK 到底是怎么产生的先把这个机制讲透。I2C 的数据传输是按字节进行的每发完一个字节8 个时钟主机要额外产生第 9 个时钟脉冲。在这个第 9 个时钟的高电平期间发送方释放 SDA 总线接收方如果存在且正常会把 SDA 拉低表示我收到了继续发——这就是 ACK。如果接收方没有拉低或者根本不存在SDA 就会被上拉电阻保持在高电平主机读到的就是 NACK。这里有一个很有意思的细节I2C 协议里主机作为接收方时也必须发出 ACK读操作中主机读完最后一个字节后要发出 NACK 来表示够了停止。很多人只记得从机要回 ACK忘了主机在接收数据时也要配合导致排查读操作时序时一头雾水。ACK 的判断逻辑很简单但背后的推导非常有价值如果第 9 个时钟 SDA 为低说明从机收到了地址且地址匹配成功如果为高则可能是从机地址不匹配、从机未上电、从机忙、或者总线上根本没有这个设备。 注意有一种特殊情况需要警惕——如果 SDA 在第 9 个时钟期间呈现半低半高或者波形畸形往往意味着总线驱动能力不足上拉电阻太大或总线电容过大或者有多个设备在同时驱动。这不是标准的 NACK而是物理层问题需要回到信号质量去排查。4.2 五种典型的 ACK 异常波形与根因指向我在实际排查中总结过几种最高频的 ACK 异常形态每种都对应不同的根因方向。你可以对号入座波形特征根因方向验证手段从机地址后直接 NACK且 SDA 在第 9 时钟一直为高从机地址不匹配比如 7 位地址左移右移搞混核对数据手册地址检查代码中地址定义从机地址后直接 NACK且 SCL 上没有第 9 个时钟主机 I2C 外设配置异常没有正确产生 9 个时钟检查主机 I2C 控制器的寄存器配置地址 ACK 正常但寄存器地址后 NACK从机不支持该寄存器地址或处于错误模式查阅从机数据手册的寄存器映射写数据过程中数据字节后 NACK从机接收缓存已满、正在写 Flash/EEPROMM、或状态机异常确认从机忙碌状态位调整写入间隔总线空闲期 SDA 被持续拉低通信无法发起从机在上电初始化失败或 I/O 电平冲突断开从机电源观察 SDA 是否恢复高电平这五种情况里最容易让新手抓狂的是第二种——主机配置出了问题。比如用单片机的硬件 I2C 外设很多人只开了 I2C 使能就以为万事大吉结果外设时钟没开或引脚复用配错SCL 上根本没有脉冲序列。这时候你用示波器看会发现地址字节发了但后面该有的时钟突然中断了从机当然没法回 ACK。遇到这种先查主机 I2C 外设的时钟树和 GPIO 配置别一上来就怀疑从机。另一个值得单独提醒的场景是EEPROM 写操作。很多 EEPROM 在收到一页数据后需要内部写周期Page Write / Internal Write Cycle这段时间内设备不响应任何 I2C 请求。如果你连续写两页数据第二页的地址字节就会收到 NACK——这不是故障而是设备忙。示波器上看到的现象是前一帧完整 ACK 全通过紧接着下一帧地址就 NACK而且这个现象每次都在写操作后固定出现。遇到这种加一个写周期延时即可解决。4.3 用 ACK 来缩小问题范围一个判断树为了让你在排查时更有条理我把 ACK 相关的判断逻辑画成了一个很粗的判断树不用做图工具直接按文字理解如果地址字节后 AKC继续写寄存器地址若 NACK → 查寄存器映射是否支持该地址继续写数据若 NACK → 查从机是否忙、是否写保护、是否数据长度超限全部 ACK → 通信链路正常问题可能在数据内容本身比如写进去的值不对如果地址字节后 NACK查从机地址是否匹配注意 7 位/8 位地址的换算查从机供电、复位引脚、使能引脚状态用万用表确认 SDA 是否被其他设备拉低查主机 I2C 控制器是否正常产生完整时钟序列这个判断树是我用得最多的工具因为它把问题在网络层还是应用层这个抽象问题变成了几组具体操作。你只要沿着节点往下走通常能在十分钟内把问题范围缩小到某个具体方向。5. 一次完整的 I2C 排查该按什么顺序走OK前面讲了很多细节现在我把一条完整的排查流程串起来。这也是我被问得最多的问题——到底先查什么、后查什么。我提供一个自己反复验证过的执行顺序。5.1 五个步骤的分层排查节奏第 1 步静态检查2 分钟断电用万用表通断档确认 SCL、SDA 对地无短路、两线之间短路。上电量 SCL、SDA 空闲电压确认在 VDD 的 90% 以上。同时确认总线上所有设备供电正常包括核电压、IO 电压和使能引脚。第 2 步确认波形存在3 分钟示波器设好下降沿触发抓 SDA 上的起始条件。如果完全抓不到任何波形问题大概率在主机端——代码有没有跑起来I2C 外设时钟开了没有GPIO 复用配好了没有如果波形有但只是乱糟糟的一团先检查探头和接地排除测量手段问题。第 3 步确认帧结构和 ACK5 分钟抓一帧完整的写操作先看起始和停止再数一下地址字节最后看第 9 个时钟的 SDA 状态。这一步决定了所有后续方向——地址 ACK 和不 ACK 是两条完全不同的排查路径千万别混着查。第 4 步针对性深挖视情况而定ACK 异常就按上面的五个典型模式去查重点核对地址和从机状态ACK 正常就去查数据内容对不对用逻辑分析仪解码确认寄存器地址和数据值是否和预期一致。第 5 步重复验证也是关键修复之后不要只看一次波形就收工。把示波器时基拉大观察一段时间的连续通信确认总线空闲状态正常、没有偶发的 NACK 或总线卡死。有时候问题隐藏在某些特定数据值下要多跑几次通信才能暴露。5.2 一个真实案例复盘音频 DAC 无声根因却在一颗 NACK分享一个我印象很深的具体案例这会比抽象理论更容易理解。当时一个项目用的是某款音频 DACI2C 控制接口接在主控的硬件 I2C1 上。现象是DAC 初始化代码返回值一直是 0看起来没报错但音频输出全是噪声。理论上初始化时往 DAC 寄存器写配置成功后应该能输出正常音频但事实上完全无声。我第一次排查时上来就用逻辑分析仪解 I2C 数据发现主控往 0x20 地址写了一大堆寄存器配置看起来一切正常。但问题恰恰藏在这里逻辑分析仪是解数字域的它能告诉你的只是线上发送了什么它判断的 ACK 有一个隐含前提——低于某阈值的低电平就认为是有效 ACK。如果 SDA 只是被微弱拉低比如从机驱动能力不足、或者总线电容太大逻辑分析仪可能也判成 ACK但这个 ACK 在物理上根本不可靠。我后来又用示波器去量 DAC 的 SDA 引脚发现一个非常隐蔽的问题DAC 的 I2C 引脚在收到配置后确实在拉低但拉低的幅度只有 0.8V 左右而主线 SDA 的空闲电平是 3.3V——这意味着从机和主机之间存在着明显的地电位差或者总线上某个设备在分压。后来查出来是 DAC 芯片的地和主控地之间走了一条细长的排线阻抗稍大导致从机的地相对主机的地抬高了将近 0.7V。DAC 以为自己在正常回 ACK主控这边采样的 SDA 电平却达不到逻辑低的标准只是看起来像 ACK实际通信数据完全不可靠。这个案例给我的启发是如果发现通信偶发失败或者逻辑分析仪解码正常但设备行为不对一定要回到示波器上看物理波形——ACK 的拉低幅度够不够、边沿是不是干净、地平面是否一致。协议解码工具会掩盖物理层问题这是 I2C 排查中最隐蔽的陷阱。6. 实操补充逻辑分析仪、示波器测量技巧和几个容易翻车的判断排查 I2C除了万用表和示波器逻辑分析仪也是高频使用的工具。我最后把几个实操中的补充点一起说了包括工具选型、接线技巧和一些常见的误判。6.1 逻辑分析仪的正确打开方式逻辑分析仪最大的优势是能协议解码——直接把总线上的原始波形翻译成地址 0x20 寄存器 0x03 数据 0x7A ACK这样可读的内容。这也意味着它的使用门槛比示波器低很多很多新手入门 I2C 排查都会先抓逻辑分析仪。但我越来越倾向于把逻辑分析仪的定位从排查工具调整为验证工具。排查阶段你需要的是看到物理层的问题电平不够、边沿过缓、时钟毛刺这些恰恰是逻辑分析仪不擅长甚至看不见的。验证阶段你需要确认协议交互内容是否正确逻辑分析仪就非常高效了。提示使用逻辑分析仪时采样率至少要设为 I2C 时钟频率的 10 倍以上。100kHz 总线建议采样率不低于 1MHz否则容易漏采窄脉冲解码会出现随机错误。我曾见过有人用 500kHz 采样率去解 400kHz 的 I2C解码结果几乎每次都不一样还以为是总线时序问题。6.2 示波器测量时几个会翻车的细节探头地线一定要短。无源探头默认的地线夹是一根长夹子线如果你跨越较长的距离把地夹在板子远处夹子线和探头针尖之间形成的环路会引入很大的噪声和振铃在波形上表现为边沿抖动。排查 I2C 时尽量用探头配的短地弹簧或者直接把探头针尖点在地孔上地线夹夹在最近的测试点。带宽 vs 采样率的区别。很多人买示波器只看采样率其实对 I2C 这种信号来说带宽决定了你能不能看到真实的边沿采样率只决定你看到的点数够不够密。50MHz 带宽的探头去测 100kHz 的 I2C 完全没问题但如果你要精确测量上升时间就必须考虑探头带宽对边沿的影响。实测下来I2C 标准模式的上升沿一般几十纳秒用 100MHz 带宽的示波器能看到大致形态但精确读数会有误差。别被单次触发骗了。I2C 总线上的数据是持续变化的如果你用单次触发Single去抓某一帧抓到的可能是一个随机的写操作或读操作并不一定能反映你关心的问题。我习惯先用 Auto 触发看总线概貌再用 Normal 触发搭配下降沿来抓取特定起始条件最后配合 Holdoff 时间去捕获稳定帧。6.3 三个常见的误判及如何避开误判一地址总对不上。I2C 地址有 7 位和 8 位的说法很多传感器的 7 位地址是 0x48但在总线上传输时左移一位变成 0x90写或 0x91读。如果你在逻辑分析仪上看到地址是 0x90但代码里写的是 0x48就以为对不上其实是同一条地址的两种表示。规避方法心里要清楚代码里写地址时有的库会用原始 7 位地址有的会要求你直接给 8 位带读写位的值。用示波器数波形或者用逻辑分析仪解码都要先确定它显示的是哪种形式。误判二看到 NACK 就觉得从机坏了。前面提到的 EEPROM 写周期就是一个典型。NACK 只是I2C 协议的反馈不代表硬件故障。排查时先问一句这个 NACK 出现的时机是否有规律是否每次都在特定操作后出现如果每次都出现在写 EEPROM 之后极大概率是设备忙如果随机分散再怀疑硬件问题。误判三把毛刺当成时钟。当 SCL 上的信号质量很差比如总线电容大、上拉电阻过大波形会出现振铃或毛刺逻辑分析仪或者示波器可能把某些毛刺误识别为额外的时钟边沿导致数据偏移。这种时候你会看到地址对但数据错、或者帧长度异常。处理方式优先改善信号质量减小上拉电阻、降低速率而不是钻进协议细节里反复猜。我在实际项目里的习惯是只要 I2C 出现数据错误第一反应永远是先看波形再谈协议。波形干净再往协议层面推波形不干净先解决物理层。这个顺序几乎能避开所有玄学问题。最后再分享一个我很受用的小技巧在写 I2C 驱动时尽量留一个寄存器回读的测试函数。通信完不要只看代码返回值实际通过 I2C 把寄存器内容读回来对比一下。很多 I2C 问题尤其是 ACK 异常通过回读能第一时间暴露而不是等到设备行为异常了才去排查。上回我调试一个传感器写配置时 ACK 正常但写进去的值怎么读都是错的后来示波器一量发现是 SCL 上的毛刺导致数据位被误采样——这种问题不用示波器只看逻辑分析仪压根解不出来。搞 I2C工具不在多关键是每个工具该回答什么问题、在什么环节出场心里要有数。
返回列表