[X]关闭
1

S03-CH01基于FDMA内存读写测试

摘要: FDMA是MSXBO(米联客的)基于AXI4总线协议定制的一个DMA控制器。有了这个IP我们可以统一实现用FPGA代码直接读写PL的DDR或者ZYNQ PS的DDR。 如果用过ZYNQ的都知道,要直接操作PS的DDR 通常是DMA 或者VDMA,然而 ...

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

1.1概述

      FDMA是MSXBO(米联客的)基于AXI4总线协议定制的一个DMA控制器。有了这个IP我们可以统一实现用FPGA代码直接读写PL的DDR或者ZYNQ PS的DDR。

      如果用过ZYNQ的都知道,要直接操作PS的DDR 通常是DMA 或者VDMA,然而用过XILINX 的DMA IP 和VDMA IP,总有一种遗憾,那就是不够灵活,还需要对寄存器配置,真是麻烦。对于我们搞FPGA的人来说,最喜欢直接了当,直接用FPGA代码搞定。现在XILINX 的总线接口是AXI4总线,那么熟练自定义AXI4 IP挂到总线上就非常方便了。基于这个目的,本小编定义了一个基于AXI4 FULL MASTER的IP,暂且取名为MSXBO_FDMA。

     通过这个IP我们可以方便地进行AXI4 FULL MASTER的操作,比如我们经常要读写DDR,那么只要挂到AXI4总线上就可以利用这个IP实现。

     以下是小编展示了一种在ZYNQ上的读写PS DDR测试方案。

1.2基于FDMA搭建的BD工程

     首先看下基于FDMA搭建的BD工程,这里使用的是ZYNQ IP搭建。

1.3 ZYNQ PS IP配置

      和使用PL DDR MIG 不同,MZ7X是ZYNQ芯片只有PS有DDR 所以访问DDR需要配置ZYNQ IP这样配置好后就可以通过AXI总线范围PS的DDR了。

      配置输入时钟

     配置DDR 

   仅配置HP接口

  地址空间分配

1.3编写FDMA测试代码

首先右击BD 并且单击

其次继续右击BD文件,选择Create HDL Wrapper

最后修改Wrapper并且添加测试代码,测试代码如下

