【前言】
I2C 卡死几乎是用过硬件 I2C 的工程师都遇到过的问题:从机在某个时刻不再响应,SCL 一直保持低电平,总线彻底挂住。极海 APM32 系列的硬件 I2C 也逃不开这个经典场景。本文把原因和解决思路整理一下。
一、卡死的三种典型形态
1. 主机发了起始条件后一直等不到 ACK,状态机停在某个中间状态。
2. 从机把 SDA 拉低不放,主机发多少时钟都不释放。
3. 总线电平正常但状态寄存器一直显示忙,实际通信已经失败。
二、为什么会卡死
1. 主机读数据时提前发了停止条件,从机仍在驱动数据线,双方状态不同步。
2. 中断里没有及时读取数据寄存器,导致后续时钟被硬件拉低。
3. 从机掉电或复位时正好在通信中间,SDA 被钳在低电平。
4. 上拉电阻阻值过大,边沿太慢,在高速率下被误判。
三、硬件复位手段(必加)
在主循环里加一个超时检测,如果一次传输超过预定时间还没完成,就执行总线复位:
1. 关闭 I2C 外设,把它配置成普通 GPIO。
2. 在 SCL 上手动发 9 个时钟脉冲,让从机把剩余的数据位移完并释放 SDA。
3. 手动产生一个停止条件:SCL 为高时把 SDA 从低拉到高。
4. 重新初始化 I2C 外设。
这套流程能解决绝大多数从机侧卡死,实测非常有效。
四、软件层面的改进
1. 用状态机替代阻塞式等待,每一步都带超时返回,杜绝死等。
2. 关键时序不要放在高优先级中断里,避免影响其它实时任务。
3. 每次传输完成后读一下状态寄存器,确认没有异常标志残留。
4. 如果从机支持,尽量用带 CRC 的协议,把错误检测交给协议层。
五、关于要不要换成模拟 I2C
模拟 I2C 的好处是时序完全可控、出问题容易定位,坏处是占用 CPU 并且速率上不去。对于速率要求不高的传感器读写,模拟 I2C 综合体验往往更好;对于需要高速率的场合,还是建议用硬件 I2C 并配好上面说的复位机制。
以上是 APM32 系列上处理 I2C 卡死问题的经验,供大家参考。 |
|