采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?

我们平时在调试I2C的时候可能很少去关注NACK信号,只知道如果Master发送数据,MSB先发,LSB后发,连续发送一个字节(8个bit),之后Slave会回复一个ACK信号,但是有时I2C slave可能会发出NACK信号,下面让我们来看看NACK信号存在的情况。

 

1、从spec下摘取一段:

图片[1]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

图片[2]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

图片[3]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

2、翻译:

        每个字节后会跟随一个ACK信号。ACK bit使得接收者通知发送者已经成功接收数据并准备接收下一个数据。所有的时钟脉冲包括ACK信号对应的时钟脉冲都是由master产生的。

        ACK信号:发送者在ACK时钟脉冲期间释放SDA线,接收者可以将SDA拉低并在时钟信号为高时保持低电平。

        NACK信号:当在第9个时钟脉冲的时候SDA线保持高电平,就被定义为NACK信号。Master要么产生STOP条件来放弃这次传输,或者重复START条件来发起一个新的开始。

 

3、实例:

可以看到如下波形,Master发送01101100(0x6c,MSB先发),在第9个时钟的时候SDA为高电平,表示Slave发送了NACK信号,之后整个I2C通信就结束了。这是一次失败的I2C通信,原因可能是I2C设备那边出的问题,或者访问I2C设备的地址与I2C设备实际的地址不对应,导致没接收到Master的数据从而返回NACK。

图片[4]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

 

下面我拿一个OV8825 Sensor的I2C来说明,

OV8825的Slave Write Address为0x6c,OV8825的ID register Address为0x300a,0x300b,ID register里面存的Value是0x88,0x25

正常的I2C波形如下:

1)设定I2C写的地址:01101100(0x6c)  00110000(0x30) 00001010(0x0a)

Slave Write Address:0x6c,ID register address:0x300a

图片[5]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

 

2)设定I2C读的地址:01101101(0x6d)  10001000(0x88)

Slave Read Address:0x6d,ID register value:0x88

图片[6]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

 

看到这里有点奇怪,i2c write是以ack+stop结束通信,而i2c read是以nack+stop结束通信的,原因如下:

i2c write的时候,master在写完最后一个字节之后slave会回ACK,然后master发送stop信号结束通信

i2c read的时候,master在接收完slave发送的最后一个字节之后会回NAK,因为这个时候master已经接收到足够的字节,NAK告诉slave不要在发送数据了。


I2C总线的挂死

 

由于I2C是线与结构,因此只要总线上任何一个器件拉低了SDA或者SCL,其他器件都无法拉高它们,看到的都是低电平。如果有器件不释放总线,则整个总线上的通讯都会被暂停,我们成为I2C bus hangs:I2C总线挂死

 

 

先来看下哪些情况下I2C从机会需要拉低SDA线。

  1. 主机向从机写数据或地址时,从机如果发出ACK应答,则会第9个CLK的期间拉低SDA

  2. 主机读数据的时候,从机会在bit为0时对应的CLK期间拉低SDA

那什么情况I2C从机又可能钳住SDA线呢?我们先来看一个典型的I2C主机发起对某一器件地址读操作,读到的数据为10011000b,MSB在先也就是0x98。在图中地址字节第9个CLK期间从机拉低SDA表示对地址进行应答,在返回的数据字节的第2,3,6,7,8几个CLK器件从机拉低SDA输出逻辑0电平。

图片[7]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

 

 

根据上面讲的I2C协议SCL为高的时候,SDA电平应保持,而等到SCL为低后(也就是下降沿后)才能发生改变。如果在上面几个CLK的前半个周期SCL拉高后主机不再拉低呢?从机会有什么动作?YES,从机会持续拉低着SDA,直到见到下一个他应该输出高电平的下降沿。

最常见的情况就是主机在通讯的过程中产生了复位。由于复位动作通常会立刻执行,外设状态机都恢复到默认状态,也就发不出完整的CLK了。那么等到主机复位完成回来后,SCL为高,SDA被从机拉低。主机无法发起START起始条件,不能开始下一次与从机的通讯,这称为SDA挂死。

要想办法恢复,我们先得知道从机什么时候会释放SDA。由于刚刚的SCL下降沿没有给出来,恢复总线要做的第一件事情就是在想办法用GPIO在SCL线上模拟一个下降沿,让从机状态机继续走下去。只发一个下降沿并不一定能将SDA释放,因为我们并不清楚当主机复位异常发生时刻从机到底处于图中哪一个状态,所以需要逐个CLK去探测,直到见到SDA被释放了,我们才终止并且发送STOP条件告诉从机这次坑爹的通讯结束了。

 

 

如果在地址字节第9个CLK拉高后主机复位。在模拟的第一个时钟低电平期间就可以看到SDA的释放,随后主机先拉低SDA,再模拟一个STOP结束条件。

图片[8]-采用硬件I2C读取E2PROM,单片机复位发生死锁怎么办?-Anlogic-安路社区-FPGA CPLD-ChipDebug

 

请登录后发表评论

    没有回复内容