[X]关闭

米联客-XILINX-H3_CZ08_7100] FPGA_AXI总线入门连载-09 使用 fdma 读写 DDR

文档创建者:FPGA课程
浏览次数:38
最后更新:2024-10-15
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 3-FPGA AXI 总线入门
本帖最后由 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 ”,搭建好的工程如下
d090b34a9dd9416b9c268d749c7f34d9.jpg
我们主要看下 MIG 的配置我们主要看下 MIG 的配置

51bce2c34e2447f0b8e9719c6d943e88.jpg

eaaab967eb084699a3292130f254d279.jpg

993c55686ff34456bfc3380fed430d48.jpg

e0bec55042fc442084ec2e06398b6258.jpg

c9d1c3e22de14a7e92e7df76f560707c.jpg

0973b5032c31475fa32e4ee7300d1816.jpg

568b65485d2f4b93a95ebe526ad56d33.jpg

fb994717a65642dbb0f58d9a89b1156e.jpg

05f1bbda14014523badf0c9e78a2a47c.jpg
1b68bc1bac5e47968e461a50ba0890b1.jpg
db42d745370046e3a0f55dcec986430a.jpg

83a377060306499090a252c8d4f19fb8.jpg

39c5a8fe48824b6091a5423749cb31a6.jpg

9f21db689f8f4ff4b791e97344163d82.jpg

