FPGA间并行总线通信:从接口协议到时序约束的实战指南
2026/6/6 18:22:37 网站建设 项目流程

1. 项目概述:为什么FPGA间并行总线通信值得深究

在复杂的数字系统设计中,尤其是涉及高速数据采集、图像处理或通信基带处理的场景,单颗FPGA的资源或I/O带宽常常捉襟见肘。这时,将任务拆分到多片FPGA协同工作就成了必然选择。我最近在一个多通道雷达信号处理的项目中就遇到了这个问题,需要将一片FPGA预处理后的数据,稳定、高速地传输给另一片FPGA进行后续的算法处理。市面上有各种高速串行接口,比如Aurora、JESD204B,听起来很高大上,但对于很多内部数据交互、控制信号传递,或者对成本、开发周期敏感的中等速率场景,一种简单可靠的并行总线方案往往更“接地气”。

这种方案的核心优势在于“直接”和“可控”。它不依赖复杂的IP核,不涉及高速串行收发器的苛刻布局布线要求,仅用一组标准的LVTTL或LVCMOS电平的普通I/O口,配合一个时钟和几个握手信号,就能搭建起通信桥梁。它的缺点也很明显,就是耗费管脚资源,且时序需要精心设计,否则极易出现数据错位、采样不稳定等问题。这篇文章,我就结合自己的实战经验,拆解这种两片FPGA间基于并行总线的单向数据传输方案,从接口定义、硬件设计、逻辑实现,到最关键的时序约束与分析,分享一套完整、可复现的设计方法与避坑指南。

2. 接口定义与工作协议:构建通信的“语言”

设计通信接口,第一步是明确“语言”规则。一个清晰、无二义性的协议是稳定通信的基础。我们采用的是一种基于请求-应答机制的同步并行接口,它结构简单,可靠性高。

2.1 信号定义与功能解析

接口信号不多,但每个都至关重要。我们以发送端(TX_FPGA)和接收端(RX_FPGA)来区分角色。

  • tx_clk (时钟信号,由TX_FPGA输出):这是整个数据传输的节拍器。所有数据都在这个时钟的边沿被发送和采样。它必须是稳定的、低抖动的时钟信号。
  • tx_db[N:0] (数据总线,由TX_FPGA输出):承载实际传输数据的并行总线,宽度N可以根据需求设定,比如8位、16位、32位等。宽度越大,单周期吞吐量越高,但占用管脚也越多。
  • tx_en (数据有效信号,由TX_FPGA输出):高电平有效,指示当前tx_db上的数据是有效的、可供采样的。它为接收端提供了明确的数据窗口标识。
  • rx_req (请求发送信号,由RX_FPGA输出):接收端向发送端“要数据”的握手信号。当RX_FPGA的接收FIFO有足够空间,或需要新数据时,拉高此信号。
  • clr (清除/复位信号,由RX_FPGA输出):这是一个全局复位信号,用于复位TX_FPGA内部的发送FIFO。通常用于通信初始化或错误恢复。

注意tx_en信号非常关键。在简单的场景下,有人可能会想用rx_req直接作为数据有效指示,但这是不安全的。因为rx_req可能是一个长脉冲,而数据是突发传输的。独立的tx_en信号实现了数据有效性与传输请求的解耦,是保证数据边界清晰的核心。

2.2 “请求-突发”工作流程详解

这套协议的工作流程像一场精心编排的舞蹈:

  1. 初始状态rx_reqtx_en均为低电平,tx_db为任意值(通常建议驱动到已知状态,如全0)。TX_FPGA的发送FIFO为空或含有待发数据。
  2. 接收端发起请求:当RX_FPGA准备好接收数据(例如其接收FIFO非满),它将rx_req信号置为高电平。这个信号是异步的,不依赖于tx_clk
  3. 发送端响应与突发传输:TX_FPGA检测到rx_req为高后,不会立即发送单个数据,而是启动一次固定长度的数据突发传输。例如,一次突发发送256个数据。此时,TX_FPGA会在下一个tx_clk上升沿开始,将tx_en拉高,并同时将第一个有效数据放到tx_db上。
  4. 数据同步传输:在tx_en为高电平期间,每一个tx_clk的上升沿,tx_db上的数据都会更新为下一个要发送的数据。RX_FPGA则在每个tx_clk上升沿采样tx_entx_db。当采样到tx_en为高时,就将tx_db的值写入接收FIFO。
  5. 突发结束与请求撤销:当固定数量的数据发送完毕后,TX_FPGA将tx_en拉低,表示一次突发传输结束。RX_FPGA在接收完预定数量的数据后,可以将rx_req拉低(也可以保持高电平以请求下一组数据,具体看流控策略)。

