如无特殊说明,下文中主设备和MCU概念可以互换。
I2C是一种比较常用的串行通信协议,常见于MCU和一些外设的通信中,比如MCU和外部EEPROM、传感器、LED驱动IC等的通信都会用到I2C通信。因此作为一名MCU软件工程师,需要掌握I2C的驱动配置以及应用软件的编写。
在实际使用过程中,I2C比较容易出现的一个问题就是死锁,今天就来介绍一下I2C死锁产生的原因以及如何解决死锁问题。
在介绍I2C死锁产生的原因之前,先简单介绍一下I2C的通信协议。I2C由串行数据线SDA和串行时钟线SCL组成,SDA和SCL在空闲时都处于高电平状态。SCL由主设备来产生,SDA上既可以传输主设备发给从设备的数据,也可以传输从设备发给主设备的数据。比如MCU配置传感器的寄存器时,SDA的数据由MCU传向从设备;传感器发送数据给MCU时,SDA的数据由传感器发送给MCU。从设备在接收完一个字节的数据后需要回复给主设备一个ACK信号,此时从设备会把SDA拉低,等待主设备控制SCL从高到低取走ACK位。
死锁的产生查痾常见的有两种情况:一种是从设备在回复ACK时主设备异常复位;另一种是从设备在回复数据位是0的时候主设备异常复位。两种情况的相同点都是主设备异常复位时SDA处于被从设备拉低状态,而主设备复位后SCL处于高电平状态(空闲状态)。此时从设备会等待主设备拉低SCL取走ACK或者数据位,而主设备会等待从设备释放SDA线。主设备和从设备互相等待,隔空对望,进入死锁状态。
解决死锁问题的几种常见方法:
1.主设备在检测到SDA被拉低超过一段时间后,主动复位从设备从而使之释放SDA。这种方法的前提是从设备有复位引脚,MCU可以控制从设备的复位引脚使之复位。
2.主设备在检测到SDA被拉低超过一段时间后,推送9个Clock到时钟总线上,取走从设备的ACK位从而使从设备释放SDA为高电平。
3.在主从设备之间串联一个I2C缓冲器,该缓冲器可以自动检测死锁状态。当检测到死锁时会主动断开与主设备的连接,并发送9个Clock给从设备,等从设备释放SDA线后从新与主设备建立连接。
I2C的死锁问题无法从根本上避免,除了MCU的异常复位导致I2C死锁,从设备在正常通信过程中也有可能异常拉低SDA导致死锁。所以软件在设计时要考虑当死锁发生时要能够从死锁中恢复,使得I2C通信可以继续进行。
https://zhuanlan.zhihu.com/p/218202643