I2C通信之稳定性问题探讨

来源:互联网 发布:淘宝店铺关闭重新开 编辑:程序博客网 时间:2024/04/27 17:06

原文地址::http://blog.csdn.net/millyzb/article/details/6554924



相关网帖

1、I2C总线通信时为什么收不到应答信号----http://bbs.csdn.net/topics/110028389

2、不能说的秘密-I2C的应用----http://userbinglingxiao.blog.163.com/blog/static/8646522201142522049960/

3、硬件I2C通讯注意点  ----http://bokeid.blog.163.com/blog/static/93102786201249111931153/


最近在调试I2C时遇到一些问题,有些经验与大家一同分享,希望大家在遇到类似问题时可以有所帮助。

关键词:I2C  亚稳态 低速信号 去抖动

 

【前奏】
    系统中需要在CPLD中实现I2C SLAVE功能,用于和CPU的I2C接口进行通信,以实现系统GPIO口的扩展。所以,首先根据I2C协议要求,用Verilog HDL编写了一个I2C SLAVE模块和testbench模块,然后在ModelSim Simulation中进行仿真验证,结果满足设计。接着将编译好的.jed文件烧录到CPLD芯片中进行上机测试验证。

    系统Uboot已自带I2C Master功能,故可通过串口操作I2C总线进行读或写操作,在多台DUT进行多次测试验证:读或写的结果都是正确的。同时,用示波器抓取读写时I2C总线上的信号,和结果也是一致。初步说明CPLD代码是OK的。
(注:I2C接口是一种简单、低速串行接口,包括时钟信号SCL和数据信号SDA两根线,使用I2C总线进行通信者分为主机和从机,即Master和Slave。)

 

【问题现象】
     稳定性测试:在Uboot中新增一个i2ctest模块,该模块会对I2C SLAVE(CPLD)不停地进行写、读操作,通过判断每次写进去和读出来的数据是否一致来决定本次通信是否成功,测试数据由0依次递增到255(系统中I2C通信数据宽度为8bit),完成一轮测试后数据又重新从0开始,进行周而复始的操作直至通信出错为止。同时修改更新CPLD中代码,以满足i2ctest要求。

     接着,在DUT上进行I2C稳定性测试,发现测试了几百到上千个循环(每次循环256次写和读操作)左右,I2C通信会出现error。经多次测试发现,出错时error类型不一样,大概为以下几种:
1、读写结果不一致,此时手动敲命令读取时结果又是正确的。
2、Master发出地址+读写命令后,没有收到Slave发出的ACK。
3、Master进行写数据之后,没有收到Slave发出的ACK。
4、Master丢失仲裁权,发生此error后,I2C总线一直处于被占用状态,Master无法进行控制。

 

【问题分析与解决】
     从上述测试结果来看,I2C通信出错时现象并不固定,且出现概率也不一样。于是进行了以下几点测试验证:
1、源码分析与再检查:首先,重新对I2C SLAVE模块代码进行检查,画出状态机的详细状态图,根据I2C通信命令进行检查,状态机跳转均正确。其次,将I2C通信开始/结束产生标识函数采用另外一种方法实现(多次采样判断法),然后测试,还是会出现I2C通信错误,说明和产生开始/结束标志函数关系不大。(题外注:其实一早就认为Slave代码没多大问题,因为对于逻辑器件来说,都是以电平触发来进行状态跳转,如果是设计错误,一次通信都不会成功。但为充分验证代码准确性,还是重新CHECK了所有代码)

 

2、在CPLD代码中添加点灯操作,以判断出错时CPLD跳转的状态,同时用示波器辅助抓取出错时SCL/SDA波形。
     多次测试发现:出错时CPLD状态机跳转并未按指定要求跳转!比如,在接受到Master发出的地址+读写命令后并未产生ACK,状态指示灯表明状态机还在strt_search状态(对接受到的地址+读写命令进行对比,以判断Master选中的Slave地址是否为自己及判断读还是写命令),说明CPLD检测到的通信地址不是CPLD的Slave地址,而示波器上抓取的地址的确为Slave的地址!这说明出错时,CPLD并未能正确捕获到Master发来的数据,有可能是通信时信号被干扰造成其未能正确接收到数据。

 

3、对比测试:将同样的Uboot和CPLD程序烧录到24FE_DEV1(本次测试样机24FE_DEV2的上一版本样机)和24GE_DEV1(同系列GE方案)板子上进行测试,经多次长久测试均未出现错误!这更加说明CPLD代码是没有问题的,问题应该出在24FE_DEV2板子上。

 

4、详细信号测试:采用3.5GHz带宽示波器对三块板子的SCL/SDA信号质量进行测试,发现三者并无多大区别,SCL/SDA的上拉电阻均为4.7K,SCL/SDA信号的上升沿在220ns左右,而下降沿时间则为3~5ns,但发现24FE_DEV2板子的SCL信号上升沿有干扰信号!莫非是这干扰信号造成CPLD对信号的误判?(题外注:I2C通信速率为100KHz,由于是低速信号,硬件调试时并未在意,仅进行一些基本信号测试,验证数据建立/保持时间满足要求。实际上,主观上已经犯了一个错,这次教训告诉我任何一个低速信号都不能马虎对待,对低速信号的边沿变换(特别是要用到边沿触发的信号)一定要用高带宽示波器测量)

 

