本帖最后由 FPGA课程 于 2024-10-15 18:39 编辑
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA
实验平台:米联客-MLK-H3-CZ08-7100开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1 概述在前文的实验中我们详细介绍了 FDMA 的使用方法, 以及使用了AXI-BRAM 演示了 FDMA 的使用,现在我们已经 掌握了 FDMA 的使用,本文我们继续使用FDMA 实现对AXI-MIG 的读写,以此读写 DDR。由于 FDMA 的读写操作都是基 于 AXI 总线,所以用户代码部分一致性也非常好,我们的状态机都不需要做修改,基本上只要把前文的 BRAM IP 换 成 MIG IP 即可。 本文实验目的: 1:利用 uiFDMA3.0 提供的接口,编写 DDR 测试程序 2:对 MIG 接口读写仿真和测试 2PL 图形化设计搭建过程我们不再详细描述,不清楚的可以参考前“08 使用FDMA 读写 AXI-BRAM ”,搭建好的工程如下
我们主要看下 MIG 的配置我们主要看下 MIG 的配置
3 编写 FDMA 的 DDR 测试代码以下程序中是 fdma 读写操作的具体实现,先写入一定 - /*******************************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 [14:0] DDR3_addr,
- output [2:0] DDR3_ba,
- output DDR3_cas_n,
- output [0:0] DDR3_ck_n,
- output [0:0] DDR3_ck_p,
- output [0:0] DDR3_cke,
- output [0:0] DDR3_cs_n,
- output [7:0] DDR3_dm,
- inout [63:0] DDR3_dq,
- inout [7:0] DDR3_dqs_n,
- inout [7:0] DDR3_dqs_p,
- output [0:0] DDR3_odt,
- output DDR3_ras_n,
- output DDR3_reset_n,
- output DDR3_we_n,
- output init_calib_complete,
- input sysclk_clk_n,
- input sysclk_clk_p
- );
- 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;
- wire sysclk_clk_n;
- wire sysclk_clk_p;
- parameter TEST_MEM_SIZE = 32'd1024*1024*1024;//1GB
- 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 & init_calib_complete)==1'b0)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
-
- wire test_error = (fdma_rvalid && (t_data[15:0] != fdma_rdata[15:0]));
- 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_addr(DDR3_addr),
- .DDR3_ba(DDR3_ba),
- .DDR3_cas_n(DDR3_cas_n),
- .DDR3_ck_n(DDR3_ck_n),
- .DDR3_ck_p(DDR3_ck_p),
- .DDR3_cke(DDR3_cke),
- .DDR3_cs_n(DDR3_cs_n),
- .DDR3_dm(DDR3_dm),
- .DDR3_dq(DDR3_dq),
- .DDR3_dqs_n(DDR3_dqs_n),
- .DDR3_dqs_p(DDR3_dqs_p),
- .DDR3_odt(DDR3_odt),
- .DDR3_ras_n(DDR3_ras_n),
- .DDR3_reset_n(DDR3_reset_n),
- .DDR3_we_n(DDR3_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),
- .init_calib_complete(init_calib_complete),
- .fdma_rstn(fdma_rstn),
- .sysclk_clk_n(sysclk_clk_n),
- .sysclk_clk_p(sysclk_clk_p),
-
- .ui_clk(ui_clk));
- endmodule
复制代码
数据到 DDR 中,然后再读出,对比是否有错误,几个关键参数: TEST_MEM_SIZE:定义了测试内从空间的大小,以 byte 为单位,是整数倍的FDMA_BURST_LEN *(fdma_wdata/8)。 FDMA_BURST_LEN:定义每次 FDMA 传输的长度,这个长度是整数倍的 fdma_wdata 或者 fdma_rdata。 ADDR_MEM_OFFSET:代码了内从访问的起始地址。 4RTL 仿真
4.1 仿真 tb 文件
DDR3 的仿真文件在对应的 FPGA 工程路径 uisrc/02_sim 路径下,把仿真文件添加进来
4.2 仿真测试
5程序分析
5.1 总流程图如下图所示,本文的程序工作流程如下,包括请求写数据、FDMA 收到写数据请求、写数据完成、请求读数据、 FDMA 收到读数据请求和读数据完成、校验。
6编译测试添加 fpga_pin.xdc 文件,不同的开发板 IO 的约束定义一样,下图仅仅提供演示,具体以自己拿到的配套资料工 程路径下的 uisrc/04_pin/fpga_pin.xdc 为准。当然读者也可以根据原理图自己定义约束。
通过 ila 在线逻辑分析仪 IP-CORE ,在线观察波形
通过在线逻辑分析仪查看结果,可以看到 test_error 信号一直低电平
6.1FDMA 的读写时序以下是 fdma_test.v 中读写 fdma ip 接口的状态机,由于读写代码对称,对 fdma 的读写操作可以分为 2 步完成,分别 是:1:发送读/写请求 2:读/写有效数据。
1: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 总线协议的使用。 2: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 总线协议的使用。
|