TCS3JB/T 4725-92使用I2C通信发送地址之后直接NACK

I2C是由Philips公司发明的一种串行数据通信协议仅使用两根信号线:SerialClock(简称SCL)和SerialData(简称SDA)。I2C是总线结构1个Master,1个或多个Slave各Slave设备以7位地址区分,地址后面再跟1位读写位表示读(=1)或者写(=0),所以我们有时也可看到8位形式的设备地址此时每个设备有读、写两个地址,高7位地址其实是相同的

数据位:当SCL由0向1跳变时,由发送方控制SDA此时SDA为有效数据,不可随意改变SDA;
当SCL保持为0时SDA上的数据可随意改变;
地址位:定义同数据位,但只由Master发给Slave;
应答位(ACK):当发送方传送完8位时发送方释放SDA,由接收方控制SDA且SDA=0;
否应答位(NACK):当发送方传送完8位时,发送方释放SDA由接收方控制SDA,苴SDA=1

当数据为单字节传送时,格式为:
开始位8位地址位(含1位读写位),应答8位数据,应答停止位。
当数据为一串字节传送时格式为:
开始位,8位地址位(含1位读写位)应答,8位数据应答,8位数据应答,……8位数据,应答停止位。

1SCL一直由Master控制,SDA依照数據传送的方向读数据时由Slave控制SDA,写数据时由Master控制SDA当8位数据传送完毕之后,应答位或者否应答位的SDA控制权与数据位传送时相反
2,开始位“Start”和停止位“Stop”只能由Master来发出。
3地址的8位传送完毕后,成功配置地址的Slave设备必须发送“ACK”否则否则一定时间之后Master视为超时,将放弃数据传送发送“Stop”。
4当写数据的时候,Master每发送完8个数据位Slave设备如果还有空间接受下一个字节应该回答“ACK”,Slave设备如果没有空间接受更多的字节应该回答“NACK”Master当收到“NACK”或者一定时间之后没收到任何数据将视为超时,此时Master放弃数据传送发送“Stop”。
5当读数据的時候,Slave设备每发送完8个数据位如果Master希望继续读下一个字节,Master应该回答“ACK”以提示Slave准备下一个数据如果Master不希望读取更多字节,Master应该回答“NACK”以提示Slave设备准备接收Stop信号
6,当Master速度过快Slave端来不及处理时Slave设备可以拉低SCL不放(SCL=0将发生“线与”)以阻止Master发送更多的数据。此时Master将视凊况减慢或结束数据传送

在实际应用中,并没有强制规定数据接收方必须对于发送的8位数据做出回应尤其是在Master和Slave端都是用GPIO软件模拟的方法来实现的情况下,编程者可以事先约定数据传送的长度slave不检查NACK,有时可以起到减少系统开销的效果但是如果slave方是硬件i2c要求一定要標准的NACK,master方是GPIO软件模拟i2c并没有正确的发送NACK就会出现“slave收不到stop”导致i2c挂死。

 在正常情况下I2C总线协议能够保证总线正常的读写操作。但是当I2C主设备异常复位时(看门狗动作,板上电源异常导致复位芯片动作手动按钮复位等等)有可能导致I2C总线死锁产生。下面详细说明一下总線死锁产生的原因

在I2C主设备进行读写操作的过程中.主设备在开始信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平在这个时候,从設备输出应答信号将SDA信号拉为低电平。如果这个时候主设备异常复位SCL就会被释放为高电平。此时如果从设备没有复位,就会继续I2C的應答将SDA一直拉为低电平,直到SCL变为低电平才会结束应答信号。而对于I2C主设备来说.复位后检测SCL和SDA信号如果发现SDA信号为低电平,则会认為I2C总线被占用会一直等待SCL和SDA信号变为高电平。这样I2C主设备等待从设备释放SDA信号,而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号两者相互等待,I2C总线进人一种死锁状态同样,当I2C进行读操作I2C从设备应答后输出数据,如果在这个时刻I2C主设备异常复位而此时I2C从設备输出的数据位正好为0也会导致I2C总线进入死锁状态。

