阅读学习杰哥过去留下的 limfx 文档及相关资料后,我发现完整工程并不是一次性搭建完成的,而是由多个小实验逐步验证、组合而成。因此,本阶段我也计划先从几个关键实验入手,在实践中逐步理解 PS 端 DMA 搬运、DDR 缓存以及后续留盘功能的实现方式。
PL 端产生测试数据,通过 AXI DMA 搬运到 PS 端 DDR 中,再由 Vitis 裸机程序读取 DDR 数据,并通过 UART 串口打印出来,以验证 PL 到 PS DDR 的数据通路是否正确。
总体流程如下所示:
测试数据产生模块(testdata_gen.v) // 模拟产生 5 张子卡、共 160 通道的同步数据
↓
数据格式转换模块(ad_to_dma.v) // 将 5 路 512 bit 数据整理为 AXI-Stream 数据,并通过FIFO完成缓存与跨时钟域,将数据送入 DMA
↓
AXI DMA // 通过 S2MM 通道将数据写入 PS DDR
↓
Vitis 裸机程序读取 DDR // 从指定 DDR 地址读取 DMA 写入的数据
↓
UART 串口打印验证 // 打印数据内容,判断搬运结果是否正确
testdata_gen.v 用于在 PL 端产生测试数据,模拟真实 AD 采集数据。当前设计中模拟 5 张子卡,每张子卡以2M/s的采样率输出 512 bit 数据,对应 32 个 16 bit 通道。该模块的输入输出为:
input wire clk, //系统时钟
input wire rst_n, //复位信号
input wire enable, //模块使能信号
output reg [511:0] testdata0_o, //子卡0测试数据
output reg [511:0] testdata1_o, //子卡1测试数据
output reg [511:0] testdata2_o, //子卡2测试数据
output reg [511:0] testdata3_o, //子卡3测试数据
output reg [511:0] testdata4_o, //子卡4测试数据
output reg data_valid //数据有效信号
测试数据格式为:
testdata0_o: sample_cnt + 通道号
testdata1_o: sample_cnt + 通道号 + 0x1000
testdata2_o: sample_cnt + 通道号 + 0x2000
...
ad_to_dma.v 用于接收 5 张子卡的数据,并将其拆分、整理为 128 bit 宽度的 AXI-Stream 数据流,供后续 AXI DMA 接收。
由于每个采样点的数据大小为512*5 = 2560 bit,也就是需要拆分成 20 个 128 bit 的数据,考虑到为便于后续数据解析,每个采样点的边界应当清晰,所以在每个采样点前加一帧作为帧头,因此当前帧格式为:
1 个帧头 + 20 拍数据
数据转换模块的输入输出为:
input wire ad_clk, //PL侧时钟信号
input wire ad_rst_n, //PL侧复位信号
input wire dma_clk, //PS侧时钟信号
input wire dma_rst_n, //PS侧复位信号
input wire enable_i, //模块使能信号
input wire [511:0] ad_data0_i, //采集数据及有效信号输入
input wire [511:0] ad_data1_i,
input wire [511:0] ad_data2_i,
input wire [511:0] ad_data3_i,
input wire [511:0] ad_data4_i,
input wire data_valid_i,
output wire [127:0] m_axis_tdata_o, //AXI-Stream 数据总线,输出给 AXI DMA S_AXIS_S2MM
output wire [15:0] m_axis_tkeep_o, //字节有效标志,每 1 bit 对应 tdata 中 1 byte,16'hFFFF 表示 128 bit 全部有效
output wire m_axis_tvalid_o, //数据有效信号,表示当前 tdata/tkeep/tlast 有效
input wire m_axis_tready_i, //下游就绪信号,由 AXI DMA/FIFO 返回,表示可以接收当前数据
output wire m_axis_tlast_o //帧结束信号,拉高表示当前拍是一帧数据的最后一拍
Block Design 中需要加入 Zynq PS、AXI DMA 以及自定义 RTL 模块。
加入后首先配置Zynq UItraScale+ MPSoC:

配置好Zynq UItraScale+ MPSoC后需要进行DMA配置。DMA配置为:
SG:开启
Control/Status Stream:关闭
MM2S:关闭
S2MM:开启
S2MM Stream Width:128 bit
S2MM Memory Map Width:128 bit
SG Length Width:26
然后进行Block Design连线。Block Design设计如下所示:

通过顶层模块将测试数据产生模块和数据格式转换模块实例化,使能信号设置为复位后拉高1s,产生640MB的测试数据。
always @(posedge ad_clk or negedge ad_rst_n) begin
if (!ad_rst_n) begin
enable <= 1'b0;
enable_cnt <= 32'd0;
end else begin
if(enable_cnt == 32'd100_000_000)begin
enable <= 1'b0;
end else begin
enable <= 1'b1;
enable_cnt <= enable_cnt+32'd1;
end
end
end
然后搭建仿真平台,通过仿真波形观察数据及其时序是否正确。当前仿真结果显示,每帧输出稳定为 21 拍,帧头固定为55AA55AA55AA55AA55AA55AA55AA55AA,符合当前帧格式设计。

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