这种“请求-突发”模式相比“每时钟请求”的优势在于,它减少了rx_req信号上的活动,降低了因信号抖动或跨时钟域问题导致错误的风险,同时也更符合FIFO批量读写的特性,提高了总线利用率。

2.3 双FIFO缓存结构的作用

图1中提到的专用FIFO是此设计的缓冲核心。

  • TX_FPGA发送FIFO:用于缓存上游逻辑(如数据处理模块)产生的数据。其作用是将上游可能不规则的数据流,平滑为以固定突发长度输出的规整数据流。同时,它隔离了上游逻辑与对外接口的时序域。
  • RX_FPGA接收FIFO:用于缓存从接口接收到的数据。其作用是吸收数据突发,供下游逻辑以自身速率平稳读取。它隔离了接口时序域与下游逻辑时序域。

两个FIFO的深度需要根据数据生产速率、消费速率以及突发长度来仔细计算,以防止溢出或下溢。一个实用的技巧是,将FIFO的“几乎满”和“几乎空”标志位用于产生rx_req和控制上游数据流,而不是等到完全满或完全空,这样可以预留安全余量,避免数据丢失。

3. 硬件设计要点:为稳定传输铺平道路

硬件连接是通信的物理基础,处理不当会直接导致时序无法收敛或系统不稳定。这里有几个容易被忽视的细节。

3.1 时钟信号的分配与布线

tx_clk是整个接口的时序参考,必须保证其质量。

  • 发送端(TX_FPGA)tx_clk应直接由FPGA内部的PLL或MMCM生成,并且必须分配到专用的全局时钟输出管脚(如Intel FPGA的专用时钟输出管脚,Xilinx FPGA的MRCC/SRCC管脚)。这些管脚到FPGA封装焊球的路径是优化的,抖动和偏斜(Skew)最小。绝对不要用一个普通的I/O口来输出这个时钟。
  • 接收端(RX_FPGA):PCB板上的tx_clk信号线,必须连接至RX_FPGA的专用全局时钟输入管脚。同样,这是为了利用FPGA内部专用的、低抖动的全局时钟网络,将时钟信号分配到所有采样寄存器,最小化时钟路径偏斜。
  • PCB布线tx_clk在PCB上应作为关键信号处理。建议采用阻抗控制的走线(如50欧姆),并保持路径连续。尽可能短、直,避免过孔。如果条件允许,应在其相邻层铺设完整的参考地平面,为它提供一个清晰的回流路径。

3.2 数据与控制信号的布线考量

对于tx_dbtx_enrx_reqclr这些信号:

  • 等长布线tx_db总线内的所有信号线,长度应尽可能匹配。目的是让这些信号同时到达接收端,减少数据总线内部的偏斜(Intra-pair Skew)。tx_en最好也与tx_db总线做等长处理,因为它和数据是同步的。rx_reqclr作为低频控制信号,时序要求宽松,可以不做严格等长,但也要保证走线质量。
  • 参考平面与串扰:所有信号线都应有良好的参考地平面。并行总线信号之间应保持足够的间距,或者在中间穿插地线,以降低串扰。高速翻转的并行总线是串扰的主要来源之一。
  • 端接电阻:对于3.3V LVTTL电平,在传输线较长(例如超过几英寸)且速率较高(例如tx_clk超过50MHz)时,需要考虑源端串联端接或并联端接,以抑制信号反射。一个常见的做法是在TX_FPGA的输出管脚串联一个小电阻(如22欧姆到33欧姆),这个电阻应靠近发送端放置。

3.3 电源与地去耦

为接口I/O Bank供电的电源必须干净、稳定。每个FPGA的I/O Bank电源引脚附近,都必须放置足够数量、容值搭配(如0.1uF和10uF)的去耦电容。这是保证信号边沿干净、减少同步开关噪声(SSN)的基石,很多间歇性的时序问题都源于电源噪声。

4. 时序约束与分析:让数据被稳稳抓住

这是整个设计的灵魂,也是最能体现工程师功底的部分。连接正确不代表能工作,时序收敛才是通信可靠的保证。我们的目标是:让RX_FPGA内部采样寄存器的时钟上升沿,稳稳地落在tx_entx_db信号的有效窗口中央。

4.1 时序路径分解与模型建立

