在28035芯片与PCF8563 I2C 实时时钟芯片进行通信时,时常出现读出的时间是错误的,而且可能时间数字在乱跳的现象。通过监测I2C总线确定是I2C的数据总线SDA锁死导致通信异常。最后在I2C初始化前加入对SDA数据总线的监测及恢复程序得以解决问题。
问题现象:
在28035芯片与PCF8563 I2C 实时时钟芯片进行通信时,时常出现读出的时间是错误的,而且可能时间数字在乱跳,监测I2C通信的时钟信号和数据信号,正常时如下(黄色为SCL时钟信号、绿色为SDA数据信号)
I2C通信出现异常时,如下图。
可以看到SCL时钟信号常高,SDA数据信号常低。
通过在网上搜索,终于找到了一个很靠谱的分享:I2C从机挂死分析和解决方法 - 简书 (jianshu.com)
作者:熊小宇
链接:https://www.jianshu.com/p/95f53ca2724e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
原因分析:
为什么会出现这种情况呢?
先描述一下I2C最重要的几个特性:
· I2C是由两根线(时钟SCL + 数据SDA)组成的多主多从串行同步通信总线。
· 规范要求接入I2C的器件,SCL时钟和SDA数据线都必须是双向开漏结构的,通过总线上的上拉电阻拉到逻辑高电平。这样的结构可以实现线与(&)功能。
· 一般情况下I2C的SDA只有在SCL为低电平的时候才能改变,为高电平的时候需要保持。对应到芯片设计上则是上升沿采样,下降沿变化。
· 两个例外情况由主机发出的总线起始条件START(SCL为高时SDA由高变低)和停止条件STOP(SCL为高时SDA由低变高)
先来看下哪些情况下I2C从机会需要拉低SDA线。
- 主机向从机写数据或地址时,从机如果发出ACK应答,则会第9个CLK的期间拉低SDA
- 主机读数据的时候,从机会在bit为0时对应的CLK期间拉低SDA
那什么情况I2C从机又可能钳住SDA线呢?我们先来看一个典型的I2C主机发起对某一器件地址读操作,读到的数据为10011000b,MSB在先也就是0x98。在图中地址字节第9个CLK期间从机拉低SDA表示对地址进行应答,在返回的数据字节的第2,3,6,7,8几个CLK器件从机拉低SDA输出逻辑0电平。
根据上面讲的I2C协议SCL为高的时候,SDA电平应保持,而等到SCL为低后(也就是下降沿后)才能发生改变。如果在上面几个CLK的前半个周期SCL拉高后主机不再拉低呢?从机会有什么动作?是的,从机会持续拉低着SDA,直到见到下一个他应该输出高电平的下降沿。
最常见的情况就是主机在通讯的过程中产生了复位。由于复位动作通常会立刻执行,外设状态机都恢复到默认状态,也就发不出完整的CLK了。那么等到主机复位完成回来后,SCL为高,SDA被从机拉低。主机无法发起START起始条件,不能开始下一次与从机的通讯,这称为SDA挂死。
解决方案:
要想办法恢复,我们先得知道从机什么时候会释放SDA。由于刚刚的SCL下降沿没有给出来,恢复总线要做的第一件事情就是在想办法用GPIO在SCL线上模拟一个下降沿,让从机状态机继续走下去。只发一个下降沿并不一定能将SDA释放,因为我们并不清楚当主机复位异常发生时刻从机到底处于图中哪一个状态,所以需要逐个CLK去探测,直到见到SDA被释放了,我们才终止并且发送STOP条件告诉从机通讯结束了。