请选择 进入手机版 | 继续访问电脑版
[X]关闭

3-1-04 FPGA使用fdma读写DDR

文档创建者:uisrc
浏览次数:548
最后更新:2023-12-30
文档课程分类
AMD: FPGA部分(2024样板资料) » 2_FPGA实验篇(仅旗舰) » 2-FPGA PL DDR使用
软件版本:vitis2021.1(vivado2021.1)
操作系统:WIN10 64bit
硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA
登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!
4.1概述   
在前文的实验中我们详细介绍了FDMA的使用方法, 前面一节课演示了FDMA读写AXI-BRAM,本文我们继续使用FDMA实现对AXI-MIG的读写,以此读写DDR。由于FDMA的读写操作都是基于AXI总线,所以用户代码部分一致性也非常好,我们的状态机都不需要做修改,基本上只要把前文的BRAM IP换成MIG IP即可。
本文实验目的:
1:利用uiFDMA3.2提供的接口,编写DDR测试程序
2:对MIG接口读写仿真和测试
本系统中先将测试数据通过AXI-DMA写入DDR,再通过AXI-DMA将DDR3中数据读出。将读写数据进行对比。通过在线逻辑分析仪抓取读写数据测试读写正确性。
2504661-20231230140049761-1990588658.jpg
4.3基于图形化逻辑设计
搭建过程我们不再详细描述,不清楚的可以参考前"使用FDMA读写AXI-BRAM",搭建好的工程如下
2504661-20231230140050223-1610416948.jpg
我们主要看下MIG的配置
1:MIG配置
2504661-20231230140050723-577971732.jpg
2504661-20231230140051225-1678234158.jpg
2504661-20231230140056912-1997547930.jpg
2504661-20231230140057454-1085465066.jpg
2504661-20231230140058099-488578222.jpg

2504661-20231230140058616-1209727581.jpg
2504661-20231230140059160-420166924.jpg
继续该页面设置
2504661-20231230140059757-676322603.jpg
2504661-20231230140100323-1832024133.jpg

2504661-20231230140100731-1836930109.jpg
2504661-20231230140101122-1497346088.jpg

2504661-20231230140101493-37267820.jpg 2504661-20231230140101937-1807517555.jpg
2504661-20231230140102442-604794606.jpg
继续NEXT,知道下页
2504661-20231230140108056-1586171617.jpg
2:编写FDMA的DDR测试代码
以下程序中是fdma读写操作的具体实现,先写入一定数据到DDR中,然后再读出,对比是否有错误,几个关键参数:
TEST_MEM_SIZE:定义了测试内从空间的大小,以byte为单位,是整数倍的FDMA_BURST_LEN *(fdma_wdata/8)。
FDMA_BURST_LEN:定义每次FDMA传输的长度,这个长度是整数倍的fdma_wdata或者fdma_rdata。
ADDR_MEM_OFFSET:代码了内从访问的起始地址。

