ARTICLE DETAIL

资讯详情

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

I2C通信调试实战:用示波器破解ACK/NACK与总线故障

I2C通信调试实战:用示波器破解ACK/NACK与总线故障 1. 先从一块能上电、电压全对却读不到数据的板子说起做嵌入式或者硬件调试的朋友应该都遇到过这种场景板子能上电电源灯亮着SDA和SCL两根线用万用表一量3.3V稳稳当当上拉电阻也焊了地址对着芯片手册核对了一遍又一遍但I2C通信就是不通。我当时调试一块带触摸屏的开发板就是这种状态代码里读GT911的ID返回值永远是0xFF或者超时折腾了两天才想起来用示波器看看总线上的真实波形。结果波形一抓出来问题清清楚楚主机在发地址阶段就收到了NACK从机根本就没响应。那一刻我才意识到之前用万用表测的那些正常电压只能证明总线静态状态没问题完全不能代表通信过程中信号是好的。这也是很多初学者最容易卡住的地方——工具用错了层级问题就永远隔着一层窗户纸。这篇文章我想把I2C信号排查这件事从头到尾捋一遍什么情况下用万用表就够什么情况下必须上示波器拿到波形之后怎么判读ACK/NACK以及一套能直接复用的排查流程。适合正在调I2C通讯但毫无头绪的工程师也适合刚接触I2C协议想搞明白信号到底怎么回事的学生和爱好者。2. 万用表在I2C总线上的能测与不能测2.1 万用表真正能做好的三件事很多人一提到测I2C就想着示波器但说实话在示波器上场之前万用表能把不少低级问题直接筛掉。我认为在I2C调试里万用表最值得做的三件事是通断测试、上拉电阻测量、静态电平测量。先说通断测试。SDA和SCL线在PCB上走线断裂、排线虚接、焊盘脱落这类物理问题用万用表的通断档一测就知道。我见过一个案子I2C偶尔通信失败排查到最后是FPC排线的SCL线有一处几乎断裂弯曲的时候接触不良。这种故障你用示波器抓波形未必能第一时间抓到因为它是间歇性的但用万用表顺着线从头到尾量一遍通断问题直接暴露。其次上拉电阻的阻值测量。I2C是开漏结构SDA和SCL必须靠上拉电阻拉高。很多开发板出厂时上拉电阻是装不装都能跑的状态因为主控内部有弱上拉但内部上拉通常几十kΩ驱动能力很弱总线稍微长一点或者挂的从机多一点信号质量就崩了。用万用表电阻档测一下板上的上拉电阻是否在预期范围一般1kΩ到10kΩ之间就能排除一大半硬件问题。第三静态电平测量。总线空闲时SDA和SCL应该都被拉到高电平。如果测出来某一路是0V说明总线被拉低了——可能是某个从机异常占用了总线也可能是SDA和SCL之间短路。我就遇到过SDA和SCL在PCB上距离太近焊接时锡桥短路的情况两条线全部被拉低用万用表一测就能锁定。2.2 为什么万用表测不了I2C协议但万用表有它的物理极限。I2C标准模式跑100kHz快速模式400kHz快速模式能到1MHz。万用表的采样率是多少普通数字万用表每秒采样几次到几十次好一点的也就几百次它看到的是一个又一个瞬间快照完全无法还原信号随时间变化的细节。更关键的是万用表只能测电压的稳态值。I2C通信时的信号是一连串的脉冲跳变ACK位更是发生在第9个时钟沿附近的一个短暂拉低动作用万用表去测这个动作就像用一张照片去判断一个人跑步的步频信息维度完全不够。所以请记住一个结论万用表用于排除静态故障拿它验证总线电平对不对可以拿它验证协议通信正不正常就是缘木求鱼。顺便说一句有些朋友用MF50这种指针表或者DT830B这类入门数字表来观察总线活动把表笔点在SDA上看指针是不是在抖动来判断有没有数据在传。这个方法理论上有一点点用但实际意义不大因为I2C的数据速率远超表头的机械响应速度指针的抖动更多是噪声干扰看不出协议细节。早期维修电视、工控设备时用指针表看总线有没有活动与其说是测信号不如说是碰运气。现在有示波器或者逻辑分析仪没必要用这种原始手段。2.3 测上拉电阻时容易被忽略的计算逻辑测上拉电阻不只是看有没有还要看合不合适。我见过不少板子上拉电阻选了10kΩ在100kHz标准模式下勉强能跑一升到400kHz快速模式就频繁出错。这里面的原因是RC充电时间常数上拉电阻越大总线电容充电越慢信号上升沿就越缓。I2C规范对上升时间是有明确要求的标准模式最大1000ns快速模式最大300ns。估算最大上拉电阻有个常用公式Rmax Tr / (0.8473 × Cbus)。假设总线寄生电容是200pF标准模式下要求Tr不超过1000ns那么Rmax 1000ns / (0.8473 × 200pF) ≈ 5.9kΩ。如果用10kΩ上拉上升时间会超标信号沿太缓从机的输入阈值判断就容易出错。最小上拉电阻则受灌电流限制Rmin (VDD - VOLmax) / IOLmax。以3.3V系统为例VOLmax取0.4VIOLmax取3mARmin (3.3 - 0.4) / 0.003 ≈ 966Ω所以上拉电阻取1kΩ以上比较稳妥。快速模式400kHz常见选择就是1kΩ到2.2kΩ标准模式100kHz取4.7kΩ到10kΩ都能接受前提是总线上挂的从机数量不多。这些在示波器上看得清清楚楚但先用万用表量出阻值心里大概有个数再看波形就有的放矢了。3. 示波器测I2C的正确姿势触发、解码、测量三件套3.1 探棒怎么接通道分配与探头选择示波器测I2C第一步是接线。我的习惯是CH1接SCLCH2接SDA跟示波器协议解码器的通道映射保持一致这样做有两个好处一是屏幕上SCL在上、SDA在下波形和时间顺序一目了然二是解码器设置时不用额外调整通道映射减少出错机会。探头方面10x衰减探头是必须的。1x探头带宽通常只有几MHz到几十MHz测I2C的上升沿波形会被严重失真看起来像圆角矩形实际是探头带宽不够。10x探头带宽高但要注意接地线尽量短——探头的接地夹线太长会引入电感在信号沿上产生振铃看起来像毛刺影响判读。如果你只是随便看看波形长接地线影响不大但要精确测量上升时间、判断信号完整性接地线一定要用短弹簧地针。带宽选择上100MHz的示波器测I2C完全够用。I2C最高1MHz100MHz带宽对应上升时间约3.5ns远快于I2C信号本身的沿。不需要为测I2C特意追求高带宽示波器把预算花在协议解码功能或者逻辑分析仪上更实在。3.2 触发放置与时基选择抓住一次完整事务很多人在示波器上看到的I2C波形是一片乱码一样的密集脉冲觉得这玩意没法看其实是触发没设对。I2C通信的起点是SDA在SCL高电平期间产生一个下降沿START条件所以触发应该设在SDA的下降沿并且用单次触发或者普通触发配合适当的时基。我自己常用的设置是触发通道选SDA触发方式选下降沿触发电平设在VDD的一半3.3V系统就是1.65V。时基怎么选先估算一下一次完整事务的时间。比如要从机读4个字节地址字节1个、寄存器地址2个、数据4个加上ACK/STOP等大概在10个字节左右每字节9个时钟周期100kHz下每个周期10μs总时长约0.9ms。时基设成200μs/div到500μs/div正好能覆盖一个完整事务。设好了按一下Single然后触发一次I2C读操作屏幕上就会稳稳地抓到从START到STOP的完整波形。这里有个关键经验如果你用的是没有协议解码功能的示波器抓波形时一定要把时基拉开看全貌然后逐步缩小看细节。先确认有没有START条件、有没有STOP条件、字节数量对不对再把某个字节的波形放大数出8个数据位加上1个ACK位。如果一上来就把时基调到很细看到的是孤零零的一个字节反而容易迷失方向。3.3 现代示波器的协议解码先看解码再看波形现在主流的示波器无论是普源、鼎阳这类国产品牌还是力科、泰克这些进口品牌基本都带了I2C协议解码功能。用了解码之后示波器会直接在屏幕上标出START、地址字节、读写位、ACK/NACK、数据字节、STOP省去了手动数时钟的巨大工作量。以力科示波器为例配合SCPI指令甚至可以把解码结果批量导出做自动化分析这是老式示波器完全做不到的。协议解码的设置入口通常有两个关键参数I2C通道映射SCL选哪个通道、SDA选哪个通道和逻辑阈值一般选TTL或者直接手动设成1.65V。阈值设置尤其重要如果阈值高于信号高电平或者低于信号低电平解码结果就会乱码。在实际项目里我喜欢先解码、后测参解码是对是错直接反映信号逻辑层面是否正常但解码正常不意味着信号物理层面合格还要用示波器的测量功能看一下高电平、低电平、上升时间、SCL频率这些参数。测量项里我重点盯四个SCL频率实际值、高电平VOH、上升时间Tr、SDA和SCL的建立/保持时间。频率超了或者低了说明主控的I2C时钟配置不对上升时间超标说明上拉电阻偏大或者总线电容过大建立起时间不够常见于软件模拟I2Cbit-bang的场景GPIO翻转的时序跟硬件I2C外设比容易出问题。这些在解码结果里看不出来必须依赖波形的模拟量测量。4. ACK的波形判读与根因倒推从第9个时钟开始4.1 ACK/NACK在波形上到底长什么样ACK是I2C协议里最容易理解也最容易出问题的环节。每一个字节传输完毕后在第9个SCL时钟周期主机释放SDA也就是不驱动它从机如果正常接收会把SDA拉低表示我收到了。如果从机没有应答SDA在第9个时钟期间保持高电平就是NACK。在示波器上ACK的判读方法非常直接数到每个字节的第9个SCL下降沿看此时SDA是低还是高。SDA为低ACK正常SDA为高NACK。很多示波器的解码功能会直接在波形上用字母标出ACK或者NACK配合波形验证十分钟就能学会。但有一个细节值得注意ACK看起来是第9个时钟时SDA为低实际上从机拉低SDA的动作是有延迟的。规范要求从机必须在第9个时钟的SCL下降沿之前把SDA拉低并且保持到SCL下降沿之后。如果从机响应慢SDA的拉低动作发生在第9个时钟沿附近看起来就像一条窄窄的负脉冲这时候用示波器的高分辨率模式或者把时基放大才能看清这个ACK脉冲是否存在。我遇到过一种情况从机内部固件处理不过来ACK脉冲宽度只有几百纳秒肉眼在整帧波形上根本看不见放大之后才发现其实有ACK只是窄得可怜。4.2 从NACK现象出发的根因分类与排查链路一旦确认NACK问题范围就大大缩小了。我这里把常见原因整理成一张表方便对照现象特征可能根因确认手段解决办法地址阶段NACK且地址字节完全正确从机未上电、未复位、地址配置引脚错误万用表测从机电源核对地址引脚电平补电源修正地址配置地址阶段NACK且地址字节与手册对不上软件里地址没左移或左右移错对照手册确认7位地址和8位写地址的换算把7位地址左移1位再填地址有ACK但第2字节寄存器地址NACK从机不支持该寄存器地址或寄存器地址长度不对对照手册的寄存器映射表修正寄存器地址数据阶段NACK从机忙/缓冲区满/不支持连续写查看从机状态寄存器改为单字节写入或加入延时随机出现NACK且示波器看到SDA上升沿很缓总线电容过大、上拉电阻偏大、信号质量差测量Tr估算Rmax减小上拉电阻或降低速率总线完全没有波形SDA一直低总线死锁从机地址冲突或驱动异常用万用表测SDA电平逐从机断开排查复位从机修正地址冲突这里面最典型的坑是地址换算。I2C的7位地址比如0x5D实际发送时是8位高7位是地址最低位是读写标志0写1读所以写地址是0xBA0x5D 1 | 0读地址是0xBB0x5D 1 | 1。很多芯片手册会直接给出8位形式0xBA/0xBB但代码库的API可能只接受7位地址或者反过来。你拿示波器看到地址字节发的是0xBB但你的从机在等0x5D自然就是NACK。4.3 软件模拟I2C时的ACK观察与手动ACK问题排查到软件层还有一个高频问题GPIO模拟I2C时主机在第9个时钟前没有释放SDA。硬件I2C外设自动处理释放动作但bit-bang代码要是写成GPIO始终输出从机想拉低SDA也拉不动因为你主机在强驱动高电平。这种问题的波形特征很典型其他时候SDA波形正常偏偏第9个时钟期间SDA保持高电平看起来像NACK实际上是主机在抢占总线。用示波器观察这种场景要特别注意把SDA波形和SCL波形放在同一屏放大第9个时钟附近看SDA在SCL高电平期间是否有被从机强行拉低的痕迹——有时候波形会有一个短暂的凹陷但马上被主机拉回去这就是总线竞争。我之前调试一个用GPIO模拟I2C的项目就是靠这个波形细节判断出问题在代码里而不是从机没回应。修改方法很简单在发送完8位数据后把SDA对应的GPIO切换为输入模式高阻态等第9个时钟结束后再恢复输出。4.4 ACK位之外总线死锁与自由数据模式ACK排查之外还有一类隐蔽问题值得单独说I2C总线上有多个从机其中一个从机的地址跟另一个冲突会导致总线在特定时刻被异常拉低波形看起来像是发送过程中SDA被强行劫持。这种情况常见于使用I2C多路复用器或者同一型号芯片挂多路时地址引脚如AD0/AD1配置没处理好。用示波器观察会发现在主机没有输出低电平的时刻SDA却出现了低脉冲这就是从机在错误地响应同一个地址。另外自由数据模式这个在部分老款I2C控制器手册里的名词其实描述的是SCL持续脉冲、SDA无起始条件的数据传输状态。如果你在示波器上看到SCL一直在翻转但波形不包含START/STOP条件大概率是从机的初始化时序没走对或者主控的I2C控制器进入了异常状态。这种情况排查思路要回到软件初始化流程检查是否在从机准备好之前就启动了通信。5. 完整案例GT911触摸屏I2C通信失败的排查全过程5.1 第一步万用表扫雷排除物理层故障回到开头说的那块带GT911的开发板。GT911是一颗电容触摸屏控制芯片用I2C接口跟主控通信。当时代码里初始化触摸屏失败读ID都是0xFFFF我第一步不是上示波器而是拿万用表做了一轮快速检查。先测VDD引脚3.3V正常。再测INT和RST引脚复位脚电压有中断脚因为没配置所以悬空合理。然后测SDA和SCL的空闲电平都在3.3V说明上拉正常总线没被拉死。顺着布线量了SDA和SCL到主控引脚的通断也OK。到这里万用表能查的都查完了结论是物理层没毛病。这个过程大概花了五分钟但它排除了所有低级错误让我在后面用示波器时能专注在协议层。5.2 第二步示波器抓出第一条完整波形锁定NACK接下来上示波器。CH1接SCLCH2接SDA触发放SDA下降沿时基先设500μs/div按Single然后让代码执行一次触摸屏初始化。抓到的波形显示主控确实在发数据但第一个字节结束后就出现了NACK整个事务没走完就停了。这里要提一个细节GT911的I2C地址是可配置的通过一个引脚的电平决定常见配置为0x5D/0x14或0xBA/0x28等。代码里用的是I2C_WriteByte(0xBA, ...)这种写法看似没问题但我示波器上看了一下实际发出的地址字节发现跟预期不符。再查代码发现驱动库函数内部把传入的地址又左移了一位等于实际发送0x740xBA 1的结果跟GT911期望的0xBA对不上所以NACK。修正调用方式后地址阶段ACK了。5.3 第三步ACL过了之后数据阶段仍然报错深挖时序地址阶段修好之后通信还是没完全正常。主控能成功发送寄存器地址0x8140GT911的ID寄存器但读回来的数据全是0xFF。示波器抓读时序发现一个有趣的现象地址阶段和寄存器地址阶段都有ACK但到了读数据阶段主机连续收到了两个字节的0xFF而且从机的ACK是正常的。这时问题就不在I2C协议层了而在于GT911这个芯片的寄存器访问规则它要求主机先写入寄存器地址2字节然后才能读取数据并且读取时要有一定的延时等待芯片内部刷新。代码里只写了1字节寄存器地址导致后续读取的寄存器地址完全错位。在示波器上观察能明显看到寄存器地址字节的波形宽度比GT911手册要求的少了8个时钟。把寄存器地址改成2字节并在读操作前加一个5ms延时数据就正常了。这个案例是一个很好的示范示波器上看到的ACK/NACK能帮你快速定位问题出在协议层还是从机内部逻辑但最终能不能解决还要靠你对从机芯片手册的理解。波形是症状的来源手册是病因的解释。5.4 排查中常见的另一个坑主机侧I2C资源不足顺带提一个热词里大家常搜的问题I2C HID该设备找不到足够资源可以使用。代码12。这个现象在Windows设备管理器里出现一般表示主机的I2C控制器资源分配出了问题常见原因是BIOS/ACPI表里I2C设备资源描述冲突或者驱动加载顺序异常。虽然这跟我们上面讨论的嵌入式I2C调试层级不同但排查思路是类似的先看资源分配相当于先查总线物理层再看驱动通信日志相当于看协议层最后用逻辑分析仪抓I2C总线相当于看波形。遇到代码12优先检查BIOS设置里的I2C设备是否被正确禁用/启用以及是否有其他设备占用了同一组I2C控制器资源。6. 配合逻辑分析仪与软件手段建立自己的排查顺序6.1 逻辑分析仪在I2C调试里的独特价值示波器有示波器的好但也有一些场景它不如逻辑分析仪。最典型的就是长时间抓取总线数据示波器的存储深度有限几十毫秒的窗口想抓几百ms甚至几秒的总线活动非常吃力而逻辑分析仪可以连续采样几秒甚至几分钟把这段时间内所有I2C事务按时间顺序解码出来。排查偶发通信失败随机NACK这类问题逻辑分析仪的优势是压倒性的。我自己在项目里通常是两者配合先用示波器看模拟信号质量——电平标不标准、上升沿缓不缓、有没有毛刺再用逻辑分析仪长时间挂机抓协议流程——主控发了什么、从机回了什么、异常发生在哪个环节。示波器负责信号好不好逻辑分析仪负责协议对不对。如果你手头只有示波器也可以先用示波器确认信号质量没问题再用软件层的打印日志辅助排查协议流程但效率上还是逻辑分析仪更方便。至于价格现在入门级的逻辑分析仪几十块就有8通道、24MHz采样率抓100kHz的I2C绰绰有余。比起花大价钱买带协议解码的高端示波器逻辑分析仪是性价比极高的补充工具。pico这类USB示波器如果带协议解码功能也可以充当逻辑分析仪用但不要勉强用普通示波器硬扛长时间解码那是跟自己过不去。6.2 我总结的I2C排查顺序与几条实操心得踩过这么多次坑之后我总结了一套自己的I2C排查顺序分享给大家万用表先行测电源、测上拉、测通断、测空闲电平。排除物理层故障耗时不超过十分钟。示波器看信号质量确认SDA/SCL的电平、上升时间、SCL频率是否符合预期。这一步能揪出上拉电阻选型错误、总线电容过大这类模拟域问题。逻辑分析仪看协议层抓完整事务看地址字节、ACK/NACK、数据内容。如果解码都正常但业务层报错问题大概率在从机逻辑或主控驱动代码。对照手册查细节地址换算、寄存器长度、时序要求一切以芯片手册为准。示波器上的波形特征要跟手册里的时序图逐项比对。最后再分享几个我在实际调试中觉得特别有用的土办法一是抓波形时先把时基放到最大看整帧事务的结构确认START和STOP都在正确位置再逐步放大。很多人一上来就放大看单个字节反而搞不清楚整体流程。二是当ACK看起来很模糊时把示波器的高分辨率模式打开或者用平均采样能有效看清第9个时钟附近的SDA低电平脉冲。有些从机的ACK宽度极窄普通显示模式下很容易被忽略。三是排查完依然找不到问题的时候试着把I2C速率降一档。100kHz下能过、400kHz下不行那问题十有八九是上拉电阻过大致使上升时间超标或者从机跟不上高速模式。降速不是最终方案但能帮你缩小排查范围。四是养成一边看示波器一边按芯片手册对图的习惯。I2C时序图看熟了波形上任何一个异常——ACK缺失、建立时间不足、多余的STOP条件——都能一眼扫出来。这个功夫不花在具体项目上平时多测几颗芯片的波形积累多了自然就有感觉。
返回列表