中能聚控那边已经提供了能跑通的板卡间aurora协议,因此考虑复用中能聚控的aurora协议相关代码。
aurora协议在之前板卡间数据传输使用的gt_wizard ip核中已经使用过,逻辑上基本一致;之前也已经用gt实现过板卡内数据回环后对接杰哥的ddaq pl端程序。因此参考之前的程序,思路如下:
中能聚控程序结构比较简单,基本分成这几个模块:
结构和上面对接思路的猜测基本一致。由于中能聚控的程序中,udp数据传输没有我们设计的blob、slice等的格式,因此aurora_to_udp的具体udp打包逻辑不会被我们应用,不需要仔细阅读。我们需要重点理解的是aurora_module模块如何使用,aurora_to_udp中如何对通过aurora协议传输的编码数据解析;而aurora_driver模块在回环调试中也可以参考。另外,还需要根据子卡发送端的数据帧编码逻辑,对应编写解码逻辑。
需要关注的采集数据流如图所示:
子卡 Aurora 发送端
│ (高速串行差分信号)
▼
GT 引脚 (rxp/rxn)
│
▼
aurora_8b10b_0_support (IP 核 wrapper)——————————————————
│ |
│ 内部完成:CDR、8B/10B 解码、帧对齐、通道绑定 |
│ 输出:AXI Stream (m_axi_rx_*) |
▼ ▼
上层模块 (aurora_to_udp, 最终到以太网) aurora_driver 模块
(直通连接,未做修改)
该模块是 Vivado 生成的 Aurora 8B/10B IP 核的顶层封装。
相关顶层模块:
// 以编号0子卡的相关模块为例
aurora_8b10b_0_support aurora_module_inst0(
// AXI TX Interface
// aurora发送端相关信号
.s_axi_tx_tdata (tx_tdata_o),
.s_axi_tx_tkeep (tx_tkeep_o),
.s_axi_tx_tvalid (tx_tvalid_o),
.s_axi_tx_tlast (tx_tlast_o),
.s_axi_tx_tready (tx_tready_o),
// AXI RX Interface
// aurora接收端相关信号
.m_axi_rx_tdata (rx_tdata_i), // 32位传输数据
.m_axi_rx_tkeep (rx_tkeep_i), // 字节有效标志,每比特对应一个字节
.m_axi_rx_tvalid (rx_tvalid_i), // 数据有效标志,高电平时data和keep信号有效
.m_axi_rx_tlast (rx_tlast_i), // 高电平时表示当前拍是帧的最后一个数据
// V5 Serial I/O
// 进行gt信号发送接收的相关差分引脚
.rxp (RXP0),
.rxn (RXN0),
.txp (TXP0),
.txn (TXN0),
// GT Reference Clock Interface
// 系统提供的gt差分时钟
.gt_refclk1_p (GT_REFCLK0_P),
.gt_refclk1_n (GT_REFCLK0_N),
// Error Detection Interface
// 相关错误诊断信号,用于debug调试
.hard_err (),
.soft_err (),
.frame_err (),
// Status
.channel_up (channel_up_o),
.lane_up (lane_up_o),
// System Interface
.user_clk_out (user_clk_o), // 输出时钟,供后续模块使用,保证时钟同步
.reset (rst), // 系统复位时钟提供
.sys_reset_out (system_reset_o),
.power_down (1'b0), // 高电平时将关闭该aurora模块
.loopback (3'b000), // 回环测试信号,3'b000时表示不进行回环
.gt_reset (rst), // 系统复位时钟提供
.tx_lock (tx_lock0),
.pll_not_locked_out (pll_not_locked_out),
.tx_resetdone_out (),
.rx_resetdone_out (),
.init_clk_in (clk_100m), // 系统提供的初始化时钟,与gt高速收发器模块中的参考时钟功能类似
.gt0_drpaddr (),
.gt0_drpen (),
.gt0_drpdi (),
.gt0_drprdy (),
.gt0_drpdo (),
.gt0_drpwe (),
.link_reset_out ()
);
其中组成如下:
该模块用于数据回环测试。相关顶层模块:
// 以编号0子卡的相关模块为例
aurora_driver #(
.data_byte_length (8),
.trans_delay (2),
.DATA_WIDTH (32) // 数据位宽,我们使用的协议数据位宽为32位
)aurora_driver_inst0(
.clk (user_clk_o), // 对应编号子卡的aurora_module提供的时钟。
.reset_n (!system_reset_o), //复位信号,低电平有效
//输入信号
.user_data (ctrl_word_user[0]), // 输入的自定义16位信号
.user_data_valid (ctrl_word_valid[0]), // user_data有效信号
// 输出信号
// Aurora_tx
.s_axi_tx_tdata (tx_tdata_o),
.s_axi_tx_tkeep (tx_tkeep_o),
.s_axi_tx_tvalid (tx_tvalid_o),
.s_axi_tx_tlast (tx_tlast_o),
.s_axi_tx_tready (tx_tready_o),
// 输入信号
// Aurora_rx
.m_axi_rx_tdata (rx_tdata_i),
.m_axi_rx_tkeep (rx_tkeep_i),
.m_axi_rx_tvalid (rx_tvalid_i),
.m_axi_rx_tlast (rx_tlast_i),
// status
.channel_up (channel_up_o),
.lane_up (lane_up_o)
);
模块内,将自定义逻辑的user_data输入,根据编码逻辑,转换为s_axi_tx_*相关信号并输出到aurora中,当进行回环测试时,可以从rx端接收数据,所接受的数据同发送的数据对比,即可检测aurora逻辑层是否存在问题。
该模块将aurora协议获取到的 5 个通道的 32 位数据,汇聚成 64 位 UDP 负载,并过滤掉测试帧头。顶层模块如下:
aurora_to_udp#(
.data_byte_length(10'd1024),
.trans_delay (8'd3)
)(
.user_clk1 (user_clk_o),
.user_rst_n1 (!system_reset_o),
······
// 省略后续板卡类似信号
.udp_clk (tx_clk_out[0]),
.udp_rst_n (!tx_reset[0]),
.start_stop (start_stop),
// 子卡0通过aurora传输的数据
.aurora1_data (rx_tdata_i),
.aurora1_valid (rx_tvalid_i),
······
// 省略后续板卡类似信号
// 输出的64位数据
.udp_data (udp_data),
.udp_valid (udp_valid)
);
该模块的解码逻辑,需要参考子卡发送端编码逻辑进行阅读。编码逻辑如下:
模块内将编码数据帧转换为 64 位 UDP 负载逻辑如下:
参考编码逻辑以及模块对应解码逻辑,即可编写32位aurora传输数据对接ddaq pl端的相关模块。
pl端程序,计划先处理好单子卡的数据对接ddaq pl端程序,之后再实现多子卡的数据同步。
当前进展:
已经将相关aurora模块移植到ddaq pl端程序中,并且针对编写了aurora数据转换为单通道数据流格式的模块,用于对接ddaq pl端程序。
后续pl端计划:
关于fifo的疑惑点:
之前讨论说不能使用fifo缓冲数据,但是关于数据接收,目前认为还是需要添加fifo缓存数据。
本文章使用limfx的vscode插件快速发布