首页 > 其他分享 >12使用fdma读写DDR

12使用fdma读写DDR

时间:2023-12-27 19:45:38浏览次数:23  
标签:begin 12 end fdma DDR 总线 FDMA DDR3

软件版本:VIVADO2021.1

操作系统:WIN10 64bit

硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA

登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!

1概述    

FDMA是米联客基于AXI4总线协议定制的一个DMA控制器。有了这个IP我们可以统一实现用FPGA代码直接读写PL的DDR或者ZYNQ/ZYNQMP SOC PS的DDR或者BRAM。在米联客的数据交互方案中,FDMA IP CORE 已经广泛应用于ZYNQ SOC/Artix7/Kintex7/ultrascale/ultrascale+系列FPGA/SOC。

如果用过ZYNQ/ZYNQMP SOC的都知道,要直接操作PS的DDR 通常是DMA 或者VDMA,然而用过XILINX 的DMA IP 和VDMA IP,总有一种遗憾,那就是不够灵活,还需要对寄存器配置,真是麻烦。XILINX 的总线接口是AXI4总线,自定义AXI4 IP挂到总线上就能实现对内存地址空间的读写访问。因此,我们只要掌握AXI4协议就能完成不管是PS还是PL DDR的读写操作。

本文实验目的:

1:掌握基于uiFDMA3.1的FPGA工程设计

2:利用uiFDMA3.1提供的接口,编写DDR测试程序

3:对MIG接口读写仿真和测试

本文我们使用FDMA实现对AXI-MIG的读写,以此读写DDR。

2系统框图

本系统中先将测试数据通过AXI-DMA写入DDR,再通过AXI-DMA将DDR3中数据读出。将读写数据进行对比。通过在线逻辑分析仪抓取读写数据测试读写正确性。

3创建图形化逻辑工程

3.1:创建工程命名为fpga_prj

fpga工程创建本课不再详细展示。如果读者这些基础知识不清楚的,请阅读第一课的实验。

3.2:创建Block Design并且命名为system

如下图所示,图形化system就是一个代码容器,接着我们要添加一些图像化的IP

3.3:添加图形化FPGA IP

首先设置自定义IP的路径,这里读者可以把我们配套工程根路径下的uisrc文件夹复制到目前的工程根路径,单击Settings在弹出的Settings窗口选择IP->Repository 设置如下路径

添加+号添加IP

比如输入关键词FDMA就可以搜索到我们米联客uiFDMA IP

用类似的方法添加必要的IP如下图所示:

3.4:调整IP参数

3.4.1:MIG配置

 

 

 

 

 

 

 

 

 

3.4.2:Clocking Wizard配置

3.4.3:AXI Interconnect IP配置

3.5完成IP之间的信号自动

这种简单的工程可以先让软件先自动化线,然后根据结果手动一些调整

可以看到连线结果

3.6引出FPGA接口信号

1.分别右击下图2个IP,然后选择Make External,把需要引出到顶层的FPGA信号引出

2.把MIG核的复位脚断开连接,重新连接在Clk_Wiz的复位上

3.断开MIG核的ui_clk信号,然后Make External,之后重新连接在原先线路上

4.连接MIG核的初始化信号init_calib_complete到复位ip

3.7修改信号名字

3.8视图优化

右击空白处,弹出菜单选择Regenerate Layout优化下视图

 

3.9地址分配

AXI总线必须分配地址,设置uiFDMA的地址空间分配,起始地址可以任意设置,我们设置从0x0000_0000开始,大小256MB

3.10自动校验

保存工程

 

 

单击下图中的控件可以对图形化编程进行校验

 

3.11自动产生顶层文件

右击system,在弹出的菜单中选择Create HDL Wrapper

 

4编写FDMA的DDR测试代码

刚刚以上自动产生的顶层文件,只是引出的信号接口,并不能完成对FDMA的控制,所以我们需要自定义一个顶层文件,可以复制刚才产生的文件,修改,这样可以省一些编写调用接口的时间。

为了方便文件的管理,我们新建一个fdma_bram_test.v文件,并且复制以上代码,到这个文件夹。

