ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FPGA高速接口实战:Aurora IP核从配置到上板调试全流程

FPGA高速接口实战:Aurora IP核从配置到上板调试全流程 1. 为什么Aurora IP核值得花时间啃下来做FPGA高速接口的兄弟应该都有体会板子跑通第一个LED容易跑通第一个高速串行接口难。尤其是当项目里出现板间互联、芯片间互联、采集卡到主控的数据搬运这类需求时你绕不开SerDes和高速协议。Xilinx的Aurora IP核就是在这个场景下最常被翻牌子的方案之一。Aurora是什么简单说它是Xilinx提供的一个轻量级、可裁剪的链路层协议IP核跑在GTGigabit Transceiver物理层之上用来做点对点的高速串行数据传输。它不像PCIe、以太网那样有一大堆协议栈和上层规范Aurora只负责把A端的数据可靠地搬到B端开销小、延迟低、资源占用少。你可以把它理解成一条“专用高速数据管道”——两端各放一个Aurora核中间用GT线连起来数据就能以Gbps级别的速率双向流动。这个IP核适合谁我梳理了一下大概三类人最需要它第一类是做数据采集和传输的FPGA工程师比如ADC采样数据要实时传到另一块板子做处理第二类是做多板卡互联的比如阵列信号处理里多块FPGA需要交换中间结果第三类是刚接触高速接口、想找一个比PCIe和以太网更容易上手的协议来练手的开发者。Aurora的协议复杂度比PCIe低不少调试手段也更直接作为高速串行接口的入门项目非常合适。但问题在于很多新手打开Vivado的IP Catalog看到Aurora 8B/10B和Aurora 64B/66B两个选项再看到里面一堆GT Selection、Lane Width、Interface选项直接就懵了。网上教程要么只讲理论不讲实操要么给个半截工程跑不起来。我当初第一次配Aurora的时候光是一个gt_reset和reset的时序关系就折腾了两天后来才发现是复位序列没搞对。这篇内容就是把我自己从零跑通Aurora IP核的完整过程拆开来讲包括IP配置的每一个关键选项怎么选、复位逻辑怎么写、AXI4-Stream接口怎么对接、上板调试怎么定位问题。工程代码我会给出核心模块的完整实现你照着搭就能跑。不管你是刚入门的FPGA新手还是已经做过几个项目但没碰过高速接口的老手这篇应该都能帮你省下不少查文档和试错的时间。2. Aurora IP核的选型与配置思路拆解2.1 Aurora 8B/10B和64B/66B到底选哪个打开Vivado的IP Catalog搜索Aurora你会看到两个IPAurora 8B/10B和Aurora 64B/66B。很多人第一步就卡在这里不知道该选哪个。我的建议很直接新手入门选8B/10B除非你有明确的带宽需求必须上64B/66B。原因在于两者的编码方式和应用场景不同。8B/10B编码是每8位数据编码成10位传输有25%的编码开销但它自带DC平衡和足够的跳变沿接收端时钟恢复容易链路建立稳定。64B/66B编码开销只有约3%效率更高但它对GT的参考时钟和均衡要求更严格调试难度也更大。对于大多数中小规模的数据传输场景8B/10B的线速率已经能跑到3.125Gbps到6.25Gbps甚至更高完全够用。还有一个实际因素8B/10B的文档、示例工程和社区讨论都更多遇到问题更容易找到参考。64B/66B在UltraScale和Versal系列上用得更多如果你用的是7系列或者UltraScale8B/10B是更稳妥的选择。2.2 Lane Width和Line Rate的计算逻辑选好IP类型之后接下来要确定Lane Width和Line Rate。Lane Width就是GT收发器的通道数可以选1、2、4、8等。Line Rate是每条Lane的线速率单位Gbps。这两个参数怎么定从你的实际数据带宽需求倒推。假设你需要单向传输5Gbps的有效数据选了8B/10B编码那线速率至少要5 / 0.8 6.25Gbps。如果选1条LaneLine Rate就是6.25Gbps如果选2条Lane每条Lane跑3.125Gbps就够了。Lane数越多单Lane速率越低但占用的GT资源和引脚也越多。这里有个经验尽量让Line Rate落在GT支持的范围内并且留一定余量。比如GT支持1.25Gbps到12.5Gbps你选6.25Gbps是合理的选12.5Gbps就贴着上限了信号完整性压力大。另外Line Rate和参考时钟有倍数关系常见的参考时钟是125MHz或156.25MHz你需要确保Line Rate是参考时钟的整数倍否则PLL锁不定。2.3 Interface选项Framing还是StreamingAurora IP核提供两种用户接口Framing和Streaming。这也是新手容易选错的地方。Framing接口有帧的概念数据以帧为单位传输每帧有起始和结束标志接收端能区分帧边界。它适合传输有明确包结构的数据比如自定义协议包。Streaming接口就是纯粹的连续数据流没有帧边界数据来了就发接收端按顺序收。它适合连续采集数据的场景比如ADC数据流。我个人的建议是如果你不确定选哪个选Framing。因为Framing更通用你可以在Framing的基础上自己封装协议而且Framing接口的握手信号更明确调试时更容易判断数据什么时候有效。Streaming接口虽然简单但一旦数据流断了或者乱了排查起来更麻烦。2.4 AXI4-Stream接口的价值Aurora IP核的用户接口可以选Native或者AXI4-Stream。我强烈建议选AXI4-Stream原因有三个。第一AXI4-Stream是Xilinx生态里的标准流接口你后面要接FIFO、DMA、滤波器这些IP都是AXI4-Stream接口直接对接不用写转换逻辑。第二AXI4-Stream的握手协议tvalid/tready非常清晰数据有效性和反压机制一目了然调试时看波形就能判断问题。第三很多现成的参考设计和开源工程都用AXI4-Stream你抄作业更方便。Native接口虽然少了一层封装、理论上延迟低一点但实际项目中这点延迟差异可以忽略而AXI4-Stream带来的便利性是实打实的。3. Vivado中Aurora IP核的配置实操3.1 新建工程与IP核添加先确保你的Vivado版本和板卡型号匹配。我用的环境是Vivado 2020.2加一块Kintex-7的开发板GT收发器是GTX。不同系列的GT类型不同7系列是GTP/GTX/GTHUltraScale是GTH/GTY但配置流程基本一致。新建工程后在Flow Navigator里点IP Catalog搜索“Aurora 8B/10B”双击打开配置界面。第一个页面是“Core Options”这里选Lane Width、Line Rate和Interface类型。我这次配置的是Lane Width 1Line Rate 3.125GbpsInterface FramingFlow Control None。Flow Control先不启用等基础链路跑通了再加。3.2 GT Selection页面的关键参数第二页“GT Selection”是重头戏。这里要选GT的Quad和Channel位置还要设置参考时钟频率。GT的位置取决于你的板子原理图哪对收发器引出了就选哪个。参考时钟频率要和你板子上的晶振匹配常见的有125MHz、156.25MHz。我板子上是125MHz所以Ref Clk Frequency填125MHz。注意Line Rate必须是参考时钟经过PLL倍频后能得到的频率3.125Gbps / 125MHz 25倍PLL能实现。这一页还有个“Startup”选项可以选“Immediate”或者“Wait for GT Reset”。我建议选“Wait for GT Reset”这样链路建立时机可控不会在GT还没稳定的时候就尝试建链。3.3 复位与时钟配置的注意事项第三页“Core Functionality”里有一些复位和时钟相关的选项。这里有个关键点Aurora IP核需要两个时钟——init_clk和gt_ref_clk。init_clk是给IP核内部逻辑用的通常接100MHz或50MHz的稳定时钟gt_ref_clk是GT的参考时钟必须接板子上的专用时钟引脚。复位方面IP核提供了gt_reset、reset、power_down三个信号。gt_reset复位GT收发器reset复位IP核逻辑power_down让GT进入低功耗模式。这三个信号的时序关系非常关键搞错了链路就建不起来。我在第4节会详细讲复位序列怎么写。3.4 生成IP核与例化模板配置完成后点OKVivado会生成IP核。右键IP核选“Open IP Example Design”Vivado会自动生成一个包含Aurora IP核的示例工程。这个示例工程非常有价值它包含了完整的复位逻辑、时钟管理和数据收发测试逻辑。我强烈建议你先把这个示例工程跑一遍仿真看看波形理解各个信号的时序关系然后再基于它改自己的工程。示例工程里的核心模块是“aurora_8b10b_0_exdes”它例化了Aurora IP核和一套测试逻辑。你可以直接把这个模块的复位和时钟部分抄到自己的工程里省去很多调试时间。4. 复位逻辑与链路建立的核心细节4.1 gt_reset、reset、power_down的时序关系这是Aurora调试中最容易踩坑的地方。很多人IP核配置没问题但链路就是建不起来十有八九是复位时序不对。正确的复位序列是这样的首先power_down保持为0正常工作模式。然后gt_reset拉高至少一个init_clk周期再拉低。gt_reset拉低后GT收发器开始初始化这个过程需要一段时间通常几十微秒。等GT初始化完成后IP核会输出gt_pll_lock和gt_rxcdrovrden等状态信号。确认这些信号有效后再把reset拉高至少一个init_clk周期然后拉低。reset拉低后Aurora IP核开始尝试建立链路channel_up信号会在链路建立成功后拉高。关键点gt_reset必须在reset之前完成而且两者之间要有足够的间隔。我一般会在gt_reset拉低后等1ms再操作reset确保GT完全稳定。4.2 复位状态机的Verilog实现下面是我实际工程中用的复位状态机代码你可以直接参考module aurora_reset_fsm ( input wire init_clk, input wire gt_ref_clk_locked, input wire gt_pll_lock, output reg gt_reset, output reg reset, output reg power_down ); localparam S_IDLE 3d0; localparam S_GT_RESET 3d1; localparam S_WAIT_LOCK 3d2; localparam S_CORE_RESET 3d3; localparam S_DONE 3d4; reg [2:0] state; reg [15:0] wait_cnt; always (posedge init_clk) begin case (state) S_IDLE: begin gt_reset 1b0; reset 1b0; power_down 1b0; wait_cnt 16d0; if (gt_ref_clk_locked) state S_GT_RESET; end S_GT_RESET: begin gt_reset 1b1; if (wait_cnt 16d100) begin gt_reset 1b0; wait_cnt 16d0; state S_WAIT_LOCK; end else wait_cnt wait_cnt 1b1; end S_WAIT_LOCK: begin if (gt_pll_lock) begin if (wait_cnt 16d50000) state S_CORE_RESET; else wait_cnt wait_cnt 1b1; end end S_CORE_RESET: begin reset 1b1; if (wait_cnt 16d100) begin reset 1b0; wait_cnt 16d0; state S_DONE; end else wait_cnt wait_cnt 1b1; end S_DONE: begin // 复位完成等待channel_up end endcase end endmodule这段代码的逻辑很清晰先等参考时钟锁定然后拉gt_reset等GT PLL锁定后再拉reset最后进入完成状态。wait_cnt的计数值根据你的init_clk频率调整我用的100MHz50000个周期就是0.5ms足够GT稳定了。4.3 channel_up和lane_up的判断链路建立成功的标志是channel_up拉高。在Framing模式下还有lane_up信号表示每条Lane是否同步。对于单Lane配置channel_up和lane_up基本同时拉高。实际调试时如果channel_up一直不拉高先检查gt_pll_lock有没有拉高。如果gt_pll_lock没拉高说明GT的参考时钟或者Line Rate配置有问题。如果gt_pll_lock拉高了但channel_up不拉高检查两端Aurora IP核的配置是否一致——Line Rate、Lane Width、参考时钟频率必须完全匹配否则链路建不起来。5. AXI4-Stream数据收发对接实操5.1 发送路径的接口信号Aurora IP核的AXI4-Stream发送接口信号包括s_axi_tx_tdata、s_axi_tx_tvalid、s_axi_tx_tready、s_axi_tx_tlast、s_axi_tx_tkeep。数据位宽取决于Lane Width和Interface配置单Lane 8B/10B通常是16位或32位。发送逻辑很简单当s_axi_tx_tready为高时把s_axi_tx_tvalid拉高同时给出tdata和tlast数据就被发送出去了。tlast表示帧的最后一个数据tkeep表示有效字节。如果是Streaming模式tlast和tkeep可以不用。下面是一个简单的发送测试逻辑reg [31:0] tx_counter; reg tx_valid; reg tx_last; always (posedge user_clk) begin if (!reset) begin tx_valid 1b0; tx_last 1b0; tx_counter 32d0; end else begin if (s_axi_tx_tready !tx_valid) begin tx_valid 1b1; tx_counter tx_counter 1b1; if (tx_counter 32d255) tx_last 1b1; end else if (tx_valid s_axi_tx_tready) begin tx_counter tx_counter 1b1; if (tx_counter 32d255) begin tx_last 1b1; tx_valid 1b0; end end end end assign s_axi_tx_tdata tx_counter; assign s_axi_tx_tvalid tx_valid; assign s_axi_tx_tlast tx_last; assign s_axi_tx_tkeep 4hF;这段代码每256个数据组成一帧发送完一帧后停止等下一轮。实际项目中你可以把tx_counter替换成你的数据源比如ADC采样数据或者FIFO读出的数据。5.2 接收路径的接口信号接收接口信号包括m_axi_rx_tdata、m_axi_rx_tvalid、m_axi_rx_tlast、m_axi_rx_tkeep。接收逻辑更简单因为Aurora IP核会自己处理链路层的事情你只需要在m_axi_rx_tvalid为高时把数据取走就行。always (posedge user_clk) begin if (m_axi_rx_tvalid) begin // 数据有效写入FIFO或做其他处理 rx_data m_axi_rx_tdata; rx_valid 1b1; if (m_axi_rx_tlast) rx_frame_end 1b1; end else begin rx_valid 1b0; end end实际项目中接收端通常要接一个FIFO或者BRAM来缓冲数据因为Aurora的接收速率可能和你的处理速率不匹配。如果处理逻辑来不及取数据可以用m_axi_rx_tready做反压但要注意Aurora的接收FIFO深度有限反压时间太长会导致数据丢失。5.3 回环测试的搭建方法验证Aurora链路最简单的方法是做回环测试把发送端的数据直接接到接收端看收到的数据是否和发出去的一致。你可以在示例工程的基础上改把m_axi_rx_tdata接到s_axi_tx_tdata形成一个回环。回环测试的波形很直观channel_up拉高后发送端开始发数据接收端应该收到相同的数据。如果收到的数据不对先检查tkeep和tlast的处理再检查两端的数据位宽是否匹配。6. 上板调试与常见问题排查6.1 链路建不起来的排查顺序上板后channel_up不拉高按以下顺序排查排查项检查方法常见原因参考时钟用示波器测gt_ref_clk引脚晶振未起振或频率不对gt_pll_lock在ILA中观察该信号Line Rate与参考时钟不匹配gt_reset时序观察复位状态机波形gt_reset和reset间隔太短两端配置对比两端IP核配置Line Rate或Lane Width不一致物理连接检查SMA线或板间连接器线缆损坏或接触不良我遇到最多的情况是gt_pll_lock不拉高基本都是Line Rate和参考时钟的倍数关系没算对。比如参考时钟125MHzLine Rate设成3.2Gbps3.2 / 0.125 25.6不是整数PLL就锁不定。改成3.125Gbps就没问题了。6.2 数据收发异常的问题定位channel_up拉高了但数据不对常见原因有这几个第一tkeep信号没处理对。8B/10B模式下tkeep表示哪些字节有效如果你固定给4hF但实际数据只有2字节有效接收端会多收无效数据。第二tlast信号时序不对导致帧边界错乱。第三两端的数据位宽不一致比如发送端32位接收端16位数据就乱了。用ILA抓波形是最有效的定位手段。抓s_axi_tx_tvalid、s_axi_tx_tready、s_axi_tx_tdata、s_axi_tx_tlast这几个信号看发送时序是否符合AXI4-Stream协议。再抓接收端的m_axi_rx_tvalid、m_axi_rx_tdata、m_axi_rx_tlast对比收发数据是否一致。6.3 我在实际项目中踩过的坑第一个坑init_clk和user_clk搞混了。Aurora IP核输出的user_clk是给用户逻辑用的频率和Line Rate有关。我一开始把user_clk当成init_clk用结果复位状态机跑得乱七八糟。后来才搞清楚init_clk是输入给IP核的稳定时钟user_clk是IP核输出的两者不能混用。第二个坑复位释放时机不对。我一开始在gt_pll_lock还没拉高的时候就释放了reset结果channel_up一直不拉高。后来改成等gt_pll_lock拉高后再等一段时间才释放reset问题解决。第三个坑ILA的时钟域选错。Aurora的user_clk和init_clk是不同时钟域ILA要分别用对应的时钟采样。我一开始用init_clk采user_clk域的信号波形全是乱的换了时钟之后就正常了。6.4 常见问题速查表现象可能原因解决方法gt_pll_lock不拉高Line Rate与参考时钟不匹配重新计算Line Rate确保是参考时钟整数倍channel_up不拉高复位时序不对检查gt_reset和reset的间隔channel_up不拉高两端配置不一致对比两端IP核的Line Rate和Lane Width收到数据但全是0发送端tvalid没拉高检查发送逻辑的tvalid生成数据错位tkeep或tlast处理错误检查tkeep和tlast的时序链路偶尔断开参考时钟抖动大检查时钟源质量加去耦电容ILA波形异常时钟域选错用对应时钟域采样7. 工程代码结构与后续扩展方向7.1 完整工程的模块划分我的工程顶层模块叫aurora_top下面例化了这几个子模块aurora_reset_fsm负责复位时序aurora_8b10b_0是IP核本身tx_logic和rx_logic分别处理发送和接收数据ila_0用于调试抓波形。时钟方面init_clk接板子上的100MHz晶振gt_ref_clk接125MHz专用时钟。顶层模块的端口包括差分参考时钟输入、GT收发器差分数据输入输出、LED指示灯指示channel_up状态、复位按键输入。整个工程资源占用很低一个Aurora 8B/10B单Lane核大概占几百个LUT和几个GT对7系列FPGA来说毫无压力。7.2 从回环测试到实际数据传输回环测试跑通后把tx_logic的数据源换成你的实际数据源比如ADC接口模块或者DDR读出的数据。rx_logic的输出接到你的数据处理模块或者FIFO。如果数据速率不匹配在中间加一个异步FIFO做跨时钟域缓冲。如果要双向传输例化两个Aurora IP核一个做主一个做从或者用同一个IP核的全双工模式。Aurora本身支持全双工发送和接收是独立的通道你只需要把两端的收发交叉连接就行。7.3 性能优化与资源评估Aurora 8B/10B单Lane在3.125Gbps线速率下的有效数据带宽是3.125 × 0.8 2.5Gbps。如果不够用可以增加Lane数或者提高Line Rate。4 Lane配置下有效带宽能到10Gbps足够大多数采集和传输场景。资源方面Aurora IP核本身占用的逻辑资源不多主要消耗在GT收发器上。7系列FPGA的GTX Quad有4个Channel一个Quad能支持4 Lane的Aurora。如果你板子上有多个Quad可以跑多组独立的Aurora链路。后续如果要加Flow Control可以在IP配置里启用它会增加一些握手信号用来做发送端的流控。如果要做更复杂的协议可以在Aurora之上自己封装一层帧格式加校验和重传机制。我个人在实际操作中的体会是Aurora IP核的难点不在配置而在复位时序和调试手段。把复位状态机写对把ILA用对基本就成功了一大半。剩下的就是数据对接的细节多抓波形多对比问题都能定位到。
返回列表