软件版本:vitis2020.2(vivado2020.2)
操作系统:WIN10 64bit
硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA(本文使用米联客(milianke)MZU07A-EG开发板)
9.1概述
本文在 AXI_DMA_LOOP 环路测试架构的基础上,在 DATA FIFO 端加入 FPGA 代码,对 FIFO 写,实现将 PL 端数据 通过 DMA 发送给 PS 功能。
本文实验目的:
1:掌握编程PL代码,以AXI-Stream协议把数据通过DMA发送到PS DDR
2:通过VITIS-SDK编程实现数据的接收
3:通过VITIS-SDK观察PS内存中接收到的数据是否正确。
9.2搭建SOC系统工程
新建一个名为为zu_prj的工程,之后创建一个BD文件,并命名为system,添加并且配置好ZYNQ Ultrascale+ MPSOC IP。读者需要根据自己的硬件类型配置好输入时钟频率、内存型号、串口,连接时钟等。新手不清楚这些内容的,请参考“3-2-01_ex_soc_base_07a-eg .pdf” “01 HelloWold/DDR/网口测试”这篇文章。
9.2.1PS部分设置
1:PS复位设置
2:设置PS FPD接口和HP接口
3:设置PL到PS的中断
Interurptsà勾选 Fabric Interrupt,勾选IRQ0[0:7]。
4:设置PL的时钟
勾选PL0,设置为100,即PS的PLL提供本系统的时钟100MHZ。
9.2.2添加IP
单击添加IP按钮“ ”,输入如下模块IP名字的关键词,并双击添加。
9.2.3IP设置
设置Wideh of buffer length register :23。(寄存器设置最大为26,即2的26次方64M大小,这里设置23bit 就够用了,长度越大,需要的资源也就越多)
这里也只要使用DMA写通道,
Data FIFO设置TDATA Width为4。
9.2.4PL图形编程
下图中可以看到FIFO的S_AXIS接口引出到了外部的FPGA代码中,所以后面我们需要编写合适的AXI-Stream FPGA代码来写FIFO。
9.2.5地址空间分配
9.2.6编写AXI-Stream写代码
如下图中,system_dma_top.v代码是可以实现对FPGA图形设计代码的调用。
现在我们看看system_dma_top.v中如何利用axi-stream协议完成对fifo的写操作。
module system_wrapper();
reg [31:0]S_AXIS_tdata; wire S_AXIS_tlast; wire S_AXIS_tvalid = 1'b1; wire FCLK_CLK0; wire s_axis_aclk; wire s_axis_aresetn; wire [3:0]S_AXIS_tkeep; wire S_AXIS_tready; wire [0:0]gpio_rtl_tri_o; wire [0:0]peripheral_aresetn;
assign S_AXIS_tkeep = 4'b1111; assign s_axis_aclk = pl_clk0; assign s_axis_aresetn = peripheral_aresetn&&gpio_rtl_tri_o;
always@(posedge pl_clk0)begin if(s_axis_aresetn == 1'b0)begin S_AXIS_tdata <= 0; end else begin if(S_AXIS_tready&&S_AXIS_tdata<511) S_AXIS_tdata <= S_AXIS_tdata + 1'b1; else if(S_AXIS_tready) S_AXIS_tdata <= 0; end end
assign S_AXIS_tlast = (S_AXIS_tdata == 511)&&S_AXIS_tready&&S_AXIS_tvalid;
system system_i (.S_AXIS_tdata(S_AXIS_tdata), .S_AXIS_tkeep(S_AXIS_tkeep), .S_AXIS_tlast(S_AXIS_tlast), .S_AXIS_tready(S_AXIS_tready), .S_AXIS_tvalid(S_AXIS_tvalid), .gpio_rtl_tri_o(gpio_rtl_tri_o), .peripheral_aresetn(peripheral_aresetn), .pl_clk0(pl_clk0), .s_axis_aclk(s_axis_aclk), .s_axis_aresetn(s_axis_aresetn)); endmodule |
以上代码非常简洁,本身axi-stream协议就非常简洁。
以上代码中设置S_AXIS_tvalid = 1'b1始终为1代表,任何时候只要S_AXIS_tready有效,数据计数器S_AXIS_tdata就加1,每次发送512个32bit数据,也就是1024个字节数据。每发送1024个数据产生一个中断。中断的产生是靠axi-stream协议的S_AXIS_tlast信号决定。S_AXIS_tlast = (S_AXIS_tdata == 511)&&S_AXIS_tready&&S_AXIS_tvalid。
9.2.7编译并导出平台文件
1:单击Block文件à右键àGenerate the Output ProductsàGlobalàGenerate。
2:单击Block文件à右键à Create a HDL wrapper(生成HDL顶层文件)àLet vivado manager wrapper and auto-update(自动更新)。
3:生成Bit文件。
4:导出到硬件: FileàExport HardwareàInclude bitstream
5:导出完成后,对应工程路径的zu_hw路径下有硬件平台文件:system_wrapper.xsa的文件。根据硬件平台文件system_wrapper.xsa来创建需要Platform平台。
9.3搭建Vitis-sdk工程
创建zu_base sdk platform和APP工程的过程不再重复,可以阅读本章节01~05相关demo。以下给出创建好zu_base sdk platform的截图和对应工程APP的截图。
9.3.1创建SDK Platform工程
9.3.2创建axi_dma_pl2ps APP工程
9.4实验结果
Debug程序,单程序停止main函数处,打开VIVADO,扫描芯片,这个时候会自动之前添加的在线逻辑分析仪IP核。如下红框的按键先不要单击。
具体步骤如下:
在VIVADO工程中点击Open Target 然后点击Auto Connect
连接成功后入下图
下图中,我们利用axi-tlast信号作为触发信号
下图中我们使用DMA产生的中断信号作为触发信号
单击如下图片,让在线逻辑分析仪的2个窗口都处于等待触发状态
如下图所示是等待触发状态
回到SDK,继续设置,打开Memory:Window->Show View->Memory
点击添加接收内存部分地址用于观察内存中的数据 地址为 0x01300000
为了观察一次收发数据:设置断点,重新让收发程序跑一次。双击以下程序处可以设置断点。
设置完成后,单击如下可以单击如下红框的按键
串口打印结果,通过设置TTC定时器,每间隔1S 打印一次计算的测速。实际上也就是计算单位时间内,DMA了多少次。可以通过增加数据位宽,以及增加PL时钟的频率,提高速度。读者可以去尝试下。
内存中观察到的数据,可以看到地址0x01300000地址的开始并不是00而是AB和我们的预期有些差异,不过数据是非常有规律的,说明DMA是正常工作的,但是我们的用户逻辑实际上没有能够确保发送数据的时候第一数据是00,这个大家可以思考下为什么,有什么办法可以改进。我们后面lwip的demo就对此问题必须做改进。
在线逻辑分析仪