光
I2C 总线挂死是最让人头疼的现场问题之一:主机发完地址就没了下文,SDA 被拉低不释放,整个总线上的其他从机也跟着瘫痪。上周在一块 STM32 板子上又遇到一次,把排查过程记录下来。
一、先看波形,别急着复位
挂死时先用示波器同时看 SCL 和 SDA。如果 SDA 恒低、SCL 为高,大概率是从机在某个字节中间卡住了——最常见的是从机在等主机的 ACK,或者从机内部状态机跑飞。这时直接复位主机没用,SDA 还被从机拉着。
二、九个时钟脉冲解挂
标准解法是主机手动发 9 个 SCL 脉冲,让从机把卡住的字节吐完、释放 SDA。实现时注意两点:一是先把 SCL/SDA 切到 GPIO 模式再发脉冲,硬件 I2C 外设在挂死状态下往往发不出来;二是发完脉冲后检查 SDA 是否回到高电平,再发 STOP 条件。如果 9 个脉冲后 SDA 还低,基本可以判定从机死锁,只能断电重启从机。
三、时钟拉伸要设超时
很多从机在处理数据时会拉低 SCL 做时钟拉伸,正常。问题出在主机没有超时机制:从机一旦异常,主机就一直等下去。我的做法是在驱动层给每次等待加超时(比如 10ms),超时后走解挂流程并记一条错误日志,现场定位能省一半时间。
四、根因多半在时序不在代码
这次遇到的根因是总线电容偏大:走线长、上拉电阻选了 10k,上升沿变缓,从机在高电平采样窗口误判。把上拉改成 4.7k、缩短分支走线后,挂死再没复现。I2C 看着简单,物理层出问题比协议层多得多。
大家在 I2C 挂死时还遇到过哪些奇葩根因?欢迎分享。
一、先看波形,别急着复位
挂死时先用示波器同时看 SCL 和 SDA。如果 SDA 恒低、SCL 为高,大概率是从机在某个字节中间卡住了——最常见的是从机在等主机的 ACK,或者从机内部状态机跑飞。这时直接复位主机没用,SDA 还被从机拉着。
二、九个时钟脉冲解挂
标准解法是主机手动发 9 个 SCL 脉冲,让从机把卡住的字节吐完、释放 SDA。实现时注意两点:一是先把 SCL/SDA 切到 GPIO 模式再发脉冲,硬件 I2C 外设在挂死状态下往往发不出来;二是发完脉冲后检查 SDA 是否回到高电平,再发 STOP 条件。如果 9 个脉冲后 SDA 还低,基本可以判定从机死锁,只能断电重启从机。
三、时钟拉伸要设超时
很多从机在处理数据时会拉低 SCL 做时钟拉伸,正常。问题出在主机没有超时机制:从机一旦异常,主机就一直等下去。我的做法是在驱动层给每次等待加超时(比如 10ms),超时后走解挂流程并记一条错误日志,现场定位能省一半时间。
四、根因多半在时序不在代码
这次遇到的根因是总线电容偏大:走线长、上拉电阻选了 10k,上升沿变缓,从机在高电平采样窗口误判。把上拉改成 4.7k、缩短分支走线后,挂死再没复现。I2C 看着简单,物理层出问题比协议层多得多。
大家在 I2C 挂死时还遇到过哪些奇葩根因?欢迎分享。