右击删除刚刚自动产生的文件

添加fdma_ddr_test.v文件

添加一个ILA在线逻辑分析仪,如果读者这些基础知识不清楚的,可以参考快速入门篇

以下程序中是fdma读写操作的具体实现,先写入一定数据到DDR中,然后再读出,对比是否有错误,几个关键参数:

TEST_MEM_SIZE:定义了测试内从空间的大小,以byte为单位,是整数倍的FDMA_BURST_LEN *(fdma_wdata/8)。

FDMA_BURST_LEN:定义每次FDMA传输的长度,这个长度是整数倍的fdma_wdata或者fdma_rdata。

ADDR_MEM_OFFSET:代码了内从访问的起始地址。

 

/*******************************MILIANKE*******************************

*Company : MiLianKe Electronic Technology Co., Ltd.

*WebSite:https://www.milianke.com

*TechWeb:https://www.uisrc.com

*tmall-shop:https://milianke.tmall.com

*jd-shop:https://milianke.jd.com

*taobao-shop1: https://milianke.taobao.com

*Create Date: 2019/12/17

*Module Name:fdma_ddr_test

*File Name:fdma_ddr_test.v

*Description: 

*The reference demo provided by Milianke is only used for learning. 

*We cannot ensure that the demo itself is free of bugs, so users 

*should be responsible for the technical problems and consequences

*caused by the use of their own products.

*Copyright: Copyright (c) MiLianKe

*All rights reserved.

*Revision: 1.0

*Signal description

*1) _i input

*2) _o output

*3) _n activ low

*4) _dg debug signal 

*5) _r delay or register

*6) _s state mechine

*********************************************************************/

