一、前言
对使用 I2C 传输的 RTC 外设 PCA85073,在 I2C 传输过程中若有复位信号输入,则有概率出现 I2C 死锁的状态,即 SCL为高,SDA一直为低的现象。
二、I2C 基本协议
在分析问题出现的原因之前,我们首先需对 I2C 信号进行解释。
首先 SCL 时钟和 SDA 数据线都必须是双向开漏结构,通过总线上的上拉电阻拉到逻辑高电平,当 SCL 与 SDA 为都为高电平时,总线处于空闲状态。
当 SCL 为高,SDA 由高到低的变化为起始信号。
当 SCL 为高,SDA 由低变高为结束信号,停止信号是由主机发出的。
当 SCL 为低时,SDA 才能更改电平状态。
三、I2C “ 挂死 ” 原因解析
由于是开漏的结构,当 I2C SDA 总线上有任何一个器件拉低总线电平的时候,其它任何器件都无法拉高 SDA 总线,如果 SDA 总线上有一个设备不释放总线,那么这条线会一直被这个设备占用,总线上的通信就会暂停。
一般情况下,从设备在数据传输完成后就释放 SDA 线,总线就会恢复空闲状态。但在一些情况下,从设备会一直拉低 SDA 线不释放,这种一般被称为 “I2C 挂死 ”或 “I2C 死锁 ”。
那么哪种情况下 I2C 会挂死呢?
上面说过,只有当 SCL 为低电平时,SDA 才能变化电平状态,当 I2C 在传输过程中被意外中断,总线停留在 SCL 高,SDA 为低的情况,此时总线就会一直被占用,这种情况原因往往是从机拉低 SDA 不释放,因为若是主机拉低 SDA 不释放,我们能够去通过软件控制主机或者通过复位等操作去解决。而若是从机的原因,由于很多时候 I2C 从机不会带复位引脚,所以就算对整个系统进行复位也没办法解除这种状态,只能通过上下电进行恢复,这种操作对于很多时候都是无法接受的,例如需要连续运行进行计时的 RTC 外设。
接下来我们继续分析
首先需要看看哪些情况下 I2C 从机会需要拉低 SDA 线
- 传输数据时,从机发出 ACK 应答
- 读数据,从机传输 0 时会拉低 SDA
那么出现挂死的最常见的情况就是主机在通讯的过程中产生了复位。由于复位动作通常会立刻执行,也就发不出完整的 CLK 了。那么等到主机复位完成回来后,SCL 为高,SDA 被从机拉低。主机无法发起 START 起始条件,不能开始下一次与从机的通讯,这称为 SDA 挂死。
四、问题解决方法
根据 NXP 的 《I2C-bus specification and user manual》最简单的解决办法就是使用 GPIO 模拟 I2C 的连续 9 位时钟或者更多时钟,因为协议规定 I2C 的通常传输的数据宽度为 8 位和 1 位应答位,额外的时钟都会被认为是停止信号,所以不管从机处于何种状态,这种方法都能使从机释放 SDA ,进入正常的传输状态。
五、问题解决实例
在使用 I2C 对实时时钟 PCA85073 读取数据过程,发现传输中间 MCU 出现复位则有概率出现 I2C 挂死的现象,通过 GPIO 模拟时钟信号可以使 PCA85073 释放 SDA 线,后续就能进行正常的数据读取,下图是通过 GPIO 模拟恢复正常传输的时序图。
六、参考文档
[1] NXP《I2C-bus specification and user manual》
登录大大通,了解更多详情,解锁1500+完整应用方案,更有大联大700+FAE在线答疑解惑!