10PL读写PS端DDR(FDMA AXI4总线实战)
软件版本:vitis2020.2(vivado2020.2)
操作系统:WIN10 64bit
硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA(米联客(milianke)MZU07A-EG硬件开发平台)
登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!
10.1概述
FDMA是米联客的基于AXI4总线协议定制的一个DMA控制器。有了这个IP我们可以统一实现用FPGA代码直接读写PL的DDR或者PS的DDR。本文中FDMA的IP是开源的,在配套FPGA工程的uisrc/ip路径下可以找到源码。本文的IP已经利用VIVADO做了图形化的封装,所以可以直接通过图形化连线设计,使用非常方便。
本文实验目的:
1:利用米联客自定一定FDMA2.0/3.0版本搭建SOC工程(最新发布的版本是3.0)
2:编写FPGA测试代码实现,PL写入数据到PS DDR然后再读出PS DDR中的数据,对比是否正确。
为了让PS的DDR可以运行,必须新建一个vitis-sdk工程,这个工程主要是为了初始化PS DDR,我们可以简单新建一个自带的hello工程。
10.2搭建SOC系统工程
新建一个名为为zu_prj的工程,之后创建一个BD文件,并命名为system,添加并且配置好ZYNQ Ultrascale+ MPSOC IP。读者需要根据自己的硬件类型配置好输入时钟频率、内存型号、串口,连接时钟等。新手不清楚这些内容个,请参考"3-2-01_ex_soc_base_07a-eg .pdf" "01 HelloWold/DDR/网口测试"这篇文章。
10.2.1PS部分设置
1:PS复位设置
2:PS AXI HP0 FPD设置
3:PL输出时钟设置
10.2.2添加自定义IP
1:设置IP路径
本文中是我们第一次在BD图形化设计中添加自定义的IP,自定义的IP需要设置IP路径才能被识别到。默认情况下,我们自定的IP在配套工程的uisrc/ip路径下:
2:添加IP
10.2.3PL图像化编程
10.2.4添加FPGA FDMA读写代码
上图中源码在配套fpga工程的uisrc/rtl路径中,本文中我们修改了默认的system_wrapper.v文件名为system_wrapper_fdma.v这样的好处是对默认文件和手动修改过的文件加以区分,以免幸苦修改的代码一不小心,被软件自动更新替换掉。
关键的代码为fdma_test.v。在这个程序中,写入一定数据到DDR中,然后再读出,对比是否有错误,几个关键参数:
TEST_MEM_SIZE:定义了测试内从空间的大小,以byte为单位,是整数倍的FDMA_BURST_LEN *(fdma_wdata/8)。
FDMA_BURST_LEN:定义每次FDMA传输的长度,这个长度是整数倍的fdma_wdata或者fdma_rdata。
ADDR_MEM_OFFSET:代码了内从访问的起始地址。
`timescale 1ns / 1ns /* Company : Liyang Milian Electronic Technology Co., Ltd. Brand: 米联客(milianke) Technical forum:uisrc.com taobao: https://milianke.taobao.com https://osrc.taobao.com jd:https://milianke.jd.com Create Date: 2019/12/17 Module Name: fdma_test Description: Copyright: Copyright (c) milianke Revision: 1.0 Signal description: 1) _i input 2) _o output 3) _n activ lowpai 4) _dg debug signal 5) _r delay or register 6) _s state mechine */ //////////////////////////////////////////////////////////////////////////////////
module fdma_test# ( parameter TEST_MEM_SIZE = 32'd40960, parameter FDMA_BURST_LEN = 16'd1024, parameter ADDR_MEM_OFFSET = 1024*1024*500 ) ( input ui_clk, input fdma_rstn, output [31: 0] fdma_waddr, output reg fdma_wareq, output [15: 0] fdma_wsize, input fdma_wbusy, output reg [127:0] fdma_wdata, input fdma_wvalid, output reg fdma_wready,
output [31: 0] fdma_raddr, output reg fdma_rareq, output [15: 0] fdma_rsize, input fdma_rbusy, input [127:0] fdma_rdata, input fdma_rvalid, output reg fdma_rready ); parameter WRITE1 = 0; parameter WRITE2 = 1; parameter READ1 = 2; parameter READ2 = 3;
reg [31: 0] fdma_waddr_r; reg [16 :0] fdma_rcnt = 0; reg [2 :0] T_S = 0;
assign fdma_waddr = fdma_waddr_r + ADDR_MEM_OFFSET; assign fdma_raddr = fdma_waddr;
assign fdma_wsize = FDMA_BURST_LEN; assign fdma_rsize = FDMA_BURST_LEN;
reg [10:0] rst_cnt = 0;
always @(posedge ui_clk) if(fdma_rstn == 1'b0)begin rst_cnt <=0; end else begin if(rst_cnt[10] == 1'b0) rst_cnt <= rst_cnt + 1'b1; else rst_cnt <= rst_cnt; end
always @(posedge ui_clk)begin if(rst_cnt[10] == 1'b0)begin T_S <=0; fdma_wareq <= 1'b0; fdma_rareq <= 1'b0; fdma_wready <= 1'b0; fdma_rready <= 1'b0; fdma_wdata <=0; fdma_waddr_r <=0; end else begin case(T_S) WRITE1:begin if(fdma_waddr_r>TEST_MEM_SIZE) fdma_waddr_r<=0; if(!fdma_wbusy)begin fdma_wareq <= 1'b1; fdma_wready <= 1; fdma_wdata <= 0; end if(fdma_wareq&&fdma_wbusy)begin fdma_wareq <= 1'b0; T_S <= WRITE2; end end WRITE2:begin if(!fdma_wbusy) begin T_S <= READ1; fdma_wready <= 0; fdma_wdata <= 32'd0; end else if(fdma_wvalid) begin fdma_wdata <= fdma_wdata + 1'b1; end end
READ1:begin if(!fdma_rbusy)begin fdma_rareq <= 1'b1; fdma_rready <= 1; fdma_rcnt <= 0; end if(fdma_rareq&&fdma_rbusy)begin fdma_rareq <= 1'b0; T_S <= READ2; end end READ2:begin if(!fdma_rbusy) begin T_S <= WRITE1; fdma_rready <= 0; fdma_rcnt <= 32'd0; fdma_waddr_r <= fdma_waddr_r + FDMA_BURST_LEN*128/8; end else if(fdma_rvalid) begin fdma_rcnt <= fdma_rcnt + 1'b1; end end default: T_S <= WRITE1; endcase end end
wire test_error = ((fdma_rready&&fdma_rvalid) && (fdma_rcnt[15:0] != fdma_rdata[15:0]));
ila_0 ila_dbg ( .clk(ui_clk), .probe0({fdma_waddr[15:0],fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wready,fdma_wbusy}), .probe1({fdma_rdata[15:0],fdma_rcnt[15:0],fdma_rvalid,fdma_rready,fdma_rbusy,T_S,test_error}) );
endmodule |
10.2.5设置地址分配
10.2.6编译并导出平台文件
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平台。
10.3搭建Vitis-sdk工程
创建zu_base sdk platform和APP工程的过程不再重复,可以阅读本章节01~05相关demo。以下给出创建好zu_base sdk platform的截图和对应工程APP的截图。
10.3.1创建SDK Platform工程
10.3.2创建hello APP工程
10.4实验结果
1:先运行hello app
2:打开设备
3:如果没有出来下图的hw_ila 波形窗口,右击刷新
4:观察在线逻辑分析结果
5:写入过程
6:读出过程