I2C时钟延展

时钟拉伸(Clock stretching)

clock stretching通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行.clock stretching是可选的,实际上大多数从设备不包括SCL驱动,所以它们不能stretch时钟.

 

  某人在调试DS90ub913与DS90ub914通过模拟I2C与DZ60通信时,914可是正常读写,而913不可以正常读写,换作DZ60硬件IIC却可以正常通信,最后在查找913规格书是才发现Clock Stretching问题,实际就是从设备在高速模式下在应答位将clk时钟拉低,通知主设备等待,等从设备释放时钟后,主设备可继续发送命令。

现象(如下图):

       由于在发送读命令之后,即ACk之后,下面从设备需要准备数据时间,(大约10us,一个时钟的时间),此时还在I2C中断中,因此SCLK上是被拉低。由于主设备,并未检查该SCLK信号,导致下一个数据的第一个时钟信号被拉低,而不知道,而当做有效信号采样,结果导致数据采用出错;我们自己的主设备,采用硬件I2C,有判断总线是否占用和超时机制,故没有这个问题。

I2C时钟延展

I2C的时钟可能被从设备拉低,从示波器看好像主少发了时钟(只有8个时钟,实际应该9个,最前面一个被从设备拉低了),实际是从设备拉低,这时候主设备最好检查时钟信号变高后,再发时钟信号脉冲!

原因:通信中,从设备由于某种原因(数据处理或准备)拉低SCL时钟线(此时总线属于被占用状态),而主设备并未判断SCL的是否为高空闲,而继续通信,导致失败 

解决方法:在通信中,要随时检查SCL电平,当它为低的时候,需要超时等待,等它为高时候,再发新的SCL信号

 (即在代码中,主设置SCL为高后,要超时判断SCL是否为高,再发后面的时序)

具体可以在主机应答位检查子程序中进行程序的完善实现Clock Stretching功能;操作如下面红色标注:

//--------------------------------------------------------------------------------------------------  
// 函数名称: check_ACK  
// 函数功能: 主机应答位检查子程序,迫使数据传输过程结束  
//--------------------------------------------------------------------------------------------------  

int8u iic1_check_ACK(void)  
{   
    int8u check;
    int16u ucErrTime=0;
    SDA1 = 1;
    DelayUS(2);
    SCL1 = 1;
 /*****************************************添加部分*********************************************/ 
    DelayUS(10);
    while(0 == SCL1) //用于检测SCL stretch 需要将检测引脚与SCL短接
    {
      ucErrTime++;
      DelayUS(1);
      if(ucErrTime>1000)
      {
        ucErrTime = 0;
        break;
      }
    }
    DelayUS(10);
 /****************************************添加部分**********************************************/
    SDA1_Dir = 0;   //SDA设置为输入端口
    DelayUS(3);     //延时3us
    check = 0;
    if(SDA1 == 1)   // 若SDA1==1 表明非应答
      check = 1;
    SCL1 = 0;
    DelayUS(2);
    SDA1_Dir = 1;
    return check;   
}

全文转自:

https://blog.csdn.net/liuligui5200/article/details/80900951