如图2和图4所示,从TX_FPGA内部的源寄存器,到RX_FPGA内部的目的寄存器,一条路径的延时可以分为三段:

  1. T_co (TX FPGA内部时钟到输出延时):时钟tx_clk在TX_FPGA内部从PLL输出到驱动输出管脚的寄存器的时钟端延时,加上寄存器本身的时钟到输出时间(Tco)。
  2. T_pcb (PCB板走线传输延时):信号从TX_FPGA管脚到RX_FPGA管脚在PCB板上的飞行时间。这取决于走线长度、介电常数和传输线模型,可以通过仿真或经验公式(如~150 ps/英寸)估算,它是一个相对固定但存在工艺偏差的值。
  3. T_su (RX FPGA内部输入到寄存器建立时间):信号从RX_FPGA输入管脚,经过输入缓冲器、布线,到达目的寄存器数据输入端的延时,再加上寄存器所需的建立时间(Tsu)。

对于时钟信号tx_clk,其路径也类似,只是它的目的是到达目的寄存器的时钟端。我们需要分别计算数据路径(tx_db,tx_en)的总延时和时钟路径(tx_clk)的总延时。

4.2 源同步接口与时钟相位调整

我们的接口是一个典型的源同步接口。即时钟(tx_clk)和数据(tx_db,tx_en)由同一个源头(TX_FPGA)发出,在接收端用这个伴随数据一起传来的时钟去采样数据。这样做的好处是,时钟和数据在PCB板上经历的延时是相关的,对工艺、温度、电压(PVT)变化具有一定的共模抑制能力。

但即便如此,由于FPGA内部路径的差异,时钟和数据的延时仍然不同。为了让接收时钟沿对准数据有效窗口的中心,我们需要在RX_FPGA内部对传入的tx_clk进行相位调整。这就是通过PLL或MMCM的相位偏移(Phase Shift)功能来实现的。我们的时序计算,最终就是为了求解这个最优的相位偏移量Tshift

4.3 时序计算实战推导

我们结合图5和图6的模型,进行一步步推导。定义:

  • Tclktx_clk的时钟周期。
  • Tdmax,Tdmin:数据路径(从TX源寄存器到RX目的寄存器数据端)的最大和最小总延时。
  • Tcmax,Tcmin:时钟路径(从TX PLL输出到RX目的寄存器时钟端)的最大和最小总延时。
  • Tshift:我们在RX_FPGA的PLL中对tx_clk施加的相位偏移(正值表示延迟)。

第一步:确定数据有效窗口数据在TX端每个时钟上升沿更新。因此,对于一个特定的数据位,它会在Tdmin时间后最早到达RX端,并在Tdmax时间后最晚稳定在RX端。这个数据会保持稳定直到下一个时钟沿的新数据到来,即持续约一个时钟周期。因此,在RX端看到的数据有效窗口为:[Tdmax, Tclk + Tdmin]窗口中心为:Tdv_center = (Tdmax + Tclk + Tdmin) / 2

第二步:确定时钟有效边沿窗口经过相位偏移Tshift后,时钟边沿在RX端出现的时间窗口为:[Tshift + Tcmin, Tshift + Tcmax]窗口中心为:Tcv_center = Tshift + (Tcmin + Tcmax) / 2

第三步:对齐窗口中心以获得最佳采样点为了最可靠的采样,我们希望时钟边沿落在数据有效窗口的正中央,即:Tcv_center = Tdv_center代入公式:Tshift + (Tcmin + Tcmax) / 2 = (Tdmax + Tclk + Tdmin) / 2解出TshiftTshift = (Tclk + Tdmax + Tdmin - Tcmin - Tcmax) / 2

第四步:代入实例计算假设我们通过约束和工具报告得到以下参数(单位ns):

  • Tclk = 20(对应50MHz时钟)
  • Tdmax = 15.5,Tdmin = 10
  • Tcmax = 3.5,Tcmin = 1

代入公式:Tshift = (20 + 15.5 + 10 - 1 - 3.5) / 2 = (41) / 2 = 20.5 ns

由于Tclk=20ns,20.5ns相当于相位偏移了0.5ns。我们可以在RX_FPGA的PLL中,将tx_clk输入的时钟相位延迟0.5ns(或提前19.5ns,效果相同)。

4.4 在FPGA开发工具中实施约束