每次I2C主设备复位后如果检测到SDA数据线被拉低,则控制I2C中的SCL时钟线产生9个时钟脉沖(针对8位数据的情况“9个clk可以激活”的方法来自NXP的文档,NXP(Philips)作为I2C总线的鼻祖这样的说法是可信的),这样I2C从设备就可以完成被挂起的讀操作从死锁状态中恢复过来。

        这种方法有很大的局限性因为大部分主设备的I2C模块由内置的硬件电路来实现,软件并不能够直接控制SCL信号模拟产生需要时钟脉冲

        如果是GPIO模拟I2C总线实现,那么在I2C操作之前加入I2C总线状态检测 I2C_Probe ,如果总线被占用则可尝试恢复总线,待总线釋放后再进行操作。要保证I2C操作最小单元的完整性不被其他事件(中断、高优先级线程,等)打断

  (5)在I2C总线上增加一个额外的总线恢複设备。这个设备监视I2C总线当设备检测到SDA信号被拉低超过指定时间时,就在SCL总线上产生9个时钟脉冲使I2C从设备完成读操作,从死锁状态仩恢复出来总线恢复设备需要有具有编程功能,一般可以用单片机或CPLD实现这一功能

(6)在I2C上串人一个具有死锁恢复的I2C缓冲器,如Linear公司的LTC4307是┅个双向的I2C总线缓冲器并且具有I2C总线死锁恢复的功能。LTC4307总线输入侧连接主设备总线输出侧连接所有从设备。当LTC4307检测到输出侧SDA或SCL信号被拉低30ms时就自动断开I2C总线输入侧与输出侧的连接.并且在输出侧SCL信号上产生16个时钟脉冲来释放总线。当总线成功恢复后LTC4307会再次连接输入输絀侧,使总线能够正常工作

}

        一般是用于连接微控制器及其外圍设备由两根线组成,分别是:时钟线SDA和数据线SCL ,在CPU和被控IC或是IC与IC之间双向传递高速的IC总线一般可以达到400kbps以上。

        事实上I2C总线通信实际仩是一种通信协议,通过一种已经制定好的约束关系在两个储存器之间来回的传输需要的数据那么这种协议或者说这种约束的具体内容昰怎么样的呢,在有了数据线SCL和时钟线SCL之后是如何进行数据的传输的呢?

       我们知道有时钟线也就相当于有了总指挥而数据线是需要在时钟線处于不同的电平的时候做出不同的反应来表示几种数据传输中需要的标志,比如说传输一个数据,什么时候开始呢什么时候结束呢,数据来了如何告诉对方做好准备呢?这些都是传输数据时需要明确规定的信号下面是这几种信号的简单介绍。

               (1) 空闲状态:当没囿数据需要传输的时候也就是说这个时候I2C总线是处于空闲的,那就让它休息就好不需要工作这时,SDA和SCL两根信号线同时处于高电平就规萣为总线的空闲状态

 (4)应答信号:发送器每发送一个字节,就会在时钟脉冲的第九个脉冲期间释放数据线SDA然后由接收器反馈一个应答信号给发送器,如果这个应答信号为低电平就为有效应答位(ACK简称应答位),表示接收器已经成功的接受了了这个字节;如果这个应答信号为高电平就为非应答位(NACK),一般表示接收器没有成功接受这个字节具体来说,对于反馈回来的有效应答位(ACK)的要求是:接收器在第九个时钟脉冲之前的低电平期间将SDA拉低并且确保在该时钟的高电平期间为稳定的低电平。   如果接收器是主控器则在他接受的朂后一个字节之后,发送一个NACK信号来通知被控发送器结束数据发送,并释放SDA线以便主控接收器发送一个停止信号P。

 (5)数据有效性:茬I2C总线进行数据传输时在时钟信号为高电平的期间,数据线上的数据必须保持稳定也就是说,比如第一个时钟脉冲时要传输的数据时1那么在第一个时钟高电平到来之前以及过去之后的这个时间内,数据线上的1(也就是高电平)都要保持为高只有在时钟线为低电平期間,数据线上的高电平或低电平才允许变化

               (6)数据的传输:在I2C总线上传送的每一位数据都有一个时钟脉冲相对应,即在SCL串行时钟的配匼下在SDA上逐位的串行传送每一位数据,数据位的传输是边沿触发

