驱动之路#46:如何测量与分析 I2C 信号?

描述

 前面几篇文章,我们已经把 I2C 的基础内容聊得差不多了。

从 I2C 通信机制,到上拉电阻,再到 I2C 子系统、I2C-tools,基本算是把理论和工具都过了一遍。

但实际工作中,最让人头疼的往往不是理论,而是这种情况:

  •  
  •  
  •  
  •  
设备树配了;驱动也加了;供电看起来也正常;但 i2cdetect 就是扫不到设备。

这时候怎么办?

继续盯着代码看,很多时候意义不大。

I2C 本质上就两根线:SDA 和 SCL。软件怎么配,最后都要落到这两根线上。所以真遇到 I2C 设备不应答,最直接的方法就是:拿万用表和示波器看信号。

这篇文章就简单聊聊:I2C 信号怎么测,波形怎么看,ACK 又该怎么判断。

1. 先快速回顾 I2C 通信

在 I2C 协议里,数据传输的基本单位是字节,也就是 8bit。

但传输 1 个字节,实际需要 9 个时钟周期:

  •  
  •  
前 8 个时钟:传输 8bit 数据;第 9 个时钟:传输 ACK / NACK 应答信号。
I2C

另外,I2C 传输时遵循高位在前,也就是 MSB first。

几个关键信号也再过一遍:

起始信号 S
SCL 为高电平期间,SDA 从高电平跳变为低电平。

停止信号 P
SCL 为高电平期间,SDA 从低电平跳变为高电平。

应答信号 ACK
接收器收到 8bit 数据后,在第 9 个时钟周期拉低 SDA。

还有一个很重要的规则:

SDA 上的数据,必须在 SCL 为高电平期间保持稳定;只有当 SCL 为低电平时,SDA 才允许变化。

这句话对看波形很重要。

因为判断 I2C 波形是否正常,本质上就是看 SDA / SCL 是否符合这个时序规则。

2. i2cdetect 扫不到设备,先别急着改驱动

设想一个常见场景:外接了一个 I2C 设备,比如触摸 IC、传感器或者电源芯片。

设备树也配了,I2C 控制器也打开了,但执行:

  •  
i2cdetect -y 2
就是扫不到设备地址。

这时候很多人第一反应是:

  •  
  •  
  •  
  •  
是不是 compatible 写错了?是不是驱动没加载?是不是 reg 地址写错了?是不是 kernel config 没开?
这些当然都要查。

但如果连 i2cdetect 都扫不到设备,说明更底层的 I2C 通信可能都没建立起来。

这时候我通常会先把问题拆成两部分:

  •  
  •  
1. SoC 到 I2C 接口这条信号链路是否正常?2. 外接 I2C 设备本身是否正常应答?

为了排除外设干扰,有时候可以先把 I2C 设备拆下来,只保留 SoC 侧的 SDA / SCL 和上拉电阻。

这么做的目的很明确:

先确认 SoC I2C 控制器输出的信号是否正常,再判断外设是否应答。

这样能避免一上来就在软件、硬件、外设之间来回猜。

 第 1 步:先测 SDA / SCL 空闲电压

测波形之前,先用万用表测一下 SDA 和 SCL 的空闲电压。

问题来了:当 I2C 总线上没有通信、甚至没有接外设时,SDA 和 SCL 应该是什么电平?

答案是:高电平

原因前面讲过,I2C 是开漏 / 开集输出,需要外部上拉电阻。

所以总线空闲时,SDA 和 SCL 都应该被上拉到 VCC。

比如系统是 3.3V 上拉,那么空闲状态下:

  •  
  •  
SDA ≈ 3.3VSCL ≈ 3.3V

如果测出来不是这个结果,就要先查硬件:

  •  
  •  
  •  
  •  
  •  
  •  
[ ] 上拉电阻有没有焊?[ ] 上拉电源是不是正确?[ ] 电阻阻值是否异常?[ ] SDA / SCL 是否被某个设备一直拉低?[ ] 引脚是否复用错?[ ] 是否存在短路或虚焊?

这个步骤很基础,但非常有用。

很多 I2C 问题,最后查半天,发现就是上拉电阻没焊、焊错值、或者某个外设把总线拉死。

所以别小看万用表这一步。

