I2C常见问题

1. I2C传输过程中,SDA异常,被从机一直强制拉低而无法恢复,是什么原因?

  • 问题分析

    在ACK的前半周期SCL被拉高而主机不再拉低SCL(比如在这个期间主机产生了复位、外设被恢复默认状态等,无法正常发出完整的CLK)。

  • 处理方法

    1. 在出现问题后,反初始化I2C。

    2. 将I2C的SCL引脚初始化为普通IO口。

    3. 模拟I2C SCL的翻转,即拉低拉高9个周期,翻转频率不高于正常I2C通讯的频率,可参考下面的Code:

    for(uint8_t i=0; i<9; i++)
    {
      app_io_write_pin(,SET)
      delay_us(1);
      app_io_write_pin(,RESET)
      delay_us(1);
    }

​ 4. 初始化I2C,检查是否正常通信。

2. I2C传输过程中,SCL异常,卡死在低电平,是什么原因?

以下是常见的I2C SCL异常卡死的情况和解决方法:

  • 情况1:

    • Slave必须先调用I2C的Receive函数。如果Master先调用I2C的Transmit函数,相当于Slave还没有准备好,根据I2C协议,此时SCL会被拉低。

  • 解决1:

    • 该原因属于应用错误,需要确保Master Transmit和Slave Receive的时序。

  • 情况2:

    • 总线仲裁。GR5515的I2C接口设计为主从接口,允许多台主机共享一条I2C总线。I2C接口使能后,会持续检测SCL和SDA的电平和跳变。当发现SCL或SDA上出现低电平脉冲(硬件干扰),则认为总线已进入忙碌状态(此干扰相当于一个额外的Master)。此时GR5515认为总线被占用,拒绝向总线发送信号。

  • 解决2:

    • 重新初始化I2C(初始化I2C状态机)或者再发送一个STOP信号(释放总线),可解决该问题。

  • 情况3:

    • 正常传输过程中直接调用I2C的初始化接口。在传输数据过程中,重新调用初始化接口,导致传输中断,但是实际传输并没有被中止,Slave仍在接收数据,将SCL线Hold住,从而下次Master传输数据的时候会发现I2C处于Active的状态,返回Busy,导致SCL被卡在低电平。

  • 解决3:

    • 在调用Init()函数之前先调用deinit()函数,I2C的deinit()针对该问题做过处理,另外在应用过程中应该避免在传输过程中调用初始化接口。

  • 情况4:

    • 正常传输过程中,出现某些异常会导致I2C被卡在低电平(如SCL遭受噪声)。之前有客户遇到在压测时,偶尔会出现I2C被卡在低电平的情况,大概一天压测可以复现一次。

  • 解决4:

    • 通过在异常处理中(判断发送函数返回值为异常),反初始化再初始化GR5515 I2C + 复位从机 + GR5515发送STOP信号,这些步骤的目的都是为了释放I2C总线。当出现未知异常时,建议先将复原方法都加入,然后通过组合的方式来找到合适的恢复方法。