I2C 死锁了?SDA 一直被拉低?别复位 MCU,试试这 3 种救活方法
摘要:I2C 总线突然挂死,SDA 线被拉低,无论怎么复位 MCU 都没用?这不是芯片坏了,而是 I2C 从机的“时钟延展”机制卡死了。本文给出 3 种硬件级的自救方案。
一、问题描述(现象)
**系统运行几天后,I2C 通讯突然中断;
示波器一看,SDA 一直为低电平,SCL 为高;
复位 MCU、重新上电都没用,只有拔掉从机电源才行。**
很多工程师的第一反应是:
-
从机芯片坏了?
-
程序跑飞了?
-
换一块板子试试?
二、原理分析(为什么会卡死?)
1. 物理模型
I2C 从机在接收数据时,如果处理不过来,会主动拉低 SCL(时钟延展)。
正常: SCL ___|‾‾‾|___|‾‾‾|___
卡死: SCL ___|‾‾‾|________ (一直等 ACK)
SDA ____________________ (被从机拉低)
2. 核心参数
-
Clock Stretching(时钟延展):从机拉低 SCL 等待主机。
-
Bus Free Time:总线空闲时间。
3. 反直觉真相
死锁通常发生在“异常终止”时。
比如:
-
MCU 在发送过程中断电。
-
程序跑飞,I2C 状态机停在中间。
-
从机正在等 ACK,主机却没了。
结果: 从机还在等时钟,主机已经不发了,SDA 被永久拉低。
三、工程级解决方案(按推荐顺序)
方案 1:硬件自愈(最推荐,量产必加)
在 SDA/SCL 线上加一个复位电路。
电路设计:
SDA -> [100Ω] -> [MOSFET Gate]
SCL -> [100Ω] -> [MOSFET Gate]
|
[N-MOS]
|
GND
控制逻辑:
-
检测到 I2C 超时(如 100ms 无响应)。
-
MCU 拉高 MOS 管 Gate,强制将 SDA/SCL 拉低。
-
延时 10us,释放。
-
重新初始化 I2C 外设。
方案 2:GPIO 位拆(软件急救)
如果硬件改不了,用 GPIO 手动解锁。
// 1. 关闭 I2C 外设
__HAL_I2C_DISABLE(&hi2c1);
// 2. 配置 SCL/SDA 为 GPIO 输出
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Pin = SCL_PIN | SDA_PIN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// 3. 模拟 9 个时钟脉冲(I2C 规范推荐)
for (int i = 0; i < 9; i++) {
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_PIN, GPIO_PIN_RESET);
delay_us(5);
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_PIN, GPIO_PIN_SET);
delay_us(5);
}
// 4. 发送 STOP 条件
HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(SCL_GPIO_Port, SCL_PIN, GPIO_PIN_SET);
delay_us(5);
HAL_GPIO_WritePin(SDA_GPIO_Port, SDA_PIN, GPIO_PIN_SET);
// 5. 恢复 I2C 外设
HAL_I2C_Init(&hi2c1);
方案 3:外部复位(最稳)
直接从机 RESET 引脚。
-
如果 I2C 从机有 RESET 引脚,直接拉低 10us。
-
这是物理层面的强制复位,100% 有效。
四、选型避坑建议
-
不要迷信软件复位:
HAL_I2C_MspInit()在 SDA 被拉低时通常无效。 -
上拉电阻:死锁后,上拉电阻无法把 SDA 拉高,必须从机释放。
-
超时机制:软件必须检测 I2C 超时,不能无限等待。
五、总结 Checklist
-
[ ] 是否遇到过“拔电才能恢复”的 I2C 故障?
-
[ ] 硬件上是否预留了强制拉低 SDA/SCL 的 MOS 管?
-
[ ] 软件是否有 I2C 超时检测与 GPIO 位拆逻辑?
-
[ ] 从机是否有 RESET 引脚可用?
六、写在最后(关注我,少走弯路)
我是 gqqsherry,一个拒绝调包、专注底层逻辑的嵌入式工程师。
I2C 死锁是工业现场最常见的“幽灵故障”,往往几个月才出现一次,一旦出问题就是致命的。
关注我的专栏《嵌入式底层避坑指南》,我会持续更新 UART、SPI、I2C 等外设的真实调试案例和量产级解决方案。
👉 下一篇预告:《I2C 地址扫描不到?别只怪从机,看看这 2 个隐藏地址位》
References
-
NXP UM10204 – I2C-bus specification and user manual
-
TI Application Report SLVA704 – I2C Bus Fault Recovery
如果你在项目中遇到过 I2C 死锁,欢迎在评论区分享你的解决经验。
原创文章,转载请注明出处。
更多推荐
所有评论(0)