`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////

// Company:CZ123 MSXBO www.osrc.cn

// Engineer: tjy

// Create Date: 2019/04/02 12:39:25

// Design Name:

// Module Name: fdma_top

// Project Name: AXI_FDMA

// Target Devices:

// Tool Versions: VIVADO

// Description: test DDR

// Dependencies:

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

//////////////////////////////////////////////////////////////////////////////////

module fdma_top(

inout [14:0]DDR_addr,

inout [2:0]DDR_ba,

inout DDR_cas_n,

inout DDR_ck_n,

inout DDR_ck_p,

inout DDR_cke,

inout DDR_cs_n,

inout [3:0]DDR_dm,

inout [31:0]DDR_dq,

inout [3:0]DDR_dqs_n,

inout [3:0]DDR_dqs_p,

inout DDR_odt,

inout DDR_ras_n,

inout DDR_reset_n,

inout DDR_we_n,

inout FIXED_IO_ddr_vrn,

inout FIXED_IO_ddr_vrp,

inout [53:0]FIXED_IO_mio,

inout FIXED_IO_ps_clk,

inout FIXED_IO_ps_porb,

inout FIXED_IO_ps_srstb

);

 

  wire [0:0]ui_rstn;

  wire ui_clk;

  //-----------------fmda signals--------------------------------------

  wire [31:0] pkg_wr_addr;

 (*mark_debug = "true"*)  wire  [31:0] pkg_wr_data;

 (*mark_debug = "true"*) (* KEEP = "TRUE" *)  reg         pkg_wr_areq;

 (*mark_debug = "true"*)  wire        pkg_wr_en;

 (*mark_debug = "true"*)  wire        pkg_wr_last;

  wire [31:0] pkg_wr_size;

  wire [31:0] pkg_rd_addr;

 (*mark_debug = "true"*)  wire  [31:0] pkg_rd_data;

 (*mark_debug = "true"*) (* KEEP = "TRUE" *) reg         pkg_rd_areq;

 (*mark_debug = "true"*)  wire        pkg_rd_en;

 (*mark_debug = "true"*)  wire        pkg_rd_last;

  wire [31:0] pkg_rd_size;

 //---------------------------------------------------------------------

  reg [31:0]pkg_wr_cnt;

 (*mark_debug = "true"*) (* KEEP = "TRUE" *) reg [31:0]pkg_rd_cnt;

 (*mark_debug = "true"*) (* KEEP = "TRUE" *) reg [1:0] T_S;

 

  reg [31:0] pkg_addr;

 

  parameter WRITE1 = 0;

  parameter WRITE2 = 1;

  parameter READ1  = 2;

  parameter READ2  = 3;

  //-----------------  

  assign pkg_wr_size = 1024;

  assign pkg_rd_size = 1024;

  

  assign pkg_wr_data = pkg_wr_cnt;

  (*mark_debug = "true"*) wire test_error;

  assign test_error = (pkg_rd_en && (pkg_rd_cnt != pkg_rd_data));

  

  parameter DDR_BASE = (10*1024*1024);

  

  assign pkg_wr_addr = pkg_addr+ DDR_BASE;

  assign pkg_rd_addr = pkg_addr+ DDR_BASE;

  

  always @(posedge ui_clk)

  begin

    if(!ui_rstn)begin

        T_S <=0;

        pkg_wr_areq <= 1'b0;

        pkg_rd_areq <= 1'b0;         

        pkg_wr_cnt<=0;

        pkg_rd_cnt<=0;

        pkg_addr<=0;       

    end

    else begin

        case(T_S)

        WRITE1:begin

            if(pkg_addr>=32'd536870911) pkg_addr<=0;

            pkg_wr_areq  <= 1'b1;

            T_S <= WRITE2;

        end

        WRITE2:begin

            pkg_wr_areq  <= 1'b0;

            if(pkg_wr_last) begin

                 T_S <= READ1;

                 pkg_wr_cnt <= 32'd0;

            end

            else if(pkg_wr_en) begin

                pkg_wr_cnt <= pkg_wr_cnt + 1'b1;

            end

        end

        READ1:begin

            pkg_rd_areq <= 1'b1;

            T_S <= READ2;   

        end   

        READ2:begin

            pkg_rd_areq <= 1'b0;

            if(pkg_rd_last) begin

                T_S <= WRITE1;  

                pkg_addr <= pkg_addr + 4096;

                pkg_rd_cnt <= 32'd0;

            end

            else if(pkg_rd_en) begin

                pkg_rd_cnt <= pkg_rd_cnt + 1'b1;

            end

        end             

        endcase

    end

  end

  

system system_i

       (.DDR_addr(DDR_addr),

        .DDR_ba(DDR_ba),

        .DDR_cas_n(DDR_cas_n),

        .DDR_ck_n(DDR_ck_n),

        .DDR_ck_p(DDR_ck_p),

        .DDR_cke(DDR_cke),

        .DDR_cs_n(DDR_cs_n),

        .DDR_dm(DDR_dm),

        .DDR_dq(DDR_dq),

        .DDR_dqs_n(DDR_dqs_n),

        .DDR_dqs_p(DDR_dqs_p),

        .DDR_odt(DDR_odt),

        .DDR_ras_n(DDR_ras_n),

        .DDR_reset_n(DDR_reset_n),

        .DDR_we_n(DDR_we_n),

        .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),

        .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),

        .FIXED_IO_mio(FIXED_IO_mio),

        .FIXED_IO_ps_clk(FIXED_IO_ps_clk),

        .FIXED_IO_ps_porb(FIXED_IO_ps_porb),

        .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),

 

        .pkg_wr_addr(pkg_wr_addr),

        .pkg_wr_data(pkg_wr_data),

        .pkg_wr_areq(pkg_wr_areq),

        .pkg_wr_en  (pkg_wr_en),

        .pkg_wr_last(pkg_wr_last),

        .pkg_wr_size(pkg_wr_size),

                

        .pkg_rd_addr(pkg_rd_addr),

        .pkg_rd_data(pkg_rd_data),

        .pkg_rd_areq(pkg_rd_areq),  

        .pkg_rd_en  (pkg_rd_en),   

        .pkg_rd_last(pkg_rd_last),

        .pkg_rd_size(pkg_rd_size),

 

        .ui_clk(ui_clk),

        .fdma_rstn(ui_rstn)    

        );

        

endmodule

以上代码中需要注意红色部分代码,PS的DDR 地址需要偏移大约1MB ,这里偏移10MB并且确保不和应用程序的DDR空间冲突。

1.5测试代码状态机分析

  1. WRITE1状态:为了测试整个DDR的存储控件,所以先计算DDR大小,536870911正好是一片512MB DDR的大小。根据之前BD里面FDMA的参数设置,一次AXI4 burst大小为256,那么每次传输1024byte(256x32/8)。我们设置pkg_wr_size 和pkg_rd_size大小为1024,那么这里每次parket 传输大小为4096bytes(1024x32bit/8)。pkg_wr_size 和pkg_rd_size的大小是以32bit计算。pkg_wr_size 和pkg_rd_size大小的设置需要注意pkg_wr_size需要是FDMA里面 AXI BURST LEN的整数倍。
  2. WRITE2状态: WRITE1通过设置pkg_wr_areq为1持续1个时钟周期,后进入WRITE2状态机,并且启动启动一次FDMA的parket传输。当pkg_wr_last为1的时候表示一次parket传输传输结束。在WRITE2状态机中使用了一个计数器,把计数器的值写入到DDR中。
  3. READ1状态:在READ1状态设置pkg_rd_areq为1启动一次FMDA的parket read 传输,之后进入READ2状态。
  4. READ2状态:当pkg_rd_las 为1代表一次read传输结束,并且地址空间地址增加。在READ2状态,通过一个计数器计数并且对比和从DDR里面读出的数据,看是否有错误。

assign test_error = (pkg_rd_en && (pkg_rd_cnt != pkg_rd_data));

1.6测试结果

      导入硬件工程到SDK 并且新建一个helloworld程序,之后下载程序测试,如果读者这个地方不清楚,可以先学习ZYNQ基础方面的教程内容,掌握如何调试ZYNQ。

      可以看到上图中error 信号一直为0代表数据读写对比没有错误。再看pkg_wr_en和pkg_rd_en信号,可以看到他们是每次burst了4次每次的长度是256。证明我们的FDMA工作正常,测试程序工作正常。下面放大数据部分。

       上图是写操作往内存里面写数据。

      上图是读操作放大后看到的数据分别是计数器和从内存里读取到的数据。


路过

雷人

握手

鲜花

鸡蛋
发表评论

最新评论

引用 Wyuan 2020-4-23 10:46
怎么得到MSXBO_FDMA ip?

查看全部评论(1)

本文作者
2019-9-10 09:59
  • 1
    粉丝
  • 4360
    阅读
  • 1
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
热门评论
排行榜