1eb57f3479af4100b9ba808dea3414bc.jpg
88f4edb9d2024447955af6414959ed87.jpg
3 编写 FDMA 的 DDR 测试代码
以下程序中是 fdma 读写操作的具体实现,先写入一定
  1. /*******************************MILIANKE*******************************
  2. *Company : MiLianKe Electronic Technology Co., Ltd.
  3. *WebSite:https://www.milianke.com
  4. *TechWeb:https://www.uisrc.com
  5. *tmall-shop:https://milianke.tmall.com
  6. *jd-shop:https://milianke.jd.com
  7. *taobao-shop1: https://milianke.taobao.com
  8. *Create Date: 2019/12/17
  9. *Module Name:fdma_ddr_test
  10. *File Name:fdma_ddr_test.v
  11. *Description:
  12. *The reference demo provided by Milianke is only used for learning.
  13. *We cannot ensure that the demo itself is free of bugs, so users
  14. *should be responsible for the technical problems and consequences
  15. *caused by the use of their own products.
  16. *Copyright: Copyright (c) MiLianKe
  17. *All rights reserved.
  18. *Revision: 1.0
  19. *Signal description
  20. *1) _i input
  21. *2) _o output
  22. *3) _n activ low
  23. *4) _dg debug signal
  24. *5) _r delay or register
  25. *6) _s state mechine
  26. *********************************************************************/
  27. `timescale 1ns / 1ps
  28. module fdma_ddr_test(
  29. output [14:0]   DDR3_addr,
  30. output [2:0]    DDR3_ba,
  31. output          DDR3_cas_n,
  32. output [0:0]    DDR3_ck_n,
  33. output [0:0]    DDR3_ck_p,
  34. output [0:0]    DDR3_cke,
  35. output [0:0]    DDR3_cs_n,
  36. output [7:0]    DDR3_dm,
  37. inout [63:0]    DDR3_dq,
  38. inout [7:0]     DDR3_dqs_n,
  39. inout [7:0]     DDR3_dqs_p,
  40. output [0:0]    DDR3_odt,
  41. output          DDR3_ras_n,
  42. output          DDR3_reset_n,
  43. output          DDR3_we_n,
  44. output          init_calib_complete,
  45. input           sysclk_clk_n,
  46. input          sysclk_clk_p

  47. );
  48. wire [31:0]   fdma_raddr;
  49. reg           fdma_rareq;
  50. wire          fdma_rbusy;
  51. wire [127:0]  fdma_rdata;
  52. wire [15:0]   fdma_rsize;
  53. wire          fdma_rvalid;
  54. wire [31:0]   fdma_waddr;
  55. reg           fdma_wareq;
  56. wire          fdma_wbusy;
  57. wire [127:0]  fdma_wdata;
  58. wire [15:0]   fdma_wsize;
  59. wire          fdma_wvalid;
  60. wire [0:0]    fdma_rstn;
  61. wire          ui_clk;
  62. wire        sysclk_clk_n;
  63. wire        sysclk_clk_p;


  64. parameter TEST_MEM_SIZE   = 32'd1024*1024*1024;//1GB
  65. parameter FDMA_BURST_LEN  = 16'd512;
  66. parameter ADDR_MEM_OFFSET = 0;
  67. parameter ADDR_INC = FDMA_BURST_LEN * 16;

  68. parameter WRITE1 = 0;
  69. parameter WRITE2 = 1;
  70. parameter WAIT   = 2;
  71. parameter READ1  = 3;
  72. parameter READ2  = 4;

  73. reg [31: 0] t_data;
  74. reg [31: 0] fdma_waddr_r;
  75. reg [2  :0] T_S = 0;

  76. assign fdma_waddr = fdma_waddr_r + ADDR_MEM_OFFSET;
  77. assign fdma_raddr = fdma_waddr;

  78. assign fdma_wsize = FDMA_BURST_LEN;
  79. assign fdma_rsize = FDMA_BURST_LEN;
  80. assign fdma_wdata ={t_data,t_data,t_data,t_data};
  81.   
  82. reg [8:0] rst_cnt = 0;

  83. always @(posedge ui_clk)
  84.     if((fdma_rstn & init_calib_complete)==1'b0)begin
  85.         rst_cnt <=0;
  86.     end
  87.     else begin
  88.         if(rst_cnt[8] == 1'b0)
  89.             rst_cnt <= rst_cnt + 1'b1;
  90.         else
  91.             rst_cnt <= rst_cnt;
  92.     end

  93. always @(posedge ui_clk)begin
  94.     if(rst_cnt[8] == 1'b0)begin
  95.         T_S <=0;   
  96.         fdma_wareq  <= 1'b0;
  97.         fdma_rareq  <= 1'b0;
  98.         t_data<=0;
  99.         fdma_waddr_r <=0;      
  100.     end
  101.     else begin
  102.         case(T_S)      
  103.         WRITE1:begin
  104.             if(fdma_waddr_r>TEST_MEM_SIZE) fdma_waddr_r<=0;
  105.                 if(!fdma_wbusy)begin
  106.                     fdma_wareq  <= 1'b1;
  107.                     t_data  <= 0;
  108.                 end
  109.                 if(fdma_wareq&&fdma_wbusy)begin
  110.                     fdma_wareq  <= 1'b0;
  111.                     T_S         <= WRITE2;
  112.                 end
  113.         end
  114.         WRITE2:begin
  115.             if(!fdma_wbusy) begin
  116.                  T_S <= WAIT;
  117.                  t_data  <= 32'd0;
  118.             end
  119.             else if(fdma_wvalid) begin
  120.                 t_data <= t_data + 1'b1;
  121.             end
  122.         end
  123.         WAIT:begin//not needed
  124.             T_S <= READ1;
  125.         end
  126.         READ1:begin
  127.             if(!fdma_rbusy)begin
  128.                 fdma_rareq  <= 1'b1;
  129.                 t_data   <= 0;
  130.             end
  131.             if(fdma_rareq&&fdma_rbusy)begin
  132.                  fdma_rareq  <= 1'b0;
  133.                  T_S         <= READ2;
  134.             end
  135.         end
  136.         READ2:begin
  137.             if(!fdma_rbusy) begin
  138.                  T_S <= WRITE1;
  139.                  t_data  <= 32'd0;
  140.                  fdma_waddr_r  <= fdma_waddr_r + ADDR_INC;//128/8=16
  141.             end
  142.             else if(fdma_rvalid) begin
  143.                 t_data <= t_data + 1'b1;
  144.             end
  145.         end   
  146.         default:
  147.             T_S <= WRITE1;     
  148.         endcase
  149.     end
  150.   end
  151.   
  152. wire test_error = (fdma_rvalid && (t_data[15:0] != fdma_rdata[15:0]));

  153. ila_0 ila_dbg (
  154.         .clk(ui_clk),
  155.         .probe0({fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wbusy}),
  156.         .probe1({fdma_rdata[15:0],t_data[15:0],fdma_rvalid,fdma_rbusy,T_S,test_error})
  157. );

  158.   system system_i
  159.        (.DDR3_addr(DDR3_addr),
  160.         .DDR3_ba(DDR3_ba),
  161.         .DDR3_cas_n(DDR3_cas_n),
  162.         .DDR3_ck_n(DDR3_ck_n),
  163.         .DDR3_ck_p(DDR3_ck_p),
  164.         .DDR3_cke(DDR3_cke),
  165.         .DDR3_cs_n(DDR3_cs_n),
  166.         .DDR3_dm(DDR3_dm),
  167.         .DDR3_dq(DDR3_dq),
  168.         .DDR3_dqs_n(DDR3_dqs_n),
  169.         .DDR3_dqs_p(DDR3_dqs_p),
  170.         .DDR3_odt(DDR3_odt),
  171.         .DDR3_ras_n(DDR3_ras_n),
  172.         .DDR3_reset_n(DDR3_reset_n),
  173.         .DDR3_we_n(DDR3_we_n),
  174.         .FDMA_S_0_fdma_raddr(fdma_raddr),
  175.         .FDMA_S_0_fdma_rareq(fdma_rareq),
  176.         .FDMA_S_0_fdma_rbusy(fdma_rbusy),
  177.         .FDMA_S_0_fdma_rdata(fdma_rdata),
  178.         .FDMA_S_0_fdma_rready(1'b1),
  179.         .FDMA_S_0_fdma_rsize(fdma_rsize),
  180.         .FDMA_S_0_fdma_rvalid(fdma_rvalid),
  181.         .FDMA_S_0_fdma_waddr(fdma_waddr),
  182.         .FDMA_S_0_fdma_wareq(fdma_wareq),
  183.         .FDMA_S_0_fdma_wbusy(fdma_wbusy),
  184.         .FDMA_S_0_fdma_wdata(fdma_wdata),
  185.         .FDMA_S_0_fdma_wready(1'b1),
  186.         .FDMA_S_0_fdma_wsize(fdma_wsize),
  187.         .FDMA_S_0_fdma_wvalid(fdma_wvalid),
  188.         .init_calib_complete(init_calib_complete),
  189.         .fdma_rstn(fdma_rstn),
  190.         .sysclk_clk_n(sysclk_clk_n),
  191.         .sysclk_clk_p(sysclk_clk_p),
  192.   
  193.         .ui_clk(ui_clk));
  194. 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 路径下,把仿真文件添加进来

783a1c33dd054918be2d1eedbdd4c7d2.jpg
8ec40473a9fc441baa3884bea45eaf3e.jpg
4.2 仿真测试
973a8534690d43d0974cb69851d098b1.jpg

5程序分析
5.1 总流程图
如下图所示,本文的程序工作流程如下,包括请求写数据、FDMA 收到写数据请求、写数据完成、请求读数据、 FDMA 收到读数据请求和读数据完成、校验。
98f97f1e7dea480abb2c99f075ae555f.jpg
6编译测试
添加 fpga_pin.xdc 文件,不同的开发板 IO 的约束定义一样,下图仅仅提供演示,具体以自己拿到的配套资料工 程路径下的 uisrc/04_pin/fpga_pin.xdc 为准。当然读者也可以根据原理图自己定义约束。
1246c5a0bd59443991e313e38a0a44cc.jpg
通过 ila 在线逻辑分析仪 IP-CORE ,在线观察波形

42e97d1380b5467a98729de621ef0536.jpg
通过在线逻辑分析仪查看结果,可以看到 test_error 信号一直低电平
28d270c4f02a4d658667eccbbe1e9d65.jpg
6.1FDMA 的读写时序
以下是 fdma_test.v 中读写 fdma ip 接口的状态机,由于读写代码对称,对 fdma 的读写操作可以分为 2 步完成,分别 是:1:发送读/写请求 2:读/写有效数据。
de0ad15286184533ba215b63263257e8.jpg

1:FDMA 的写时序
56e64b8e5b544ae09ffe86f1f87efc7a.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 总线协议的使用。
2:FDMA 的读时序
42c9fb6b1e254dc5a2548f6df0a40e3e.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 总线协议的使用。

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

本版积分规则