`timescale 1ns / 1ps

module fdma_ddr_test(

output [13:0]DDR3_0_addr,

output [2 :0]DDR3_0_ba,

output DDR3_0_cas_n,

output [0 :0]DDR3_0_ck_n,

output [0 :0]DDR3_0_ck_p,

output [0 :0]DDR3_0_cke,

output [0 :0]DDR3_0_cs_n,

output [3 :0]DDR3_0_dm,

inout  [31:0]DDR3_0_dq,

inout  [3 :0]DDR3_0_dqs_n,

inout  [3 :0]DDR3_0_dqs_p,

output [0 :0]DDR3_0_odt,

output DDR3_0_ras_n,

output DDR3_0_reset_n,

output DDR3_0_we_n,

input I_sysclk_p

);

 

wire [31:0]   fdma_waddr; //FDMA写通道地址

reg           fdma_wareq; //FDMA写通道请求

wire [15:0]   fdma_wsize; //FDMA写通道一次FDMA的传输大小      

wire          fdma_wbusy; //FDMA处于BUSY状态,AXI总线正在写操作  

wire [127:0]   fdma_wdata; //FDMA写数据

wire          fdma_wvalid;//FDMA写有效

wire [31:0]   fdma_raddr; //FDMA读通道地址

reg           fdma_rareq; //FDMA读通道请求

wire [15:0]   fdma_rsize; //FDMA读通道一次FDMA的传输大小        

wire          fdma_rbusy; //FDMA处于BUSY状态,AXI总线正在读操作

wire [127:0]   fdma_rdata; //FDMA读数据

wire          fdma_rvalid;//FDMA 读有效

 

wire          ui_clk; //系统时钟

wire          fdma_rstn;

reg           test_error;

   

parameter TEST_MEM_SIZE   = 32'd1024*1024*256;;//256MB; //设置内存总的测试范围,以字节为单位

parameter FDMA_BURST_LEN  = 16'd512;   //设置FDMA BURST 长度,该参数最大65535

parameter ADDR_MEM_OFFSET = 0;         //设置内存的偏移地址

parameter ADDR_INC = FDMA_BURST_LEN*16; //设置每次AXI BURST增加的地址

   

//状态机

parameter WRITE1 = 0;

parameter WRITE2 = 1;

parameter WAIT   = 2;

parameter READ1  = 3;

parameter READ2  = 4;

 

reg [2  :0] T_S = 0;//状态机

reg [31: 0] t_data;//产生测试数据

reg [31: 0] fdma_waddr_r;//地址

 

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;

assign fdma_wdata = {t_data,t_data,t_data,t_data};//写测试数据

   

   

//延迟复位

reg [8:0] rst_cnt = 0;

always @(posedge ui_clk or negedge fdma_rstn)

    if(fdma_rstn == 1'b0)

        rst_cnt <= 0;

    else if(rst_cnt[8] == 1'b0)

        rst_cnt <= rst_cnt + 1'b1;

 

//演示FDMA接口使用的读写状态机

always @(posedge ui_clk)begin

    if(rst_cnt[8] == 1'b0)begin //复位

        T_S <=0;  

        fdma_wareq   <= 1'b0;

        fdma_rareq   <= 1'b0;

        t_data       <=0;

        fdma_waddr_r <=0;      

    end

    else begin

        case(T_S)      

        WRITE1:begin //写状态1

            if(fdma_waddr_r==TEST_MEM_SIZE) fdma_waddr_r<=0; //当测试范围到达,继续从初始地址开始

                if(!fdma_wbusy)begin //如果FDMA写总线非忙

                    fdma_wareq  <= 1'b1; //请求一次FDMA写

                    t_data  <= 0;        //测试数据清0

                end

                if(fdma_wareq&&fdma_wbusy)begin //当FDMA的写请求为1,并且总线忙,代表FDMA响应了写请求

                    fdma_wareq  <= 1'b0;   //清除写请求

                    T_S         <= WRITE2; //进入下一个状态

                end

        end

        WRITE2:begin //写状态2

            if(!fdma_wbusy) begin//如果FDMA总线非忙,代表数据已经写完

                 T_S <= WAIT; //进入下一个状态

                 t_data  <= 32'd0; //清测试数据

            end

            else if(fdma_wvalid) begin //如果FDMA总线忙,并且fdma_wvalid代表了数据必须有效,则写入测试数据

                t_data <= t_data + 1'b1; //以计数器方式写入测试数据

            end

        end

        WAIT:begin//该状态机不是必须的,可以直接跳过

            T_S <= READ1;

        end

        READ1:begin//读状态机1

            if(!fdma_rbusy)begin //当fdma读总线非忙

                fdma_rareq  <= 1'b1; //发送读请求

                t_data   <= 0;//清测试数据

            end

            if(fdma_rareq&&fdma_rbusy)begin ////当FDMA的读请求为1,并且总线忙,代表FDMA响应了读请求

                 fdma_rareq  <= 1'b0;   //清除读请求

                 T_S         <= READ2;  //进入下一个状态

            end

        end

        READ2:begin //读状态机2

            if(!fdma_rbusy) begin //当FDMA 读总线非忙,代表读完成

                 T_S <= WRITE1; //进入下一个写状态,循环测试

                 t_data  <= 32'd0; //清测试数据

                 fdma_waddr_r  <= fdma_waddr_r + ADDR_INC;//计算下一次FDMA BURST的地址

            end

            else if(fdma_rvalid) begin //当读有效

                t_data <= t_data + 1'b1; //产生测试数据用于和读出的数据对比

            end

        end  

        default:

            T_S <= WRITE1;    

        endcase

    end

  end

 

always @(posedge ui_clk)begin

    test_error <= (fdma_rvalid && (t_data[31:0] != fdma_rdata[31:0]));

end  

 

ila_0 ila_dbg (

    .clk(ui_clk),

    .probe0({fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wbusy}),

    .probe1({fdma_rdata[15:0],t_data[15:0],fdma_rvalid,fdma_rbusy,T_S,test_error})

);

 

  system system_i

       (.DDR3_0_addr(DDR3_0_addr),

        .DDR3_0_ba(DDR3_0_ba),

        .DDR3_0_cas_n(DDR3_0_cas_n),

        .DDR3_0_ck_n(DDR3_0_ck_n),

        .DDR3_0_ck_p(DDR3_0_ck_p),

        .DDR3_0_cke(DDR3_0_cke),

        .DDR3_0_cs_n(DDR3_0_cs_n),

        .DDR3_0_dm(DDR3_0_dm),

        .DDR3_0_dq(DDR3_0_dq),

        .DDR3_0_dqs_n(DDR3_0_dqs_n),

        .DDR3_0_dqs_p(DDR3_0_dqs_p),

        .DDR3_0_odt(DDR3_0_odt),

        .DDR3_0_ras_n(DDR3_0_ras_n),

        .DDR3_0_reset_n(DDR3_0_reset_n),

        .DDR3_0_we_n(DDR3_0_we_n),

        .FDMA_S_0_fdma_raddr(fdma_raddr),

        .FDMA_S_0_fdma_rareq(fdma_rareq),

        .FDMA_S_0_fdma_rbusy(fdma_rbusy),

        .FDMA_S_0_fdma_rdata(fdma_rdata),

        .FDMA_S_0_fdma_rready(1'b1),

        .FDMA_S_0_fdma_rsize(fdma_rsize),

        .FDMA_S_0_fdma_rvalid(fdma_rvalid),

        .FDMA_S_0_fdma_waddr(fdma_waddr),

        .FDMA_S_0_fdma_wareq(fdma_wareq),

        .FDMA_S_0_fdma_wbusy(fdma_wbusy),

        .FDMA_S_0_fdma_wdata(fdma_wdata),

        .FDMA_S_0_fdma_wready(1'b1),

        .FDMA_S_0_fdma_wsize(fdma_wsize),

        .FDMA_S_0_fdma_wvalid(fdma_wvalid),

        .fdma_rstn(fdma_rstn),

        .sysclk(I_sysclk_p),  

        .ui_clk(ui_clk));

endmodule

5:程序分析

5.1:总流程图

如下图所示,本文的程序工作流程如下,包括请求写数据、FDMA收到写数据请求、写数据完成、请求读数据、FDMA收到读数据请求和读数据完成、校验。

以下是fdma_test.v中读写fdma ip接口的状态机,由于读写代码对称,对fdma的读写操作可以分为2步完成,分别是:1:发送读/写请求 2:读/写有效数据。

5.2:FDMA的写时序

fdma_wready设置为1,当fdma_wbusy=0的时候代表FDMA的总线非忙,可以进行一次新的FDMA传输,这个时候可以设置fdma_wreq=1,同时设置fdma burst的起始地址和fdma_wsize本次需要传输的数据大小(以bytes为单位)。当fdma_wvalid=1的时候需要给出有效的数据,写入AXI总线。当最后一个数写完后,fdma_wvalid和fdma_wbusy变为0。

AXI4总线最大的burst lenth是256,而经过封装后,用户接口的fdma_size可以任意大小的,fdma ip内部代码控制每次AXI4总线的Burst长度,这样极大简化了AXI4总线协议的使用。

5.3:FDMA的读时序

fdma_rready设置为1,当fdma_rbusy=0的时候代表FDMA的总线非忙,可以进行一次新的FDMA传输,这个时候可以设置fdma_rreq=1,同时设置fdma burst的起始地址和fdma_rsize本次需要传输的数据大小(以bytes为单位)。当fdma_rvalid=1的时候需要给出有效的数据,写入AXI总线。当最后一个数写完后,fdma_rvalid和fdma_rbusy变为0。

同样对于AXI4总线的读操作,AXI4总线最大的burst lenth是256,而经过封装后,用户接口的fdma_size可以任意大小的,fdma ip内部代码控制每次AXI4总线的Burst长度,这样极大简化了AXI4总线协议的使用。

6 RTL仿真

6.1:仿真tb文件

DDR3的仿真文件在对应的FPGA工程路径uisrc/02_sim路径下,把仿真文件添加进来

6.2:仿真测试

7上板验证

添加fpga_pin.xdc文件,不同的开发板IO的约束定义一样,下图仅仅提供演示,具体以自己拿到的配套资料工程路径下的uisrc/04_pin/fpga_pin.xdc为准。当然读者也可以根据原理图自己定义约束。

 

通过ila在线逻辑分析仪IP-CORE,在线观察波形

通过在线逻辑分析仪查看结果,可以看到test_error信号一直低电平

标签:begin,12,end,fdma,DDR,总线,FDMA,DDR3
From: https://www.cnblogs.com/milianke/p/17931287.html

相关文章

  • 13基于fdma ddr多路视频数据构架方案
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1概述    基于AXI总线可以使用axi_interconnect的仲裁机制,同时接入多个基于AXI总线的IP,米联客的fdma采......
  • 12.27每日总结
    今天早上进行了软件构造的实验作业实验二:百度图像增强与特效SDK实验一、实验要求任务一:下载配置百度图像增强与特效的Java相关库及环境(占10%)。任务二:了解百度图像增强与特效相关功能并进行总结(占20%)。任务三:完成图像增强GUI相关功能代码并测试调用,要求上传自己的模糊照片进行......
  • 【2023-12-26】连岳摘抄
    23:59RMWS!                                                 ——XXX你认为,儿子长大后别给他压力,他一下可以继承几千万的资产,生活将更幸福。这是富裕阶层典型的误区,以......
  • 使用容器快速在阿里云 ECS 多节点上搭建 Citus 12.1 集群
    阿里云ECS机器节点这里我们使用两台同一区域的ECS机器。机器配置:2核2G。(ps:阿里云99元一年的活动)一台安装coordinator(协调器),这里内网IP为172.18.60.11一台安装worker,这里内网IP为172.18.60.12操作系统两台机器分别安装了厂商的AlibabaCloudLinu......
  • 12.30号直播:SSRF打穿内网
    本次的课程的内容为:1.SSRF漏洞原理2.SSRF靶场演示3.利用思路扩展 12月30日晚20:00,我们不见不散~  Ms08067安全实验室专注于网络安全知识的普及和培训,是专业的“图书出版+培训”的网络安全在线教育平台,专注于网络安全领域中高端人才培养。平台已开设Web安全零基础就......
  • 雅礼 2023.12.27 习题课记录
    雅礼2023.12.27习题课记录前言这一场罚时多,都是一些低级错误。好吧全都是水题。水题(只放代码)莫诺卡普参加了一场编程比赛,其中包括\(26\)个问题,从A到Z命名。问题按难度排序。此外,已知莫诺卡普可以在\(1\)分钟内解决问题A,在\(2\)分钟内解决问题B,\(\dots\),在\(2......
  • 2023-12-27:用go语言,店铺数量n,编号1~n, 人的数量m,编号1~m, 每个人有自己投票的店铺p,和改
    2023-12-27:用go语言,店铺数量n,编号1~n,人的数量m,编号1~m,每个人有自己投票的店铺p,和改投1号店的报价x。返回想让1号店铺成为人气最高的店,至少花多少钱?1<=p,n,m<=3000,1<=x<=10^9。1号店铺贿赂问题。来自华为OD。答案2023-12-27:来自左程云。灵捷3.5大体步骤如下:minC......
  • 汉源高科120路128路电话光端机+1路百兆网 PCM语音电话光纤收发器光PCM128A-ETH
    128路电话光端机+1路百兆网络HY-128P1FL是汉源高科(北京)科技有限公司采用自主知识产权的大规模集成电路,应用时分复用技术,将以太网信号和电话信号混合编码后在一对光纤上传输。实现热线电话业务传输,传输通道为光传输通道。该机采用2U机架式设计,集成度高,体积小,功耗低,工作可靠,安装使用......
  • centos 7.9 安装 python 3.10.5 和 openssl 3.0.12
    centos编译安装python和openssl安装环境:centos7.9:python3.10.5和openssl3.0.12centos6.10:python3.10.5和openssl1.1.1两个环境都能安装成功,可以正常使用。安装openssl下载地址下载后解压,进入到解压目录执行:./Configure--prefix=/usr/local/openssl3.......
  • 12-Mysql的日志管理
    一、mysql常见日志二、错误日志配置方法:[mysqld]log-error=/data/mysql/mysql.log查看配置方式:mysql>showvariableslike'%log%error%';作用:记录mysql数据库的一般状态信息及报错信息,是我们对于数据库常规报错处理的常用日志,默认在data目录下三、一般查询......