5、将SCL/SDA上拉电阻电阻调整为1.5K,其他保持不变,进行多次测试(几百万次读、写操作)都没有出现异常。

 

初步分析出I2C通信不稳定的原因如下:
     由于SCL/SDA信号的上升沿在220ns左右(I2C协议中标准模式下为1000ns max),期间处于亚稳态的时间较(0.3VDD~0.7VDD),而如果在这段时间内信号受到干扰,其电平并不处于有效逻辑电平范围内,而且在变化,这就导致与其相连的数字部件CPLD作出不同的判断,有的作为‘1’,有的作为‘0’,也有的进入亚稳态,CPLD会出现逻辑混乱,由此致使I2C SLAVE状态机的乱跳而出现I2C通信错误。分析我们的I2C SLAVE代码都没有做相关预防措施,因此当板子上干扰较大时则会出现I2C通信错误。
     对于24GE_DEV1和24FE_DEV1样机均暂时没有发现I2C通信异常问题,仅在24FE_DEV2板子上出现,说明24FE_DEV2板子上干扰比其他两块要大。在24FE_DEV2板子上将SCL上拉电阻调整为1K~1.5K时,SCL上升沿时间缩短到60~80ns,其处于亚稳态的时间大大减少,因此受干扰的几率也大大降低,所以I2C通信出错的几率大大降低,目前暂无异常发生。但从理论上来讲,该信号在亚稳态时还是可能受到外界干扰的,只是信号处于亚稳态时间变得很短,被干扰到的几率非常低而已。

 

解决方法及验证:
1、调整SCL/SDA上拉电阻为1.2~1.5K(阻值越小,上升时间越短,受干扰几率越低,但根据I2C协议要求,上拉电阻不能取得太小,需大于(VDD-Volmax)/3mA=(3.3V-0.4V)/3mA=0.97K),可有效解决I2C稳定性问题,但存在风险。在样机上将上拉电阻调整为1.2K进行稳定性测试,顺利通过常温72H测试。

2、对SCL/SDA信号进行debounce处理:对SCL/SDA信号进行过滤消抖处理(见下),以让CPLD准确判断SCL/SDA信号变换,可利用快速时钟对SCL/SDA信号进行多次采样以准确判断SCL/SDA的高低电平,由此避开信号的亚稳态阶段,可从根本上解决I2C不稳定问题。在现有I2C SLAVE代码中添加该功能后,在多台样机上进行测试,常温下进行了72H测试未出现error,然后放到老化箱进行高(60°)、低(-10°)、常(25°)温环境下稳定性测试,各进行了24H稳定性测试,均顺利PASS。说明该方法可有效解决I2C稳定性问题!
`define DEB_I2C_LEN 4  // 注:根据各自系统进行设定,相关源码来自开源网站。
// 3.1) OpenCores' I2C Slave,  debounce sda and scl
   always @ (posedge fast_clk or negedge RESETn)
      begin
        if(!RESETn)
           begin
              sdaPipe <= {`DEB_I2C_LEN{1'b1}};
              sdaDeb  <= 1'b1;
              sclPipe <= {`DEB_I2C_LEN{1'b1}};
              sclDeb  <= 1'b1;
           end
        else
           begin
              sdaPipe <= {sdaPipe[`DEB_I2C_LEN-2:0],sda};
              sclPipe <= {sclPipe[`DEB_I2C_LEN-2:0],scl};
              if(&sclPipe[`DEB_I2C_LEN-1:1] == 1'b1)
                     sclDeb <= 1'b1;
              else if(|sclPipe[`DEB_I2C_LEN-1:1] == 1'b0)
                     sclDeb <= 1'b0;
              if(&sdaPipe[`DEB_I2C_LEN-1:1] == 1'b1)
                     sdaDeb <= 1'b1;
              else if(|sdaPipe[`DEB_I2C_LEN-1:1] == 1'b0)
                     sdaDeb <= 1'b0;
           end
     end

当然,如果采用施密特触发器之类的延时判断器件也是可以有效解决该问题的。由于板子上的CPLD管脚并未带有此功能(一些更高级的CPLD都有带有此项功能),故不能进行验证。

 

【总结】
可以说这是一个低速信号引发的“血案”,也是一个“亚稳态”问题的生动实例!即便面对低速信号,我们硬件工程师也不能掉以轻心,其缓慢的上升沿或下降沿(满足其规范要求)造成其处于亚稳态的时间过长,而在这段不定态的时间待得越长就越危险,其受到干扰的几率就越大!如果我们还要以其作为触发信号的话就更危险了,如一定要这么做,记住一定要对其进行debounce处理。debounce处理后信号会有几百ns的时延(可根据各自系统要求,调整代码进行设定),但这对于充裕的建立/保持时间而言,不会对系统通信造成任何影响。(本系统中Tsu和Thd余量都很大,故采用类似方法处理低速信号时,要关注debounce后信号的相关时序参数是否仍满足要求!否则会引入新的问题!)



0 0