经过一个多星期的折腾终于搞懂的TWI的协议。刚开始看的时候感觉这是个非常强大的东西,看到后面越感觉到Atmega这么好的单片机这么会存在一个很不相称的TWI,太不简洁了。设置了过多的状态,其实很多都是没必要的。整个通信协议其实就是IIC,只是TWI增加了很多状态显得是画蛇添足。 USART、SPI、IIC这三种常用的通信接口个人认为个有优缺点,需要针对不同的需求选择。IIC和其他两种相比最大的不同点应该是IIC的主机仲裁机制,有了主机仲裁机制的存在就使能IIC总线上的每个设备都可以经过仲裁成为主机。 1工作原理 1.1电气连接 TWI使用两根总线,一根用于传输数据(SDA),另一根用于传输时钟(SCL)。由于总线上可以挂载多个设备,所以设备的TWI总线接口不可能使用推挽输出,但是可以使用内部上拉电阻,在挂载的设备数量过多时等效上拉电阻为所有设备上拉电阻的并联值,可能会非常小,为此还是建议不要把相应的IO上拉电阻打开,使用外部上拉更妥(其实如果只用内部上拉电阻,在传输数据时很容易出错,因为内部上拉电阻太大了)。 总线上不允许出现没有上电的AVR设备。因为在单片机没有上电时IO口之间存在比较小的导通电阻,相当于在SDA和SCL之间接了一个电阻,这会造成传输的数据出错。同时手册中还规定了通信总线间的最大分布电容。 (图一)TWI总线的连接 1.2数据格式 TWI 总线上数据位的传送与时钟脉冲同步。时钟线为高时,数据线电压必须保持稳定(应该是下降沿移位,高电平采样),除非在启动与停止的状态下。 和USART一样,TWI也没有使用使能端口,所以数据传输时需要一个起始信号和一个停止信号。TWI的起始信号(START)和停止信号(STOP)并不是用数据”1”和”0”表示,START的产生是在SCL高电平时,SDA上输出一个下降沿。STOP的产生是在SCL高电平时,SDA上输出一个上升沿。在START 与STOP 状态之间发出的START 状态,这被称为REPEATED START 状态,如下图所示: (图二)START/STOP
从机时刻会监视总线的变化,如果有出现START则开始接收地址,如果出现的是STOP则切换到未寻址状态。从机是如果检测START和STOP的呢?根据这两个信号的特点自己推测了下面的逻辑方框图:
(图三)START/STOP检测逻辑方框图 图中的传输门是高电平导通,即SCL为”1”时传输门导通,SDA的跳变就会被边沿检测器检测到,再传到控制单元。 所有在TWI 总线上传送的数据包均为 9 位(第9位是由接收设备发出的应答),在第9个时钟周期内通过拉低SDA作出应答。若接收设备有其它原因无法响应,则应该保持SDA 为高。 开始通信时,主机在总线上产生一个START,接着是从机地址数据包(7 位地址位、1 位READ/WRITE 控制位。如果READ/WRITE 为1,则执行读操作,否则执行写操作)从机被寻址后在第9个时钟周期通过拉低SDA作出应答,若该从机忙或有其它原因无法响应主机,则应该在应答周期保持SDA为高,主机可以发出STOP 状态或REPEATED START 状态重新开始发送。 地址字节的MSB 首先被发送。从机地址由设计者自由分配,但需要保留地址0000 000作为广播地址。当发送广播呼叫时,所有的从机应在应答周期通过拉低SDA作出应答。当主机需要发送相同的信息给多个从机时可以使用广播功能。注意在广播时发送Read 位没有意义,因为如果几个从机发送不同的数据会带来总线冲突。所有形如1111 xxx 格式的地址都需要保留,以便将来使用。 (图四)典型的数据传送
1.3总裁机制 总线上可能会出现多个主机同时传输数据,当一个主机要产生”1”,而另一个主机要产生”0”,就出现了错误,所有需要一个总裁机制来保证从机接收到的数据是正确的。 多个主机传输数据第一个要解决的问题就是统一时钟,因为每个主机使用的时钟不一定是相同的。TWI协议使用了一种称为“时钟与”的方式解决时钟不统一的问题。有种叫做“两人三足”的游戏可以解释“时钟与”的原理。游戏是一个人的左脚与另一个人的右脚绑在一起走路,假设这两个人就是总线上的两个主机,两人原来的走路速度就是两个主机的时钟频率,绑在一起的脚就是两个时钟相与后的共用时钟。脚抬起为时钟高电平,脚踏地为时钟低电平。开始走路,当脚抬起时其中一个人要塌下,则都塌下了。在塌下时只有两个都打算抬起才能抬起(因为塌下省力,抬起费力)。所以两人的速度只能一致了。为了便于理解自己根据“时钟与”的实现原理绘制了下面的逻辑方框图。 (图五)时钟结构逻辑方框图
图四中预分频器的复位端是高电平复位,复位状态下输出是低电平,MOS管高电平导通低电平截止。假设现在预分频器输出的是低电平,MOS截止,SCL为”1”,现在有另一个设备把SCL端拉低,则带非门输入的与门输出为”1”,使预分频处于复位状态,MOS管继续处于截止状态。当SCL被释放后,预分频器从复位状态恢复,开始输出时钟。 TWI的时钟输出这种可以同步低电平的特性还用于主机与从机的通信握手。例如从机接收到数据后TWINT标志位置位,从机把SCL拉低,这样从机就有时间处理完数据再清零TWINT释放SCL准备接收下一个数据。 主机要产生START前需要等待总线空闲(SCL、SDA都为高电平),产生START后开始传输数据(这里把地址也看成是数据的一种),这时候如果有其他主机也加入就会产生仲裁过程。仲裁过程有可能发生在整个数据的传输过程中的任何时刻。仲裁是由参与的主机自觉完成的,也就是说只有失去仲裁的主机才知道总线发生了仲裁,其他没有被淘汰的主机是无法检测到总线是否有仲裁,从机不参与仲裁。判断自己是否失去仲裁非常简单,输出数据”1”时,如果SDA被其他主机拉低则自己失去仲裁。在数据的传输整个过程中都会检查自己是否会失去仲裁。检测的内部逻辑方框图如下: (图六)仲裁检测结构逻辑方框图 与门输出高电平则触发仲裁判定,判定自己已经失去仲裁。从图上可以看出,如果内部数据输出的是”1”,则MOS管截止,SDA为高,这时其他主机把SDA拉低,与门输出高电平触发仲裁判定,修改TWI状态为仲裁失败。 会发生仲裁的情况有:多个主机对同一个从机进行不同的数据或方向的访问时,会在READ/WRITE位或数据间发生仲裁。多个主机访问不同主机时,会在地址(SLA)发生仲裁。以上两种情况都是假设主机是同时发出START的,但是实际情况并非如此。例如一个主机在与从机传输数据时,恰好有另一个主机也要传输数据,则它要等待总线空闲才能启动信号,如果总线上SDA传输的是”1”,时钟有是高电平,就会认为总线空闲。于是另一个主机就在总线上产生了一个START,原来的主机检查到SDA被拉低就认为自己仲裁失败,原来接收数据的从机检查到START就会转到未寻址模式。 2 AVR-TWI应注意的几个问题 2.1主机与从机 刚学习TWI时可,能是收到SPI的影响,看到有主机和从机就去查看寄存器是怎么把设备设置为主机或者从机的,找了半天没有看到一个具体的主从模式标志位。随着学习的深入才知道原来TWI不主动发送数据时就是处于接收状态也就是所谓的从机模式,主动发送数据时就是所谓的主机模式。所以根本就没有一个“静态”的主机。就如同电话,可以主动联系他人也可以由他人打进来。个人感觉把主机模式翻译成主动通信,从机模式翻译成被动通信。TWI可以使用主动通信也可以被动通信,主动通信需要对方的地址(如同电话号码)。这样就容易理解多了。 2.2控制寄存器TWCR TWINT:中断标志。不能硬件清零,需要软件清零。特别注意,只有在TWINT置位才能写数据寄存器TWDR。从机模式下,TWINT置位时会把SCL拉低,停止总线数据的传输,清零TWINT后才重新释放总线。如果允许TWI中断且开启总中断,则必须要清零TWINT才能退出中断函数。调试从机时发现,在退出中断函数前没有清零TWINT,会使已经被寻址的从机切换到未寻址状态。 TWI:应答使能。主从的接收模式下置位时,接收到数据会返回一个应答。从机发送模式下清零时主机将接收到的数据位全是”1”。在从机模式下清零还可以不允许主机寻址自己。 START:起始信号标志位。置位后清零TWINT则在总线上产生一个START信号。发送完成会置位TWINT。该位需要手动清零。 STOP:停止信号标志位。置位后清零TWINT则在总线上产生一个STOP信号。发送完成不好置位TWINT,且不需要手动清零。 2.3 TWI状态 TWI的状态过于细致,这成了它的缺点。在写程序时就要用一个很大的switch来处理这些状态,每次执行要完成的判断会很多。如果是用中断服务函数来处理不仅函数显得很长,而且执行时间也不断(主要在判断上)。手册中对每个状态的处理有详细说明,这里主要说明几个不太容易理解的状态。 0x68、0x78、0xB0这三个状态都是表示仲裁失败的,且又是在从机的状态表格中出现。如果是第一次看学习TWI估计会一下子搞不清楚为什么从机能检测到仲裁失败?认真看才发现这三个状态是主机发生仲裁失败,转为从机后,又恰好是获得总线控制权的主机要寻址的从机,从机接收了地址后的状态。 0xA0这个状态是在从机接收的状态表中出现的,说明是在从机工作时接收到STOP或重复START。没有说一定是从机接收模式,所以在从机发送模式也会发生。从手册P157中的TWINT置位出现的情况也可看出不限于从机接收模式。 0x0状态是由非法的START或STOP引起的。这个状态只会在主机模式中发生。在手册P153中有对传输数据的要求是:“发送主要有START状态、SLA+R/W、至少一个数据包及STOP状态组成。只有START与STOP状态的空信息是非法的。”所以在主机模式下发送一个START接着发送STOP或在发送完SLA+R/W接着发送STOP等都会发生0x0状态。在发送非法START/STOP时TWI并不会真的发送到总线中去,只会在内部引起TWINT置位。在发生0x0状态时手册上有明确说明,要求清零TWINT和置位STOP。
|