Felix

技术源于积累,成功始于执着! 个人邮箱:justlxy@mail.dhu.edu.cn QQ:1576109464

【转】I2C 关于时钟拉伸(clock stretch)问题

0
阅读(13721)

原文出处:http://blog.csdn.net/happygaohualei/article/details/52864694


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

链接是IIC标准官网说明http://www.i2c-bus.org/clock-stretching/,贴到这里


Clock Stretching

In an I2C communication, the master device determines the clock speed. Unlike RS232 the I2C bus provides an explicit clock signal which relieves master and slave from synchronizing exactly to a predefined baud rate.

However, there are situations where an I2C slave is not able to co-operate with the clock speed given by the master and needs to slow down a little. This is done by a mechanism referred to as clock stretching.

An I2C slave is allowed to hold down the clock if it needs to reduce the bus speed. The master, on the other hand, is required to read back the clock signal after releasing it to the high state and wait until the line has actually gone high.

Bandwith

Clock stretching sounds a bit odd but is common practice. However, the total bandwidth of the shared bus might be significantly decreased. So, especially for I2C buses shared by multiple devices, it is important to estimate the impacts of clock stretching. So do not make the slowest I2C device dominate your bus performance.

Clock Stretching in High Speed Mode

Clock stretching in High-Speed-Mode is only allowed after the ACK bit (and before the 1st bit of the next byte). Stretching between bits 2-9 is illegal because the edges of these bits are boosted with an additional current source. See I2C specification Rev. 03 chapter 5.3.1 for further details.

而本人具体遇到的情况就是从设备有Clock stretching功能,而之前本人没遇到过,读数经常有错误,还以为是硬件出了问题,实际就是从设备在高速模式下在应答位将clk时钟拉低,通知主设备等待,等从设备释放时钟后,主设备可继续发送命令。


本人遇到的现象及解决过程记录如下:

从设备在应答位把clk拉低,主设备无视继续发送clk,读取数据错误

1.bmp

开始以为从设备硬件错误(不知道部分从设备有clk stretch功能),无奈将应答clk拉宽,等到clk恢复正常电平,见图

2.png

问题是解决了,没有错误数据,但这种强制延时的手段风险还是有的,比如从设备的拉低时间每次不一样,哪次格外长的话,延时多少算合适,未知,仍有出错风险。而且本人还犯了个低级错误,认为IIC有外部上拉,配置成内部上拉也一样,其实不然,这导致stretch时从设备无法把clk电平打到0附近,拉到一个中间电位,这对于检测也是很麻烦的,把MCU配置成开漏输出后,clk中间态电位没有了。

3.bmp

至于SDA还有残留中间电位态,不影响读数据了,暂时没细究,应该还是和配置有关。最后解决方案是外加一个clk检测引脚,专门读取应答位时钟电平,一旦发现拉低,那就等待,这样的话是最保险可靠的方案。上图就是等待的过程。

下面贴出等待的代码,只需添加一个读取即可

u8 IIC_Wait_Ack(void)
{	
    u32 ucErrTime=0;	
    SDA_IN();      //SDA设置为输入  	
    IIC_SDA=1;	
    delay_us(10);    	
    IIC_SCL=1;	
    delay_us(10);		
    
    /*****************************************添加部分**********************************************/	
    while(0 == READ_SCL)//用于检测SCL stretch 需要将检测引脚与SCL短接	
    {		
        ucErrTime++;		
        delay_us(1);		
        if(ucErrTime>1000)		
        {			
            break;		
        }	
    }	
    delay_us(10);		
    
    /*****************************************添加部分**********************************************/	
    ucErrTime = 0; 	
    while(READ_SDA)	
    {		
        ucErrTime++;		
        if(ucErrTime>25000)		
        {			
            IIC_Stop();			
            return 1;		
        }	
    }	
    IIC_SCL=0;//时钟输出0   	
    return 0;  
}