[X]关闭
3

10PL读写PS端DDR(FDMA AXI4总线实战)

摘要: FDMA是米联客的基于AXI4总线协议定制的一个DMA控制器。有了这个IP我们可以统一实现用FPGA代码直接读写PL的DDR或者PS的DDR。本文中FDMA的IP是开源的,在配套FPGA工程的uisrc/ip路径下可以找到源码。本文的IP已经利用V ...

软件版本: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:读出过程

1

路过

雷人

握手

鲜花

鸡蛋

刚表态过的朋友 (1 人)

发表评论

最新评论

引用 xclzjvcy 2021-11-15 19:15
你好汤老师,您上边的提取码错误,可以再分享一下吗?
引用 uisrc 2021-8-18 20:43
配套源码下载链接:https://pan.baidu.com/s/1TvjOdZvCyDQpS4a7jYivRQ 提取码:1111
引用 rluxezmn 2021-8-17 14:58
你好汤老师,请问下9.10.11的源码可以提供下吗?

查看全部评论(3)

本文作者
2021-8-15 23:40
  • 7
    粉丝
  • 7063
    阅读
  • 3
    回复
  • 1
  • 2
  • 3
热门评论
排行榜