计算出的Tshift需要反馈到约束文件中。以Intel Quartus Prime为例,关键约束包括:

  1. 创建生成时钟:对输入的tx_clk创建一个虚拟的“生成时钟”,作为内部采样时钟的参考。

    create_generated_clock -name rx_sampling_clk -source [get_ports tx_clk] -phase 0.5 [get_ports tx_clk]

    这里-phase 0.5表示0.5ns的偏移(具体语法请参考工具手册)。

  2. 设置输入延迟:对tx_dbtx_en信号设置输入延迟约束,告诉时序分析工具这些信号相对于tx_clk的外部延迟情况。这需要根据PCB延迟和Tdmax/Tdmin的估计值来设置。

    set_input_delay -clock rx_sampling_clk -max 15.5 [get_ports {tx_db[*] tx_en}] set_input_delay -clock rx_sampling_clk -min 10 [get_ports {tx_db[*] tx_en}]
  3. 设置虚假路径:对于rx_reqclr这类异步控制信号,它们与tx_clk时钟域没有确定的时序关系,应设置为虚假路径,避免无关的时序报错干扰分析。

    set_false_path -from [get_ports {rx_req clr}] -to [get_clocks rx_sampling_clk]

    在逻辑设计上,这些信号进入TX_FPGA后,必须经过同步器(两级寄存器)同步到TX_FPGA的工作时钟域,才能用于控制逻辑。

完成约束后,必须运行完整的时序分析(TimeQuest Timing Analyzer或Vivado的时序报告),检查建立时间(Setup)和保持时间(Hold)的裕量(Slack)是否为正,并且最好有足够的余量(例如大于0.5ns)以应对PVT变化。

5. 逻辑设计与实现细节

有了清晰的协议和时序规划,逻辑实现就相对直接了,但仍有细节需要注意。

5.1 发送端(TX_FPGA)逻辑设计

发送端状态机可以设计为以下几个状态:

  1. IDLE:等待rx_req同步信号为高。注意,来自RX_FPGA的rx_req是异步信号,需要先经过两级寄存器同步到tx_clk时钟域,得到rx_req_sync再使用。
  2. BURST_STARTrx_req_sync为高后,进入此状态。在此状态拉高tx_en,并从发送FIFO中读出第一个数据放到tx_db上。
  3. BURST_TRANSFER:在此状态,每个tx_clk上升沿,从FIFO中读取下一个数据输出,并递增突发计数器。当计数器达到预设突发长度时,进入下一状态。
  4. BURST_END:拉低tx_en。检查rx_req_sync,如果仍为高,则跳回BURST_START开始下一次突发;如果为低,则回到IDLE

发送FIFO的读使能应在BURST_STARTBURST_TRANSFER状态下,根据FIFO非空且需要发送数据时产生。

5.2 接收端(RX_FPGA)逻辑设计

接收端逻辑更简单,是一个持续的过程:

  1. 在每个tx_clk(经过PLL相位调整后的时钟)的上升沿,采样tx_entx_db
  2. 如果采样到的tx_en为高,则将采样到的tx_db数据写入接收FIFO。
  3. 接收FIFO的“几乎满”或水位标志用于产生rx_req。例如,当FIFO中的数据量低于某个阈值时,拉高rx_req;当FIFO快满时,拉低rx_reqrx_req信号可以直接输出到管脚,无需同步到tx_clk域,因为它由RX_FPGA本地时钟产生,在TX端会被同步。
  4. clr信号可以由一个上电复位逻辑或特定的错误恢复状态机产生,直接输出到管脚。在TX端,它也需要被同步到TX的工作时钟域后才能用于复位发送FIFO。

5.3 同步器设计与亚稳态处理

这是跨时钟域信号处理的核心安全措施。

  • 在TX_FPGA中,为rx_reqclr输入信号分别添加两级寄存器同步链,同步到tx_clk域。
  • 在RX_FPGA中,如果tx_clk还用于驱动其他逻辑(而不仅仅是采样接口),那么从接口采样得到的数据(已稳定)在送入接收FIFO时,FIFO的写时钟是tx_clk,而读时钟可能是RX_FPGA的其他工作时钟。这就构成了一个异步FIFO。必须使用标准的异步FIFO IP核或者自己用双端口RAM和格雷码计数器实现,以确保跨时钟域数据传递的安全。

实操心得:千万不要为了省事,用单个寄存器去采样异步信号。亚稳态是概率性事件,在实验室可能测试一万次都好用,到了现场温度变化、电源波动时,就可能突然出现,导致系统崩溃。两级寄存器同步是成本最低、最可靠的“保险丝”。

6. 调试、验证与常见问题排查

设计完成并上电后,真正的挑战才开始。以下是我总结的调试流程和常见坑点。