{ 模式是推挽输出,当主控IC是作为接受器是应该设置为浮空输入

void IIC_Start(void)  // (2)函數作用已经标出来了产生起始信号,具体步骤看函数
 

void IIC_Stop(void) // (3)函数作用已经标出来了产生停止信号,具体步骤看函数
 

//等待应答信号到来 //(4)这是当传输一个字节之后等待应答信号ACK的到来
//返回值: 1接收应答失败
// 0,接收应答成功
while(READ_SDA)  这里的while循环中是在等待SDA的返回信号如果是0就跳絀循环,返回为0属于有效应答
{ ucErrTime++; 如果等待中一直是1,就返回为1位无效应答并且产生停止信号。
 

 

//不产生 ACK 应答  (6)不产生应答
 

//(7)IIC 发送一个芓节
 

 
以上部分是参考原子的程序上面列出了在使用i2c通信所用到的各个函数,包括产生起始信号停止信号,应答不应答,发送一个字節和读取一个字节等函数的封装使用方便!


下面开始正式介绍i2c通信的具体实践内容:


理解:首先无论我们是要读取还是写入数据,我们嘟需指定地址然后在这个地址里面读取或者写入数据。


写入数据的具体过程遵从I2C的通信协议前面已经介绍过就不再重复说明了。





























以上昰对上面时序图的解读也是主控芯片(stm32f103)对被控芯片写入数据时的具体步骤(这里的被控芯片是以24C02为例)。




    这里就不对代码展开详细的解释了代码的过程是依据上述24C02的写时序来的。如果有疑问的地方可以评论区留言,共同交流学习
 
总结:至此,I2C的初探学便结束了總的来说,这种通信方式还是相对比较简单的也只占用了两个IO口。实际的使用效果如何目前还不敢妄下定论这只是一种在两个IC之间通荇的手段,依据其规定好的方式对数据进行传输。它是一个完整的数据传输过程有开始,传输 应答,结束等不同的信号进行指示鉯后还将学到SPI,485CAN 等通信方式,届时再做专门的比较和学习
本篇博客其实是本人在学习I2c中的理解和笔记。如此叙述出来一是加深自己對I2C通信的理解,二是也希望与各位同学交流共同进步。当然如果还能对大家有所帮助那更是意外收获了本篇博客也会在以后深入学习Φ进行补充和加深。本人也只是初学如果文中有不当或错误的地方,还请指正谢谢!

}

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

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

Simulation中进行仿真验证,结果满足设计接著将编译好的.jed文件烧录到CPLD芯片中进行上机测试验证。

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

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了所有代码)

多次测试发现:出错时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.7KSCL/SDA信号嘚上升沿在220ns左右,而下降沿时间则为3~5ns但发现24FE_DEV2板子的SCL信号上升沿有干扰信号!莫非是这干扰信号造成CPLD对信号的误判?(题外注:I2C通信速率為100KHz由于是低速信号,硬件调试时并未在意仅进行一些基本信号测试,验证数据建立/保持时间满足要求实际上,主观上已经犯了一个錯这次教训告诉我任何一个低速信号都不能马虎对待,对低速信号的边沿变换(特别是要用到边沿触发的信号)一定要用高带宽示波器測量)

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

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

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

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

}

我要回帖

更多关于 TCS34725 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信