第 2 步:用示波器抓 i2cdetect 波形

确认空闲电压正常后,就可以看波形了。

实操方法也很简单:

一边执行:

  •  
i2cdetect -y 2

一边用示波器抓 SDA 和 SCL。

建议这样接:

  •  
  •  
  •  
CH1:SCLCH2:SDAGND:板子地

执行 i2cdetect 时,主机会不断向不同 I2C 地址发起访问,所以总线上会出现一串 I2C 波形。

如果 I2C 控制器工作正常,至少应该看到:

  •  
  •  
  •  
  •  
SCL 有规律地输出时钟;SDA 跟随数据发生变化;起始信号和停止信号存在;每 8bit 数据后有第 9 个 ACK 时钟。

如果连 SCL 都没有波形,那就要回头查:

  •  
  •  
  •  
  •  
  •  
  •  
[ ] I2C 控制器是否打开;[ ] pinctrl 是否配置正确;[ ] 当前测的是不是正确引脚;[ ] i2cdetect 的总线编号是否正确;[ ] 控制器驱动是否加载;[ ] 时钟资源是否正常。

如果 SCL 有波形,但 SDA 不对,再重点查 SDA 线、上拉、外设拉低、地址应答等问题。

第 3 步:重点看第 9 个时钟的 ACK

看 I2C 波形时,新手不一定要一上来就把所有 bit 都解出来。

调试阶段最关键的是先看一个东西:第 9 个时钟周期,SDA 有没有被拉低。

前面说过,I2C 每传输 8bit 数据后,第 9 个时钟是 ACK 周期。

如果从设备正常应答,它会在第 9 个时钟周期拉低 SDA。

也就是说:

  •  
  •  
第 9 个时钟周期 SDA 被拉低:ACK,设备应答;第 9 个时钟周期 SDA 保持高电平:NACK,设备未应答。

这个现象非常关键。

比如拆掉外设后,再执行 i2cdetect 抓波形。

这时你会看到主机确实发出了地址和时钟,但第 9 个时钟周期 SDA 没有被拉低。

I2C

这是正常现象,因为外设已经拆掉了,不可能有人返回 ACK。

如果接上外设后,地址正确、供电正常、复位释放正常,那么在访问对应地址时,第 9 个时钟周期应该能看到 SDA 被外设拉低。

看到这个 ACK,至少说明:

  •  
  •  
  •  
  •  
[ ] 主机发出了 I2C 波形;[ ] 外设识别到了地址;[ ] 外设能正常拉低 SDA;[ ] 主从通信已经初步建立。

这比单纯看软件日志更直观。

 

3. 正常波形应该长什么样?

一个比较正常的 I2C 波形,大概有这些特征:

  •  
  •  
  •  
  •  
  •  
  •  
1. 空闲状态下,SDA 和 SCL 都是高电平;2. Start 时,SCL 高电平期间 SDA 从高变低;3. 数据传输时,SCL 高电平期间 SDA 保持稳定;4. 每 8bit 数据后,有第 9 个 ACK 时钟;5. 如果设备应答,第 9 个时钟周期 SDA 会被拉低;6. Stop 时,SCL 高电平期间 SDA 从低变高。

	I2C
	

如果波形大体符合这些特征,说明 I2C 总线时序基本没问题。

这时候如果软件还访问失败,就可以进一步查:

  •  
  •  
  •  
  •  
  •  
设备地址是否正确;读写方向是否正确;寄存器访问格式是否正确;设备是否需要初始化命令;驱动里通信流程是否符合芯片手册。

4. 异常波形怎么看?

I2C 异常波形大概可以分几类。

(1)SDA / SCL 一直低

如果 SDA 或 SCL 一直是低电平,说明总线可能被拉死。

常见原因:

  •  
  •  
  •  
  •  
  •  
  •  
[ ] 外设异常,把 SDA / SCL 拉低;[ ] 引脚短路到地;[ ] GPIO 复用错误;[ ] 电源异常导致外设状态异常;[ ] I2C 控制器处于异常状态;[ ] 焊接问题。

这种情况下,i2cdetect 通常也扫不到设备。

(2)SDA / SCL 一直高,没有波形

如果 SDA / SCL 都是高电平,但执行 i2cdetect 时没有任何波形,说明主控侧可能根本没发起 I2C 传输。