6.1 调试流程建议

  1. 静态检查:首先确认PCB连接与原理图一致,电源和地网络无误。用万用表测量关键电源点电压是否正常。
  2. 时钟先行:不加载完整逻辑,先分别给两块FPGA加载一个最简单的测试程序:TX_FPGA输出固定频率的tx_clk(如50MHz),RX_FPGA将输入的tx_clk直接驱动到一个LED上。用示波器测量TX端和RX端的tx_clk,观察波形是否干净、频率是否正确、幅度是否达标。这是基础中的基础。
  3. 信号质量测试:在TX_FPGA逻辑中,让tx_db输出一个简单的循环计数模式(如0xAA, 0x55),tx_en常高。用示波器多通道功能,同时观察tx_clk和几条tx_db信号线。检查数据是否在时钟上升沿稳定变化,信号有无过冲、回沟、振铃。测量建立时间和保持时间是否充裕。
  4. 协议功能测试:加载完整的发送和接收逻辑,但将接收到的数据直接回环到另一个接口输出,或者用ILA(集成逻辑分析仪,如Xilinx的ILA或Intel的SignalTap)抓取接收端FIFO入口的数据。在发送端通过按键或软核CPU控制发送特定数据序列(如递增数列、伪随机码),在接收端验证数据的正确性和连续性。
  5. 压力与稳定性测试:进行长时间、全速率的满带宽数据传输测试。同时监测FPGA的片内温度和关键电源电压纹波。温度过高或电源噪声增大可能引发时序裕量收缩,导致偶发性错误。

6.2 常见问题与排查表

现象可能原因排查思路与解决方法
完全无数据1. 时钟未输出/未连接。
2. 电源或地连接错误。
3.rx_req信号始终为低。
1. 示波器检查TX端tx_clk有无输出,RX端能否测到。
2. 检查所有电源网络和地网络连通性。
3. 检查RX_FPGA逻辑,确认产生rx_req的条件是否满足(如接收FIFO非满)。
数据 sporadic(零星)错误1. 时序裕量不足,处于亚稳态边缘。
2. 信号完整性差(反射、串扰)。
3. 电源噪声大。
1. 重新审查时序约束,查看时序报告中的建立/保持时间裕量(Slack)。尝试微调RX端PLL的相位偏移Tshift
2. 用示波器仔细观测数据和时钟波形,看有无畸变。检查PCB布线,确认端接电阻是否合适、有无stub。
3. 用示波器AC耦合模式测量FPGA的I/O电源纹波,增加去耦电容。
数据连续错位(如整体偏移一个时钟)1. 时钟相位偏移Tshift设置错误,导致采样点在数据有效窗口边缘甚至之外。
2.tx_en信号与数据对齐关系错误。
1. 这是最典型的相位问题。使用ILA抓取RX端采样时刻的tx_entx_db,看tx_en有效窗口是否覆盖了时钟上升沿。系统性调整PLL相位(以10-50ps为步进),寻找错误率最低的点。
2. 检查TX端逻辑,确保tx_en与第一个有效数据在同一个tx_clk上升沿发生变化。
突发传输长度不对1. 发送端和接收端对突发长度的定义不一致。
2. 计数器逻辑错误。
1. 核对双方代码中定义的突发长度常数是否一致。
2. 用ILA抓取发送端的突发计数器状态,看其计数和结束逻辑是否正确。
高负载下偶发错误1. 同步开关噪声(SSN)。
2. 温度升高导致时序特性变化。
1. 大量数据总线同时翻转会导致地弹。优化PCB设计,确保有坚实的电源/地平面,I/O Bank电源去耦充足。在代码中,如果允许,可以错开数据总线的翻转时刻(但这会略微增加偏斜)。
2. 进行高低温测试。在时序约束中应用更严苛的器件模型(如高温低压模型)进行时序分析,确保有足够的设计余量。

6.3 关于ILA/SignalTap的使用技巧

片上逻辑分析仪是调试数字逻辑的利器。针对本设计:

  • 在TX端:可以抓取同步后的rx_req_sync、发送状态机、发送FIFO的读空标志、以及输出的tx_en和部分tx_db数据。用于确认发送逻辑是否按预期响应请求。
  • 在RX端:这是重点。必须抓取经过相位调整后的采样时钟、tx_entx_db以及写入接收FIFO的数据。通过对比抓取到的tx_db和写入FIFO的数据,可以直观判断采样是否正确。如果可能,设置触发条件为“写入FIFO的数据不等于某个预期值”,可以快速捕获错误发生时的瞬间波形。

调试是一个假设-验证-修正的循环过程。从电源、时钟、信号质量这些物理层开始,再到协议层、数据层,层层递进,大部分问题都能被定位和解决。最令人头疼的往往是间歇性错误,这通常指向时序裕量不足或信号完整性问题,需要耐心地结合工具报告和实测波形进行精细调整。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询