4. 三线握手

三线握手,这个名字听起来挺唬人。其实说白了,就是比两线握手多了一条线——时钟线。

你想想看,两线握手的时候,发送方和接收方全靠“请求”和“应答”两根线来回拉扯。但这里有个问题:双方怎么知道对方什么时候把信号变了? 靠的是各自内部的时钟去采样。如果两边时钟不同步,或者采样时机不对,就容易漏掉信号。

我早年做FPGA项目时,就吃过这个亏。两线握手,数据偶尔丢一拍,查了三天,最后发现是接收方的采样时钟比发送方慢了那么几纳秒。从那以后,我对时钟同步就特别敏感。

4.1 数据有效信号:谁说了算?

三线握手里,数据有效信号是核心。它不像两线握手那样,靠“请求”信号来暗示数据有效。三线握手专门有一根线,就叫“数据有效”(Data Valid,简称DV)。

这根线的作用很简单:发送方把数据放到总线上之后,再拉高DV信号,告诉接收方:“数据已经稳了,你可以来取了。”

接收方看到DV为高,就知道当前总线上的数据是有效的。然后它开始采样,采样完成后,拉高“应答”信号。发送方看到应答,就知道数据被收走了,于是拉低DV,准备下一笔数据。

关键点:数据有效信号必须在数据稳定之后才拉高。如果数据还在跳变,DV就拉高了,接收方采到的就是错误数据。这就是所谓的“建立时间”问题。

我个人的习惯是,在FPGA设计里,数据有效信号通常用寄存器打一拍再输出。这样能确保DV和数据是严格对齐的,不会出现毛刺。

4.2 时钟同步:三线握手的“节拍器”

三线握手和两线握手最大的区别,就是多了一根时钟线(Clock)。

时钟线的作用,是让发送方和接收方共享同一个时间基准。所有信号的变化,都发生在时钟的上升沿或下降沿。这样一来,双方就不需要靠“猜”来判断对方什么时候改变信号了。

举个例子:

  • 发送方在时钟上升沿把数据放到总线上,同时拉高DV。
  • 接收方在下一个时钟上升沿看到DV为高,于是采样数据。
  • 接收方在再下一个时钟上升沿拉高应答信号。

你看,每一步都跟着时钟走,节奏非常清晰。这就是同步设计的精髓。

小技巧:如果发送方和接收方不在同一个时钟域,那就需要做跨时钟域处理。我一般用两级同步器来处理DV信号,防止亚稳态传播。

我曾经在一个项目中,把两个不同晶振的芯片用三线握手连起来。结果发现,因为时钟频率有微小差异,长时间运行后数据会偶尔错位。后来加了一个FIFO做缓冲,才彻底解决。嗯,这里要注意:三线握手虽然有时钟线,但前提是双方时钟同源。如果不同源,就得另想办法。

4.3 三线握手的典型应用

三线握手在实际工程中非常常见。我挑几个典型的场景说说。

4.3.1 SPI总线

SPI(Serial Peripheral Interface)就是三线握手的典型代表。它用四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。

但严格来说,SPI的核心是三线:时钟、数据输出、数据输入。片选信号是额外的控制线。

SPI的通信过程:

  1. 主机拉低CS,选中从机。
  2. 主机在SCLK的每个时钟沿,通过MOSI发送一位数据。
  3. 从机在同样的时钟沿,通过MISO返回一位数据。
  4. 传输完成后,主机拉高CS。

这里的数据有效信号,其实就是时钟沿本身。数据在时钟沿被采样,所以不需要额外的DV线。

避坑指南:我曾经在SPI设计里,把时钟极性和相位搞反了。结果数据读出来全是乱的。后来老老实实对着数据手册,把CPOL和CPHA配对了,才恢复正常。所以,用SPI之前,一定要确认好时钟的极性和相位。

4.3.2 I2C总线

I2C虽然只有两根线(SCL和SDA),但它本质上也是三线握手的变种。SCL是时钟线,SDA是数据线,而数据有效信号是通过SCL的时钟沿来隐含表示的。

I2C的规则是:数据在SCL为高电平时必须稳定,只有在SCL为低电平时才能变化。这就是数据有效信号的另一种表达方式。

我刚开始学I2C时,总觉得它比SPI复杂。后来发现,只要记住“SCL高电平时读数据,低电平时换数据”这个口诀,就简单多了。

4.3.3 自定义并行总线

在一些高速数据采集系统里,我们经常用自定义的并行总线。比如ADC采集卡和FPGA之间,就常用三线握手:

  • 时钟线:ADC的采样时钟,送给FPGA。
  • 数据线:多路并行数据,比如12位或16位。
  • 数据有效线:ADC告诉FPGA,“当前数据已经转换完成,可以读取了”。

这种结构的好处是,FPGA不需要去猜ADC什么时候输出数据。只要看到DV为高,就直接采样,非常可靠。

我记得有一次做高速采集,ADC的时钟频率是200MHz。如果不用三线握手,光靠两线握手,根本来不及响应。用了三线握手后,每个时钟周期都能传一笔数据,效率极高。

4.4 三线握手的时序图

下面我用SVG画一个典型的三线握手时序图,帮你直观理解。

三线握手时序图 CLK DATA 无效数据 有效数据 无效数据 DV ACK DV拉高,数据有效 接收方应答 DV拉低,传输结束

从时序图里可以看得很清楚:

  • 时钟CLK一直运行,作为时间基准。
  • 数据在DV拉高之前,是无效的(灰色区域)。
  • DV拉高后,数据变为有效(绿色区域)。
  • 接收方看到DV为高,在下一个时钟沿采样数据,然后拉高ACK。
  • 发送方看到ACK为高,拉低DV,完成一次传输。

总结一下:三线握手的核心就是“时钟同步 + 数据有效信号”。它比两线握手更可靠,比四线握手更简单。在需要高速、可靠传输的场景下,三线握手是首选。

我个人觉得,三线握手是接口设计里性价比最高的方案。它不复杂,但能解决大部分同步传输的问题。你如果能把三线握手吃透,后面学更复杂的协议(比如AXI、PCIe)就会轻松很多。

经验之谈:设计三线握手时,一定要把时序余量算清楚。我曾经因为布线太长,导致DV信号比数据晚到了半个时钟周期,结果接收方采到了错误数据。后来加了等长布线,才解决问题。

好了,三线握手就讲到这里。记住:时钟是骨架,数据有效信号是血肉,两者缺一不可。