`timescale 1ns / 1ps
/*******************************MILIANKE*******************************
*Company : MiLianKe Electronic Technology Co., Ltd.
*Create Date: 2021/10/15
*Module Name:
*File Name:
*Description:
*config sensor resgister
*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) IO_ input output
*4) S_ system internal signal
*5) _n activ low
*6) _dg debug signal
*7) _r delay or register
*8) _s state mechine
*********************************************************************/
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 sysclk
);

wire [31:0]   fdma_raddr;
reg           fdma_rareq;
wire          fdma_rbusy;
wire [127:0]  fdma_rdata;
wire [15:0]   fdma_rsize;
wire          fdma_rvalid;
wire [31:0]   fdma_waddr;
reg           fdma_wareq;
wire          fdma_wbusy;
wire [127:0]  fdma_wdata;
wire [15:0]   fdma_wsize;
wire          fdma_wvalid;
wire [0:0]    fdma_rstn;
wire          ui_clk;

parameter TEST_MEM_SIZE   = 32'd1024*1024*256;
parameter FDMA_BURST_LEN  = 16'd512;
parameter ADDR_MEM_OFFSET = 0;
parameter ADDR_INC = FDMA_BURST_LEN * 16;

parameter WRITE1 = 0;
parameter WRITE2 = 1;
parameter WAIT   = 2;
parameter READ1  = 3;
parameter READ2  = 4;

reg [31: 0] t_data;
reg [31: 0] fdma_waddr_r;
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;
assign fdma_wdata ={t_data,t_data,t_data,t_data};

reg [8:0] rst_cnt = 0;

always @(posedge ui_clk)
    if(~fdma_rstn)begin
        rst_cnt <=0;
    end
    else begin
        if(rst_cnt[8] == 1'b0)
            rst_cnt <= rst_cnt + 1'b1;
        else
            rst_cnt <= rst_cnt;
    end

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
            if(fdma_waddr_r==TEST_MEM_SIZE) fdma_waddr_r<=0;
                if(!fdma_wbusy)begin
                    fdma_wareq  <= 1'b1;
                    t_data  <= 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 <= WAIT;
                 t_data  <= 32'd0;
            end
            else if(fdma_wvalid) begin
                t_data <= t_data + 1'b1;
            end
        end
        WAIT:begin//not needed
            T_S <= READ1;
        end
        READ1:begin
            if(!fdma_rbusy)begin
                fdma_rareq  <= 1'b1;
                t_data   <= 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;
                 t_data  <= 32'd0;
                 fdma_waddr_r  <= fdma_waddr_r + ADDR_INC;//128/8=16
            end
            else if(fdma_rvalid) begin
                t_data <= t_data + 1'b1;
            end
        end  
        default:
            T_S <= WRITE1;   
        endcase
    end
  end

reg test_error;

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_i_fdma_raddr(fdma_raddr),
        .FDMA_S_0_i_fdma_rareq(fdma_rareq),
        .FDMA_S_0_o_fdma_rbusy(fdma_rbusy),
        .FDMA_S_0_o_fdma_rdata(fdma_rdata),
        .FDMA_S_0_i_fdma_rready(1'b1),
        .FDMA_S_0_i_fdma_rsize(fdma_rsize),
        .FDMA_S_0_o_fdma_rvalid(fdma_rvalid),
        .FDMA_S_0_i_fdma_waddr(fdma_waddr),
        .FDMA_S_0_i_fdma_wareq(fdma_wareq),
        .FDMA_S_0_o_fdma_wbusy(fdma_wbusy),
        .FDMA_S_0_i_fdma_wdata(fdma_wdata),
        .FDMA_S_0_i_fdma_wready(1'b1),
        .FDMA_S_0_i_fdma_wsize(fdma_wsize),
        .FDMA_S_0_o_fdma_wvalid(fdma_wvalid),  
        .fdma_rstn(fdma_rstn),
        .sysclk(sysclk),  
        .ui_clk(ui_clk));

endmodule


3:程序分析3-1:总流程图
如下图所示,本文的程序工作流程如下,包括请求写数据、FDMA收到写数据请求、写数据完成、请求读数据、FDMA收到读数据请求和读数据完成、校验。
2504661-20231230140108553-188950179.jpg
以下是fdma_test.v中读写fdma ip接口的状态机,由于读写代码对称,对fdma的读写操作可以分为2步完成,分别是:1:发送读/写请求 2:读/写有效数据。 2504661-20231230140108937-1538384067.jpg

3-2:FDMA的写时序
2504661-20231230140114283-327319106.jpg
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总线协议的使用。
3-3:FDMA的读时序
2504661-20231230140114673-264553645.jpg
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总线协议的使用。
4:地址空间分配
配置完成后需要注意地址空间分配,FDMA IP的内存起始地址从0开始
2504661-20231230140115063-2048255810.jpg
4.4RTL仿真1:仿真tb文件
DDR3的仿真文件在对应的FPGA工程路径uisrc/02_sim路径下,把仿真文件添加进来
2504661-20231230140115558-515078162.jpg
2504661-20231230140116090-1389447096.jpg
2:仿真测试
2504661-20231230140116594-1371878131.jpg
4.5上板验证
添加fpga_pin.xdc文件,不同的开发板IO的约束定义一样,下图仅仅提供演示,具体以自己拿到的配套资料工程路径下的uisrc/04_pin/fpga_pin.xdc为准。当然读者也可以根据原理图自己定义约束。
2504661-20231230140116990-502115884.jpg
通过ila在线逻辑分析仪IP-CORE,在线观察波形
2504661-20231230140117410-254219242.jpg
通过在线逻辑分析仪查看结果,可以看到test_error信号一直低电平
2504661-20231230140117801-524266932.jpg

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则