搞嵌入式这么多年,我见过太多人在 I2C 问题上栽跟头了。明明代码写得没毛病,上拉电阻也焊了,可传感器就是不出数;有时候能读出来,但十次里面有一两次读到全 0xFF。于是有人开始怀疑芯片坏了,有人怀疑时序库写错了,还有人把从机地址翻来覆去改了好几遍。其实这时候最该做的,是把示波器探头夹上去,看看 SCL 和 SDA 上到底发生了什么。
I2C 是两根线的协议,SCL 走时钟,SDA 走数据,从物理上就决定了它比 UART、SPI 都好测——但也好骗人。两根线既要传地址、传数据、还要传 ACK/NACK,任何一个环节出了问题,表现都是同一个:通信失败。这篇文章我从万用表、示波器到 ACK 位逐一拆开讲,把一套完整的排查流程留下来,适合刚接触 I2C 的硬件工程师、单片机开发者,也适合被"玄学故障"折磨了很久的调试老手。
1. I2C 信号测量的底层逻辑:两根线上到底有什么
1.1 开漏结构决定了一切
I2C 的总线结构和 UART 不一样。UART 是推挽输出,Tx 要么主动拉高、要么主动拉低,电平是"被驱动"出来的;I2C 不一样,SCL 和 SDA 都接在开漏(open-drain)驱动器的漏极上,芯片只能把线拉低,要恢复高电平只能靠外部上拉电阻把总线拉回 VCC。
这听起来像是一个硬件细节,但它决定了排查 I2C 信号时候的很多"怪现象":
- 总线上所有器件都是"线与"关系,任何一个器件把 SDA 拉低,整条总线就是低电平,其他器件再怎么想表达"1"也没用。这就是为什么 I2C 能在一个物理总线上挂多个从机,而仲裁机制靠的就是这个特性。
- 信号的上升沿不是芯片推出来的,是上拉电阻和总线寄生电容的 RC 充电过程决定的。RC 常数越大,上升沿越缓,波形越"圆"。一旦示波器上看上升沿像一个小山坡而不是陡峭的边沿,问题大多出在这个 RC 环节。
- 静态的时候(总线空闲),SCL 和 SDA 应该都是高电平。如果量出来是低电平,说明有器件在"霸占"总线,或者上拉电阻没装、开路。
我记得刚带新人做第一块板子的时候,对方拿着新焊好的 PCB 问:"为什么 SDA 量出来只有 1.2V 而不是 3.3V?" 这就是典型的没理解开漏结构——他量的时候以为总线空闲时 SDA 会被"推"到高电平,实际上总线空闲时 SDA 是靠上拉电阻慢慢充电上来的。如果上拉电阻阻值太大、总线电容又大,静态电平可能还在爬升过程中就被下一次通信打断了。这种问题在万用表上看不出来,但示波器上一眼就能看到。
1.2 测量工具的定位:万用表看静态,示波器看动态,逻辑分析仪看协议
一个常见误区是:上来就用示波器,发现抓不到波形就判定"总线没信号"。其实测量 I2C 是有分工的,工具选对了效率高很多:
- 万用表:负责静态测量。通断、短路、上拉电阻、静态电压(空闲电平),这些都靠它。万用表测不了动态时序,但它是排查的第一步,能把"焊接问题、上电问题、短路问题"快速排除掉。
- 示波器:负责动态波形。SCL/SDA 的时序关系、ACK 位、毛刺、上升沿、钳位情况,这些必须靠示波器。示波器的核心价值在于"看波形形状和时序关系",不光是看有没有脉冲。
- 逻辑分析仪:负责协议层解码。它能自动解出起始位、地址、ACK、数据字节,把时序变成可读的帧。适合在波形看起来"好像都对"但通信还是失败的时候,快速确认协议层是否正确。逻辑分析仪解不了模拟信号问题(比如电平不够、边沿太缓)——这正是它替代不了示波器的原因。
我的建议是:先万用表排除硬件基础问题,再示波器看信号质量,最后用逻辑分析仪(或示波器的 I2C 解码功能)确认协议内容。这三步不是可选的,而是由 I2C 本身的特点决定的——它是开漏协议,从电气层到协议层每一层都有坑。下面我按这个顺序把每一步的实操细节展开。
2. 万用表开路:静态电平、短路和上拉电阻的排查
2.1 上电之前:量的是焊接和布线
很多人拿到新板子第一件事就是上电,然后发现 I2C 通信失败,再拿示波器去抓,抓了半天抓不到,最后才发现是某个焊盘虚焊。我后来养成一个习惯:上电之前先用万用表二极管档或蜂鸣档做一轮"裸检"。
第一项,测 SCL 和 SDA 对地、对电源的短路。直接把表笔分别搭在 SCL 与 GND、SDA 与 GND 之间,蜂鸣档响就说明短路;再测 SCL 与 VCC、SDA 与 VCC,同样确认没有直接短路。这里要提醒一下:如果板上已经有 I2C 器件焊好了,测得的结果是"存在上拉电阻的分压网络",不会完全短路也不会完全开路,表笔一搭会有一个充放电过程,数值稳定需要一两秒,别急着下结论。
第二项,测器件地址引脚(比如 A0/A1/A2)的焊接情况。很多 I2C 从机有地址配置引脚,它们决定从机地址的低几位。如果这些引脚虚焊,器件内部可能默认一个地址,而你的代码用的却是另一个地址,表现出来就是"发送地址后一直 NACK"。万用表能测这些引脚到 VCC/GND 的通断,确保地址引脚确实被拉到了你想让它到的电平。
第三项,测上拉电阻是否真的焊上了。我遇到过一批板子,上拉电阻位是 0603 的,过回流焊时立碑(tombstone),一端没焊上,结果 SDA 的上拉完全消失。静态上电后 SDA 可能会被拉到低,但万用表不通电测不出来,所以上电前最好用蜂鸣档顺着电阻两端走一遍。
2.2 上电之后:静态电平必须接近 VCC
上电后、通信之前,先把万用表拨到直流电压档,测 SCL 和 SDA 对地的静态电压。
正常情况下,两条线在总线空闲时都应该被上拉到接近 VCC(比如 VCC 是 3.3V,测量值应该在 3.2V 以上)。如果测量值明显偏低,比如只有 1V 或者 2V,那就说明有问题。这里要区分几种情况:
- 电压为零:上拉电阻没焊、或电阻开路、或总线上某个器件把线拉死了。最常见的是某个从机的 SDA 或 SCL 引脚内部故障,或者焊接时把相邻引脚搭锡短路到地。
- 电压在 1V~2V 之间"不上不下":这是最让人迷惑的。原因通常是总线空闲时某个器件确实在持续驱动低电平,但是它的驱动能力弱、上拉又强,两边处于"拔河"状态,中间电平就悬在半空。另一个常见原因是 SDA/SCL 被接到了其他有分压的网络上。
- 电压正常但通信时低电平"压不下去":这个万用表测不出来,得用示波器看,后面再说。
有一点要注意:万用表测静态电压时,如果系统里有多个器件,有些器件在空闲时会释放总线,但有些器件(比如某些 EEPROM 或传感器)在未初始化时会有一个默认的低电平输出状态。所以遇到静态电平不对,不妨把可能挂载的器件逐个断开(如果是排针连接的话),二分法定位是谁在拉低总线。
2.3 上拉电阻的计算和实测
I2C 上拉电阻的取值不是一个随便焊个 10k 就完事的参数,它对信号质量的影响非常大。
从原理上说,上拉电阻 R_p 和总线等效电容 C_bus 构成一个 RC 充电回路。I2C 规范对上升时间有要求:标准模式(100kHz)要求上升时间不超过 1000ns,快速模式(400kHz)要求不超过 300ns,快速模式+(1MHz)要求不超过 120ns。而上升时间 t_r 大约等于 0.8473 × R_p × C_bus(从 30% 到 70% VCC 的典型估算)。
所以上拉电阻的最大值受限于 C_bus 和频率要求:
R_p(max) = t_r / (0.8473 × C_bus)如果总线电容估算在 200pF(包含器件引脚电容约 10pF×几个、PCB 走线电容约 1~2pF/cm、探头电容),标准模式 100kHz 下:
R_p(max) = 1000ns / (0.8473 × 200pF) ≈ 5.9kΩ也就是说 10kΩ 在某些布局下其实已经"压线"了,如果总线走线很长、挂载器件很多,10kΩ 会导致上升沿超时,在 400kHz 下几乎必挂。
上拉电阻的最小值则受限于器件的灌电流能力。I2C 规范规定低电平 V_OL 要低于 0.4V(在 VCC=3.3V 时),而器件引脚能承受的最大灌电流(I_OL)通常在 3mA~20mA 之间。如果选太小的电阻,比如 330Ω,灌电流太大,低电平可能压不下去,从机就会读不到逻辑 0。最小值估算:
R_p(min) = (VCC - V_OL) / I_OL以 VCC=3.3V、V_OL=0.4V、I_OL=3mA 计算:
R_p(min) = (3.3 - 0.4) / 0.003 ≈ 966Ω所以常见的设计取 2.2kΩ~4.7kΩ 是有道理的。我个人在 3.3V 系统、单板内短走线、挂 2~3 个从机的情况下,默认选 4.7kΩ;如果系统要跑 400kHz 或者走线超过 10cm,用 2.2kΩ 比较稳。
万用表在这步能做什么?它可以测电阻值确认上拉电阻的实际阻值没有偏差过大,但没法测出总线电容和动态上升时间。所以上拉电阻选型最终还是要靠示波器看上升沿来验证——这就是下一步的重点。
3. 示波器抓 I2C:触发、探头和时序读图
3.1 探头接法:地线夹短接是命脉
示波器测 I2C 的第一个坑,是探头的地线夹太长。10cm 长的地线夹相当于一个很大的环路电感,会在高频下引入振铃,波形上看起来就是上升沿上叠加了一大堆毛刺。测 I2C 这种低速协议时很多人觉得无所谓,但 400kHz 快速模式下,这些毛刺会被误判成"总线噪声",白白浪费大量排查时间。
正确的做法是:
- 用地线弹簧(ground spring)或者把探头地线夹直接夹在离 SCL/SDA 测试点最近的 GND 上,缩短地回路。
- SCL 接 CH1,SDA 接 CH2,两路同时测。不要只测一路,因为 I2C 的时序关系是两根线之间的"相对关系",只看一路什么都判断不了。
- 探头用 10× 档位(标配探头默认拨到 10×),带宽足够测 I2C 的 100kHz/400kHz 信号。1× 档虽然信号幅度大,但探头输入电容也大(十几 pF),会加载到总线上,影响上升时间。
还有一个容易忽略的点:如果板子上有多个电源域,示波器探头的地和板子之间可能存在地电位差。虽然 I2C 板子通常共地,但测量前拿万用表确认一下探头地和板子地电压为 0 更稳妥,避免把示波器探头夹到有压差的参考点上。
3.2 触发设置:别再傻等波形了
抓 I2C 波形最让人头疼的问题是"怎么让它稳定触发"。如果直接用上升沿触发,SCL 上每个时钟都会触发一次,波形在屏幕上乱跳,什么也看不清楚。有两个思路:
思路一:用 SDA 下降沿触发抓起始条件。I2C 通信的开始条件(START)是 SCL 为高时 SDA 产生一个下降沿。把触发源设为 SDA,触发方式设为下降沿,就可以让示波器在每次通信起始时触发,然后设置合适的时间基准(比如每格 50~100μs,视总线速率而定),就能把一次完整传输的波形稳定显示出来。这是最简单、最推荐的做法,任何示波器都支持。
思路二:用触发释抑(Holdoff)或脉冲宽度触发过滤毛刺。如果 SDA 上有噪声、下降沿抖动频繁,可以适当加上触发释抑,让示波器在触发后的一段时间内不再触发。或者用示波器的"脉冲宽度触发"功能,设置"小于正常时钟周期的脉冲才触发",过滤掉窄毛刺。
思路三:示波器的 I2C 协议触发。中高端示波器(力科、泰克、是德的大部分主流型号,国产的鼎阳、普源也有这个功能)自带 I2C 协议触发和解码功能。设置好 SCL/SDA 通道、触发条件选"地址匹配",输入从机地址(比如 0x50),示波器就能在总线传输包含该地址的帧时精确触发,并且直接在波形上方解出"起始、地址、R/W、ACK、数据"的协议内容。这是排查 ACK 问题的最强工具。
我开始做 I2C 排查的头两年,傻乎乎地用边沿触发去抓波形,花了大量时间在屏幕上找帧结构。后来养成的习惯是:先用下降沿触发看整体传输是否发生,再用协议触发定位到具体帧,直接看 ACK 位。顺序反了就会事倍功半。
3.3 从波形上读时序:建立时间、保持时间、上升沿
波形稳定之后,要能从图上读出下面几个关键量:
SCL 频率。看 SCL 的周期 T,频率等于 1/T。如果实际测出来和代码里配置的频率差很远,说明时钟源或者分频设置有误。比如代码里配 400kHz,但波形上周期是 20μs(50kHz),那问题就出在 I2C 时钟配置本身。
建立时间 t_SU 和保持时间 t_HD。I2C 规范要求:标准模式下 SDA 在 SCL 低电平期间变化,且在 SCL 上升沿之前必须稳定一段建立时间(最小 250ns);SCL 下降沿之后 SDA 要保持一段保持时间(最小 0ns 即可)。如果示波器上看到 SDA 在 SCL 已经拉高之后才变化,说明从机的数据输出时序有问题,可能是芯片选型或代码模拟时序造成的。
上升沿时间 t_r。这是前面讲 RC 参数的实测验证。测法:从波形 10% 到 90% 电平的时间。如果上升沿明显超过规范值(100kHz 下大于 1000ns),说明上拉电阻偏大或者总线电容偏大,会导致从机对高电平的判定不稳定。如果上升沿陡得异常(小于 10ns),说明上拉电阻过小,可能造成振铃,灌电流也可能超限。
低电平电压值。正常情况 SCL 和 SDA 的低电平应该很接近 GND(低于 0.4V)。如果低电平"压不下去"、底部有 0.5V 或 1V 的残留,说明器件灌电流能力不够,或者总线有其他电压源在注入电流。这种问题在万用表上完全看不出来,是示波器才能发现的隐形故障。
我举一个真实案例。有一次客户反馈某 I2C 温湿度传感器偶发读取失败,我抓波形发现 SCL 是 400kHz、SDA 数据也都在,但 SDA 的上升沿明显很缓,导致在 SCL 采样点附近 SDA 还没有完全到达高电平,主机采样到"0"而不是"1"。查了一圈发现是板子上 I2C 总线上挂了三颗器件、走线又长,总线电容超过了设计预期,4.7kΩ 上拉不够用了。换上 2.2kΩ 之后,上升沿从约 900ns 降到约 400ns,问题彻底消失。这就是"波形看着有,但信号质量不达标"的典型情况。
4. ACK 的解剖:第 9 个时钟上的真相
4.1 ACK/NACK 的波形特征
ACK(Acknowledge)是 I2C 协议里最容易被忽略、但又最能说明问题的一个位。它在每 8 位数据(或地址)之后出现,由接收方在第 9 个 SCL 时钟周期内把 SDA 拉低,表示"我收到了"。
波形上的判断方法:
- 发送完 8 位之后,主机释放 SDA(让它被上拉为高),然后在第 9 个 SCL 时钟的高电平期间,看 SDA 是否被拉低。如果 SDA 在第 9 个时钟内是低电平,就是 ACK;如果 SDA 保持高电平,就是 NACK(No Acknowledge)。
- 注意观察第 9 个时钟期间 SDA 的低电平是否真的"到位"。有些场景 SDA 下降沿有,但只降到 1.5V,从机主控的输入阈值不足以识别为低,实际上主机端看到的就是 NACK,但从机以为自己在 ACK。这是最隐蔽的一种 ACK 故障,必须靠示波器看电平幅度才能确认。
为什么 ACK 是排查 I2C 的重中之重?因为 ACK 的返回情况直接告诉你了"通信链路中哪一环出了问题"。地址阶段的 ACK 说明从机存在且地址正确;数据阶段的 ACK 说明从机接收正常、且当前数据阶段合法。反过来,NACK 就像从机在说"我这边有问题",你要做的是顺着 NACK 出现在哪个字节去反推问题类型。
4.2 常见 NACK 场景:地址错误、从机没上电、总线被拉死
我把 NACK 的成因分成三类,每一类的判据不同:
第一类:从机地址 NACK——发地址就没有 ACK。这是最常见的情况。示波器上能看到主机发送了 8 位地址(7 位地址 + R/W 位),但第 9 个时钟 SDA 是高电平。原因可能包括:
- 从机实际地址和代码配置不一致(后面专门讲 7 位/8 位地址换算)。
- 从机没上电、或电源电压不对,芯片没有工作。
- 从机地址引脚(A0/A1/A2)的电平配置和代码预期不符。
- 总线上有两个从机用了同一个地址,地址冲突导致应答混乱。
- 主机和从机的电平域不一致,比如主机是 5V 系统、从机是 3.3V 系统,没有做电平转换,从机可能根本识别不了 SDA 上的高电平和低电平,自然就不 ACK。
第二类:数据阶段 NACK——地址 ACK 了,但数据没 ACK。这种情况说明从机存在、地址正确,但它在数据阶段拒绝接收。常见原因:
- 写入只读寄存器或向只读器件写数据,从机按协议规定不 ACK。
- 写入的字节数超过器件支持的页大小(EEPROM 页写溢出),从机在页边界拒绝 ACK。
- 主机发送的数据格式不符合从机的寄存器映射要求(比如某些器件要求先写寄存器地址再写数据)。
- 从机内部状态异常,比如正在处理上次命令、或者进入了错误状态,暂时不响应。
第三类:总线上根本没有 ACK 位出现——SDA 被拉死。这种情况下示波器上看到的是 SDA 始终为低、SCL 还在一跳一跳。通常是某个从机故障,把 SDA 一直占用拉低,导致主机根本没法释放 SDA 来表达 ACK/NACK。这种"总线死锁"在万用表上表现为静态 SDA 电压接近 0V,但有时是间歇性的,需要通过长时间抓波(用示波器的余晖模式或者 Roll 模式)才看得到。
4.3 地址换算的坑:7 位地址和 8 位地址
我统计过,我接触过的 I2C 故障里,至少有三成跟地址换算有关系。原因是不少芯片数据手册写的是 7 位地址,但代码或调试工具要求填 8 位地址(7 位地址左移一位、最低位填 R/W 位)。很多人在这里来回错位。
举例:某 EEPROM 的 7 位地址是 0x50(二进制 1010000),加上写位(R/W=0)后,实际发送的 8 位字节是 0xA0(10100000);加上读位(R/W=1)后是 0xA1(10100001)。如果调试工具里要求填 8 位地址,你却填了 7 位地址 0x50,工具会直接把这个字节发到总线上,实际总线上的 7 位地址就变成了 0x28(0101000)——和器件期望的 0x50 正好错开一位,从机当然不会应答。
排查方法:示波器看地址阶段的那 8 个 bit,按波形解出实际发送的地址值(注意 I2C 是高字节在前,MSB first),对比数据手册的 7 位地址是否正确。我在代码里通常这样处理:
uint8_t addr_7bit = 0x50; uint8_t addr_8bit_write = (addr_7bit << 1) | 0; // 0xA0 uint8_t addr_8bit_read = (addr_7bit << 1) | 1; // 0xA1如果波形上地址阶段的 bit 序列解出来是 0101000(0x28),而器件数据手册要求 0x50(1010000),那就是"7 位/8 位地址混用"的经典错误。这个问题在裸机代码里好排查,在 Linux 驱动里也有类似情况——i2c-tools 的i2cget默认填的是 7 位地址,但有些驱动 API 要求的却是 8 位,切换调试手段时这个差异会突然冒出来。
5. 完整排查流程:一次真实故障的定位过程
5.1 复现故障和抓取第一手波形
前面几章讲的是工具能力,这一章我把它们串成一套可以照着做的流程。以一次典型的"I2C 传感器偶发读取失败"为例。
拿到故障报告后,第一步不是改代码,而是复现。我通常把示波器探头预先夹好(SCL 到 CH1、SDA 到 CH2、地线夹最短距离),设置成 SDA 下降沿触发,时间基准先设大一点(比如每格 200μs),然后让设备连续跑读取命令。
为什么要先设大时间基准?因为你不知道故障发生率有多高。如果你上来就设 50μs/格,看到的只是单次传输的放大图,可能等半天也碰不上故障那一次。先用 200μs 甚至 1ms/格"俯瞰"总线活动,确认哪一次传输异常、异常发生在哪个字节位置,再把时间基准调小去仔细看。
复现的另一个技巧是"适当放大故障率"。如果故障是偶发的,可以试着把总线频率调高(比如从 100kHz 调到 400kHz)、把电源电压调到临界值、或者把上拉电阻临时换成大阻值,让信号余量变小,故障就更频繁出现。这不是修改产品设计,而是为了快速定位薄弱环节,定位后再把参数调回去。
5.2 按信号完整性五要素逐一排除
抓到异常波形后,我习惯按五个要素逐项检查,不跳步:
- 电平幅度:SCL/SDA 高电平是否接近 VCC,低电平是否接近 GND。偏离就查上拉、查器件驱动能力。
- 边沿质量:上升沿是否有明显缓慢爬升、振铃、台阶。有就用 RC 理论倒推上拉电阻和总线电容是否匹配。
- 时序关系:SDA 在 SCL 采样点是否稳定。建立时间和保持时间是否满足规范。不满足就查代码产生波形的方式(是硬件 I2C 外设还是 GPIO 模拟),以及从机数据手册的时序要求。
- ACK 位:第 9 个时钟 SDA 是否被正确拉低,拉低到多少伏。NACK 就按上一章的三种分类逐一排除。
- 信号完整性干扰:是否有毛刺/振铃叠加在上升沿或下降沿。有就检查地回路、探头接法、PCB 布线(SDA 和 SCL 是不是被其他高频信号串扰了)。
这五要素的顺序是我刻意安排的:先排除最基础的电气问题(电平、边沿),再看时序逻辑,最后才怀疑噪声干扰。大部分人一上来就怀疑是干扰,结果换了一堆屏蔽线也没用,最后发现是上拉电阻选错——因为干扰排查成本最高,而基础电气问题其实一眼就能看出来。
5.3 代码回读与波形交叉验证
信号层面排查完之后,还要做一层"协议内容"的验证。示波器上看到了正常的 ACK、正常的时序,不代表协议内容就对——可能地址对了、ACK 了,但数据字节内容发错了;或者 SDA 上确实有波形,但波形对应的 bit 序列并不是代码里想要传送的内容。
这时候用逻辑分析仪(或者示波器的 I2C 解码功能)把波形解成协议帧,对照代码里的收发缓冲数组一项一项核对。具体做法:
- 先在代码里定义一个发送缓冲区,把要发送给从机的字节序列打印出来或者固定写死。
- 逻辑分析仪抓到的帧应该能解出同样的地址、寄存器地址和数据字节。
- 如果帧内容对不上,说明问题在固件端——可能是 I2C 库的封装用错了地址参数、或者字节序有问题;如果帧内容一致但功能不对,说明问题在从机端配置或寄存器语义理解错误。
我在实际项目中遇到过一种情况:波形完美、ACK 也有、数据也对,但传感器就是不工作。后来发现是 datasheet 上寄存器地址表印错了(某个寄存器地址实际是 0x1E 而不是 0x1D)。这类问题信号测量解决不了,只能靠逻辑分析仪把"I2C 层"验证通过之后,再用功能测试去验证"器件语义层"。但它依然离不开前面的信号测量——因为你必须先确认 I2C 物理层没问题,才有资格怀疑寄存器表有问题。
6. 实测中的意外状况和处理经验
6.1 时钟延展:从机把 SCL 拽住不放
时钟延展(clock stretching)是 I2C 协议中一个"可选项",很多从机在需要时会把 SCL 拉低,迫使主机等待,以此延长低速操作的处理时间。问题是:很多 I2C 主控(尤其是简单 GPIO 模拟的)根本不支持时钟延展,或者支持得不完整,导致从机一拉低 SCL,主机就判定超时、重发甚至崩溃。
波形上的特征:SCL 在某个低电平位置停留时间明显比正常时钟周期长,可能长到几毫秒甚至更多。SDA 可能是高或低,取决于从机正在做什么。
排查思路:先用示波器确认从机是否在时钟延展。如果确实是,再查主控是否支持——硬件 I2C 外设基本都支持,但需要开启相关配置;GPIO 模拟的话就要修改代码,让主机在 SCL 拉低时等一等,不要死读。我记得有一次做 EEPROM 页写,写完 64 字节后从机做内部编程,SCL 被拉低了 5ms,我的 GPIO 模拟代码没有等延展,直接发了第二个写命令,导致第一个命令丢了一半数据。后来在每次启动条件前加了一个 SCL 等待延展的循环才解决。
6.2 突破负载极限:总线电容和上拉电流的平衡
I2C 规范对总线电容有要求:标准模式上限 400pF,快速模式上限 200pF(快速模式+是 550pF)。多挂几个器件、走线一长,电容就上去了。
当你发现波形上升沿过缓、低电平压不下去的时候,既要考虑减小上拉电阻,也要考虑减小总线电容。减电容的办法:
- 缩短 SCL/SDA 走线长度,避免绕圈。
- 减少挂载器件数量,或者把 I2C 分成多路(用 I2C 多路复用器如 TCA9548A 之类的芯片分路)。
- 避免在 SCL/SDA 上并联不必要的保护器件,有些 TVS 管寄生电容很大(几十 pF 到几百 pF),会拖慢边沿。
我遇到过一块板子,为了让信号过 ESD 测试,在 SCL/SDA 上各加了一颗 TVS 管,结果 I2C 400kHz 死活跑不稳,示波器一看上升沿 1μs 都打不住。拆掉 TVS 后一切正常。后来选了低电容 TVS(小于 1pF)才兼顾保护和信号质量。
6.3 探头电容对高速 I2C 的影响
前面提到 1× 探头比 10× 探头输入电容大,测 I2C 时影响不可忽视。实际影响有多大?标准示波器 10× 探头输入电容约 10~15pF,1× 探头约 50~150pF(不同品牌差异很大)。如果总线电容本来就接近 200pF,再并上一个 100pF 的 1× 探头,上升沿明显变缓,甚至会让原本正常的通信在测量状态下变失败。
所以我在测 I2C 的时候有一条铁律:示波器探头必须用 10×,并且接入后再看一次总线通信是否还正常。如果接入探头后故障消失或者出现,说明探头本身的负载效应在干扰被测系统。这时候要么换更低电容的探头(有源探头/差分探头,虽然贵但必要时用),要么用逻辑分析仪的低电容输入接口来监测。
还有一个经验:如果要长时间监测 I2C 波形(比如复现偶发故障),建议用示波器的"余晖模式"或者长余辉显示,把多次触发的波形叠加在一起。偶发的毛刺、NACK、时序异常在这种模式下会以"暗影轨迹"的形式显现出来,比单帧截图更容易发现异常。
最后说一点个人体会。I2C 的排查之所以让很多人觉得难,不是因为它复杂,而是因为它"太简单"——两根线,一个地址,一个 ACK,看起来翻不出什么浪花。但恰恰是这种简单,让每一层(电气层、时序层、协议层、器件语义层)的问题都会最终表现为同一个现象:通信失败。如果你手里只有万用表,能排查的范围就止步于静态电平;如果你习惯了示波器的协议触发,就能直接定位到 ACK 位;如果再把逻辑分析仪的帧解码用起来,整个 I2C 传输在你的脑子里就是一帧一帧清清楚楚的画面。工具每多一层,你能"看见"的东西就多一层——这也是我写这篇排查流程的初衷:不是让你背参数,而是让你知道在故障面前,应该按什么顺序去看、去测、去判断,让每一次测量都回答一个具体问题。