中能聚控aurora协议移植到ddaq pl端程序(20260407)

思路

中能聚控那边已经提供了能跑通的板卡间aurora协议,因此考虑复用中能聚控的aurora协议相关代码。

aurora协议在之前板卡间数据传输使用的gt_wizard ip核中已经使用过,逻辑上基本一致;之前也已经用gt实现过板卡内数据回环后对接杰哥的ddaq pl端程序。因此参考之前的程序,思路如下:

  1. 中能聚控的程序里面,数据接收解析结构应该是和我们的程序结构类似的,即,主卡接收到子卡通过aurora传输的信号后,由相关ip核将信号解析成可以给后续模块使用的格式;
  2. 对接重点是,理解中能聚控程序中,子卡传输给主卡的信号,通过什么接口引脚传输到主卡;相关ip核需要如何配置,才能将信号转换为子卡所编码的数据帧;子卡编码的数据帧,又被什么模块,通过什么方式处理,转换成可供后续udp包打包的格式;
  3. 现在还需要考虑到,现在是多块子卡传输数据到同一块主卡,因此还要思考,不同子卡如何同步工作,各个子卡数据如何有序拼接。

中能聚控程序阅读

初步阅读

中能聚控程序结构比较简单,基本分成这几个模块:

  1. aurora_module_inst0~5:调用aurora_8b10b ip核,对各个子卡通过aurora协议传输的信号进行解析,获得相关的编码数据;
  2. aurora_driver_inst0~5:aurora 发送端相关信号的驱动模块,并不对aurora接收端具体传输的数据进行处理;
  3. aurora_to_udp:将通过aurora协议接收到的编码数据,转换成适合打包为udp的数据;
  4. ip核xxv_ethernet_0和gen_channel_wrapper:进行udp数据传输.

结构和上面对接思路的猜测基本一致。由于中能聚控的程序中,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 模块
                                           (直通连接,未做修改)

aurora_module模块分析

该模块是 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					()
    );

其中组成如下:

  1. GT 收发器:rxn/rxp, txn/txp差分对,用于串并转换、8b/10b解码、逗号对齐等。
  2. Aurora 协议层(位于ip核内部)。
  3. AXI Stream 输出接口:m_axi_rx_*,输出数据。

aurora_driver

该模块用于数据回环测试。相关顶层模块:

// 以编号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_to_udp

该模块将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)

);

该模块的解码逻辑,需要参考子卡发送端编码逻辑进行阅读。编码逻辑如下:

  1. 发送端在无有效数据传输时,会插入一个固定编码 32'h55aa_bcbc,其中8'hbc即高速收发器中用于数据对齐的k码,通过该编码提示接收端aurora如何正确读取gt信号。
  2. 发送端默认32通道全部启用,因此没有设置包头信息;
  3. 发送完毕,此时继续发送固定编码32'h55aa_bcbc。

模块内将编码数据帧转换为 64 位 UDP 负载逻辑如下:

  1. 创建5个fifo,分别缓冲5个子卡传输数据;
  2. 创建状态机,分为idle状态和各个板卡的waiting状态、aurora状态;
  3. 当开始进行udp传输时,检测5个板卡对应fifo是否非空,如果有哪个fifo非空,则对该fifo进行8次读出,8次读出完毕之后,继续检测其他fifo是否非空;
  4. 5个fifo均完成读出后,回到idle状态进行复位操作。

参考编码逻辑以及模块对应解码逻辑,即可编写32位aurora传输数据对接ddaq pl端的相关模块。

当前进展与后续计划

pl端程序,计划先处理好单子卡的数据对接ddaq pl端程序,之后再实现多子卡的数据同步。

当前进展:
已经将相关aurora模块移植到ddaq pl端程序中,并且针对编写了aurora数据转换为单通道数据流格式的模块,用于对接ddaq pl端程序。

后续pl端计划:

  1. 需要将程序仿真测试后上板调试,检查程序逻辑;
  2. 完成多子卡数据同步,保证采样点各通道数据的同步,避免采样点内通道乱序;
  3. 完成主卡对子卡的控制逻辑,如果有对各个子卡中各个通道的控制需求,还需要调整aurora发送端编码逻辑;
  4. 将pl端程序封装,替换ps端中相关模块。

关于fifo的疑惑点:
之前讨论说不能使用fifo缓冲数据,但是关于数据接收,目前认为还是需要添加fifo缓存数据。

  1. 一方面,即便是单个板卡采集数据,也需要将aurora输出125Mhz时钟驱动的32位数据,转换为ddaq pl端所需的384Hz时钟驱动的16位数据,时钟异步问题需要fifo来处理;
  2. 另一方面,多个板卡同步采集数据,但是udp包组装时,依然需要逐个板卡逐个通道组装,读取完子卡0的32通道数据同时,后续子卡的32通道数据也已经全部传输完毕,如果想再读取后续子卡传输的采集数据,后续子卡的数据依然需要先将数据缓存起来;
  3. 关于fifo对于时延的影响,查找了之前使用fifo的ila截图,数据从写入fifo,到被fifo读出,延时基本在5个左右的写时钟,参考aurora输出数据的125Mhz时钟,fifo导致的延时大约在50ns。而读取所有板卡的32*5=160通道数据,使用384Mhz时钟,每次读取1通道,需要使用160个时钟周期,计算可得时延大约为416us。

本文章使用limfx的vscode插件快速发布