重点查:

  •  
  •  
  •  
  •  
  •  
  •  
[ ] i2cdetect 的 bus 编号是否正确;[ ] /dev/i2c-X 是否存在;[ ] I2C 控制器设备树是否启用;[ ] pinctrl 是否正确;[ ] 测试点是否选错;[ ] 控制器驱动是否 probe。
 (3)有时钟,但没有 ACK

这种情况比较常见。

现象是 SCL 有时钟,SDA 也有地址数据,但第 9 个时钟周期 SDA 没有被拉低。

说明主控在喊设备,但没有设备回应。

重点查:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
[ ] I2C 设备地址是否正确;[ ] 外设供电是否正常;[ ] reset / enable 是否释放;[ ] 外设是否还在复位状态;[ ] SDA / SCL 是否接反;[ ] 设备是否挂在当前这一路 I2C 上;[ ] 是否存在地址位理解错误。

这里特别提醒一下:有些芯片手册写的是 8bit 地址,有些 Linux 驱动里用的是 7bit 地址,新手很容易搞混。

(4)波形纹波大、边沿很差

还有一种情况是,波形看起来有变化,但质量很差。

比如:

  •  
  •  
  •  
  •  
  •  
  •  
上升沿很慢;电平抖动明显;纹波很大;高电平达不到标准;低电平拉不下去;毛刺很多。

这类问题就不太像纯软件问题,更像硬件信号质量问题。

重点查:

  •  
  •  
  •  
  •  
  •  
  •  
  •  
[ ] 上拉电阻值是否合适;[ ] 是否重复上拉导致电阻过小;[ ] 总线是否过长;[ ] 挂载设备是否过多;[ ] PCB 走线是否受干扰;[ ] 是否有强干扰源靠近;[ ] 示波器探头接地是否合理。

我之前就遇到过一种情况:执行 i2cdetect 时能看到波形,但纹波过大,最后直接影响 I2C 通信稳定性。

这种问题看日志不一定明显,但示波器一抓就很直观。

I2C

 

5. 一个实用排查流程

以后遇到 I2C 设备扫不到,可以按下面流程来:

I2C 信号排查 Checklist:
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
[ ] 1. 确认 /dev/i2c-X 是否存在;[ ] 2. 确认 i2cdetect 使用的 bus 编号正确;[ ] 3. 万用表测 SDA / SCL 空闲电压是否为上拉电压;[ ] 4. 执行 i2cdetect,同时示波器抓 SCL/SDA;[ ] 5. 确认 SCL 是否有时钟输出;[ ] 6. 确认 SDA 是否有数据变化;[ ] 7. 确认第 9 个时钟周期是否有 ACK;[ ] 8. 若无 ACK,检查地址、供电、复位、接线;[ ] 9. 若波形质量差,检查上拉、电容、走线、干扰;[ ] 10. 若波形正常但驱动失败,再回到软件层查 probe 和寄存器访问流程。

这个顺序比较重要。

不要一上来就陷入驱动源码。

I2C 是低速总线,很多问题拿示波器看一下,基本就能判断方向。

6. 总结

I2C 调试时,软件日志只能告诉你“失败了”,但示波器能告诉你“到底失败在哪里”。

如果 i2cdetect 探测不到设备,可以先看两件事:

  •  
  •  
1. SDA / SCL 空闲电压是否正常;2. 执行 i2cdetect 时,波形是否有时钟、数据和 ACK。

其中最关键的是 ACK:

  •  
  •  
第 9 个时钟 SDA 被拉低:设备应答;第 9 个时钟 SDA 没拉低:设备未应答。

看到 ACK,说明主从通信至少建立起来了。

看不到 ACK,就优先查地址、供电、复位、上拉、接线和总线编号。

如果波形纹波大、边沿差、干扰严重,就要回头查硬件设计和信号质量,而不是继续死磕驱动。

一句话总结:

I2C 调不通时,别只看代码;SDA / SCL 的电压和波形,往往比日志更诚实。

(完)

下期可以继续聊:如何调试 I2C 设备?


本人专注 Linux 嵌入式全栈开发,有项目合作 / 技术支持 / 交个朋友,欢迎后台私信。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分