软件版本: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/网口测试”这篇文章。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线

9.2.1PS部分设置

1:PS复位设置

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_02

2:设置PS FPD接口和HP接口

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_03

3:设置PL到PS的中断

Interurptsà勾选 Fabric Interrupt,勾选IRQ0[0:7]。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_04

4:设置PL的时钟

勾选PL0,设置为100,即PS的PLL提供本系统的时钟100MHZ。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_05

9.2.2添加IP

单击添加IP按钮“9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_06 ”,输入如下模块IP名字的关键词,并双击添加。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_07    9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_08     9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_09

9.2.3IP设置

设置Wideh of buffer length register :23。(寄存器设置最大为26,即2的26次方64M大小,这里设置23bit 就够用了,长度越大,需要的资源也就越多)

这里也只要使用DMA写通道,

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_10

Data FIFO设置TDATA Width为4。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_11

9.2.4PL图形编程

下图中可以看到FIFO的S_AXIS接口引出到了外部的FPGA代码中,所以后面我们需要编写合适的AXI-Stream FPGA代码来写FIFO。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_12

9.2.5地址空间分配

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_13

9.2.6编写AXI-Stream写代码

如下图中,system_dma_top.v代码是可以实现对FPGA图形设计代码的调用。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_14

现在我们看看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平台。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_15

9.3搭建Vitis-sdk工程

创建zu_base sdk platform和APP工程的过程不再重复,可以阅读本章节01~05相关demo。以下给出创建好zu_base sdk platform的截图和对应工程APP的截图。

9.3.1创建SDK Platform工程

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_16

9.3.2创建axi_dma_pl2ps APP工程

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_17

9.4实验结果

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_18

Debug程序,单程序停止main函数处,打开VIVADO,扫描芯片,这个时候会自动之前添加的在线逻辑分析仪IP核。如下红框的按键先不要单击。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_19

具体步骤如下:

在VIVADO工程中点击Open Target 然后点击Auto Connect

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_20

连接成功后入下图

下图中,我们利用axi-tlast信号作为触发信号

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_21

下图中我们使用DMA产生的中断信号作为触发信号

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_22

单击如下图片,让在线逻辑分析仪的2个窗口都处于等待触发状态

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_23

如下图所示是等待触发状态

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_24

回到SDK,继续设置,打开Memory:Window->Show View->Memory    

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_25

点击添加接收内存部分地址用于观察内存中的数据 地址为 0x01300000

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_26    9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_27

为了观察一次收发数据:设置断点,重新让收发程序跑一次。双击以下程序处可以设置断点。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_28

设置完成后,单击如下可以单击如下红框的按键

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_29

串口打印结果,通过设置TTC定时器,每间隔1S 打印一次计算的测速。实际上也就是计算单位时间内,DMA了多少次。可以通过增加数据位宽,以及增加PL时钟的频率,提高速度。读者可以去尝试下。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_30

内存中观察到的数据,可以看到地址0x01300000地址的开始并不是00而是AB和我们的预期有些差异,不过数据是非常有规律的,说明DMA是正常工作的,但是我们的用户逻辑实际上没有能够确保发送数据的时候第一数据是00,这个大家可以思考下为什么,有什么办法可以改进。我们后面lwip的demo就对此问题必须做改进。

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_31

在线逻辑分析仪

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_32

9AXI-Stream发数据到PS(DMA)(AXI4总线篇)_AXI4总线_33