FPDLINK是TI设计的高速差分传输总线,主要用于传输图像数据,比如camera和显示数据。而且该标准还在不断的演进,从最初的一对线传输720P@60fps图像,到目前可以传输1080P@60fps,后续的芯片还可以支持更高的图像分辨率。传输距离也很远,能达到20米左右,非常适合汽车应用。
FPDLINK在传输的过程中有高速的前向通道,用于传输高速的图像数据和小部分的控制数据。也有速度相对较低的后向通道,用于传输反向的控制信息。前后向通信构成双向的控制通道,从而有了本文中将要讨论的FPDLINK中I2C的巧妙设计问题。
FPDLINK在使用中都是一个serializer和deserializer配对使用,CPU可以连接到serializer,也可以连接到deserializer,取决于具体的应用。比如,在camera应用中,camera sensor连接到serializer,将数据发送到deserializer,cpu则接收从deserializer发送过来的数据。在显示应用中,CPU则将数据发送给serializer,deserializer接收serializer的数据再传送给LCD屏进行显示。
CPU的i2c则可以连接到serializer或者deserializer的i2c。以下我们以上图的camera为例来讲解FPDLINK的i2c设计
FPDLINK芯片接收CPU发送过来的I2C信息,将I2C信息通过FPDLINK传送到另外一端。我们知道,在i2c协议中,SDA是通过SCL来进行同步的。在一般应用中,在SCL的上升沿锁存数据,这就需要master或slave需要在SCL下降沿准备好数据。但是在FPDLINK里面,由于FPDLINK传输是有时间的,当master发送数据时不会有问题,最多slave收到的数比master发送的晚一些clock。但是slave往master回复的信息就会有问题,比如当slave回应ACK给master时,当ACK传输到master时,比slave发出的时间已经晚了,即已经经过了FPDLINK的延时,可能已经错过了SCL的上升沿。
幸好i2c 协议考虑到了这种情况,i2c spec规定了一个属性叫i2c stretch,也就是i2c slave在没有准备好的情况下,在发送ACK之前可以将SCL拉低,这样master在尝试拉高SCL的时候就会失败,这样master就会一直尝试将SCL拉高,等slave将SCL释放以后,master就可以拉高SCL,接收ACK bit。因此在分析FPDLINK Slave端i2c 波形时,会发现每次发slave地址部分都只有8个bit,其实ACK会在后面进行回应,如下图
TI的FPDLINK芯片充分利用了这个特性,他并不是把接收到的i2c波形进行简单的转发(即保持和发送端相同的波特率),而是将收到的数据重新再按照FPDLINK芯片上设置的波特率重新发送。因此在分析FPDLINK Slave端i2c 波形时,需要注意这一点。可能CPU的i2c波特率是400K,但是FPDLINK slave接收端的i2c的波特率是100K或者1M,这个取决于FPDLINK芯片里面的SCL high和low的相关设置。
通过分析slave的i2c波形,还会发现一个挺有意思的现象,在读寄存器数据时,slave会自己先发出波形进行预先读取,比如要读取的寄存器地址为0x00的数据,会在波形上看到在当master发出写寄存器地址0x00以后,接着会发出slave的地址进行读(R/W = 1), slave 在发出该波形后,会紧接着发出8个SCL波形进行预先读取,而这8个clock在master侧是没有对应的,其实是master要在后面才发的,所以slave相当于先发了。
这个地方的设计是非常巧妙的,因为i2c协议规定,i2c stretch只能发生在第九bit,也就是ACK bit。如果slave回应了master的slave读的ACK,则当master发出正式读取数据的SCL时从机将没有机会拉住SCL,因为读取数据的SCL头八个波形是不允许拉的,而此时也没有收到从机的数据,所有就有问题了。
TI的做法是,既然前面有一次写的动作,后面又紧接着发的是一个读的slave地址,显然要读的是前面写的那个寄存器地址,因此将在master发送读的slave地址的第9bit ACK拉住,同时发出8个SCL进行寄存器读写,再释放SCL,master检测到SCL释放后,重新发送读数据clock,此时就有数据返回给CPU了。
虽然I2C可能是比较简单的总线协议之一,但是其中的某些设计还是非常非常巧妙的。