[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_PL-DDR篇连载-03使用fdma读写axi-bram测试

文档创建者:FPGA课程
浏览次数:629
最后更新:2024-09-10
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 2-FPGA PL DDR使用
本帖最后由 FPGA课程 于 2024-9-10 09:02 编辑

​ 软件版本: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是米联客基于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.2的FPGA工程设计
2:利用uiFDMA3.2提供的接口,编写BRAM测试程序
3:对AXI-BRAM读写仿真和测试
我们第一入门的demo选择对BRAM仿真测试,是因为不管是仿真还是编译测试,对AXI-BRAM速度都非常快,我们在下面一个DEMO中会给出对DDR的读写仿真测试。
2系统框图
本系统中先将测试数据通过Milianke UiFDMA写入Bram,再通过Milianke UiFDMA将Bram中数据读出。将读写数据进行对比。通过在线逻辑分析仪抓取读写数据测试读写正确性。
1ad965cc2eea436e8b628dc994bfec45.jpg
3创建图形化逻辑工程1:创建工程命名为fpga_prj
双击VIVADO软件图标启动VIVADO
ca276ac8a1da4d798985c6b8ee7584ba.jpg

设置工程路径,并且命名工程名为fpga_prj
ec3563b6e7e44b51952391e435fe681d.jpg
335417b8b6e446a2805f48b07ea8a1cf.jpg
以下设置FPGA或者ZYNQ或者ZYNQ-MPSOC芯片型号,必须和开发板保持一致,如果不清楚的请查阅自己开发板的硬件手册或者根据选型手册上参数确认
d2dd35528df042368fc2771d3bf4b06d.jpg
135350eb963c45bf9344a0b9bc879d47.jpg
18885d4f3e424c9eade5cacb1c2a8cb4.jpg
2:创建Block Design并且命名为system
bfe5e478d69e40b5a2196e55cbf80b90.jpg

如下图所示,图形化system就是一个代码容器,接着我们要添加一些图像化的IP
aad5554b061a41ce9f11118ad7e02cdc.jpg
3:添加图形化FPGA IP
首先设置自定义IP的路径,这里读者可以把我们配套工程根路径下的uisrc文件夹复制到目前的工程根路径,单击Settings在弹出的Settings窗口选择IP->Repository 设置如下路径
3d67f6bb5af149068e2e199660355cc5.jpg

添加+号添加IP
6b8f2db6b3674492a7f472e87c446712.jpg
比如输入关键词FDMA就可以搜索到我们米联客uiFDMA IP
5ccd62aa79d0423bbac8046b0acbc13a.jpg
f07a61df6bdb4bd4a4c441782e2081c0.jpg
用类似的方法添加必要的IP如下图所示:
45ad0614f4d0493fb260cf6c22a8ea3d.jpg
4:完成IP之间的信号自动
这种简单的工程可以先让软件先自动化线,然后根据结果手动一些调整
135f57df25484bba8a7447776caa6689.jpg
可以看到连线结果
8cda6db6219c4ca585765f31018b4547.jpg
5:调整IP参数
5-1:BRAM参数设置
首先把IP的配置参数修改下,双击需要设置的IP可以进行参数设置
FDMA设置数据位宽128bit 可以访问内存地址位宽32bit,最大AXI 最大burst的程度为256
48186f2ae5ec448aa7f89952ff501505.jpg
BRAM设置,使用BRAM Controller 为真双口RAM
897cb11dbc71406dae5d48044b95c82d.jpg
40ce01bb120945afa21549225f9b7fbf.jpg
28150649c98b448da9b6f1f1e2c62948.jpg
4cb259f3169f4423a87c4f8200983afc.jpg
5-2:BRAM Controller参数设置
AXI BRAM Controller设置axi4协议,数据位宽128bit 读延迟1个时钟
875aaf470fb2421ba5ee2e39387335fb.jpg
5-3:Clocking Wizard参数设置
97f379bddfd648099e1d4d3db76988bc.jpg
b78c6923e04b493282153a6db9ea946f.jpg
5-4:AXI Interconnect IP设置
双击AXI Interconnect IP 进行设置
9eabd4877fbf4de2a8468678c7dbefe5.jpg
设置AXI Interconnect IP的性能参数,其中Enable Register Slice 用于改善时序,Enable Data FIFO用于增加FIFO大小,增加数据传输效率
5cfde28f471747b9966080950850e1ba.jpg
6:引出FPGA接口信号
分别右击下图2个IP,然后选择Make External,把需要引出到顶层的FPGA信号引出
b30eba01208d407e9de5f96cf0ee4222.jpg
为了引出时钟需先右击信号PIN脚断开连接,然后Make External,之后重新连接
3a287063d358459ab88b794a23b70f47.jpg
d5252344debb4c41accd7e07303298fe.jpg
修改后重新连接时钟
b8ed13c7614046c0b90235b5bf1a516c.jpg
7:修改复位和信号名字
修改默认的时钟名字,以相同的方法修改其他信号
1d61d169375548a0bb1f7bc318f08fc7.jpg
信号名修改后,修改复位脚的接线
5a6c7ab97e9a4d9aba3159e5b984e2cf.jpg
修改完成后
7145d03f559d4753ba9328f66251afa7.jpg
8:视图优化
右击空白处,弹出菜单选择Regenerate Layout优化下视图
079b1691ded94683a7aaad4cabcd19d3.jpg
731b7d4e88924f9b8afa0b95d370d65b.jpg
9:地址分配
AXI总线必须分配地址,设置uiFDMA的地址空间分配,起始地址可以任意设置,我们设置从0x0000_0000开始,大小64KB
9063791cfd7d44b0873908d747b64c70.jpg
10:自动校验
保存工程
14a4ce63eea547c0aaa3bb97298bc6c1.jpg
11:校验图形逻辑工程
单击下图中的控件可以对图形化编程进行校验

08ab960e0d684ac6a28e29ef1e2632b9.jpg
0dfd8dd2bb404ee7a8c146478ee5f117.jpg
12:自动产生顶层文件
右击system,在弹出的菜单中选择Create HDL Wrapper
b604dd84ac0b41ca9aa13d00365a0fab.jpg
5f7939e7a5a04c5fbb878963458b1d46.jpg
bc49884b55f74c4c96c252ff6ad10b53.jpg
4编写FDMA的BRAM测试代码
刚刚以上自动产生的顶层文件,只是引出的信号接口,并不能完成对FDMA的控制,所以我们需要自定义一个顶层文件,可以复制刚才产生的文件,修改,这样可以省一些编写调用接口的时间。
为了方便文件的管理,我们新建一个fdma_bram_test.v文件,并且复制以上代码,到这个文件夹。
3014492b69c74c64b81abb48054bdfab.jpg
右击删除刚刚自动产生的文件
b5bc13e71bb642ed9ec1de1d160e0f01.jpg

添加fdma_bram_test.v文件
cc8a783c69b2451f9a4043d24aef664c.jpg
69d281811eee4a5abb70aa33bcf15cdf.jpg
fdma_bram_test.v文件

  1. `timescale 1ns / 1ps

  2. module fdma_bram_test(
  3.   input sysclk_p,
  4.   input sysclk_n
  5. );

  6. wire [31:0]   fdma_raddr;
  7. reg           fdma_rareq;
  8. wire          fdma_rbusy;
  9. wire [127:0]  fdma_rdata;
  10. wire [15:0]   fdma_rsize;
  11. wire          fdma_rvalid;
  12. wire [31:0]   fdma_waddr;
  13. reg           fdma_wareq;
  14. wire          fdma_wbusy;
  15. wire [127:0]  fdma_wdata;
  16. wire [15:0]   fdma_wsize;
  17. wire          fdma_wvalid;
  18. wire          sysclk;
  19. wire          ui_clk;
  20. wire          test_error;
  21. reg           test_error1=1'b0;

  22. parameter TEST_MEM_SIZE   = 32'd64*1024;//64KB
  23. parameter FDMA_BURST_LEN  = 16'd512;
  24. parameter ADDR_MEM_OFFSET = 0;
  25. parameter ADDR_INC = FDMA_BURST_LEN * 16;

  26. parameter WRITE1 = 0;
  27. parameter WRITE2 = 1;
  28. parameter WAIT   = 2;
  29. parameter READ1  = 3;
  30. parameter READ2  = 4;

  31. reg [31: 0] t_data;
  32. reg [31: 0] fdma_waddr_r;
  33. reg [2  :0] T_S = 0;

  34. assign fdma_waddr = fdma_waddr_r + ADDR_MEM_OFFSET;
  35. assign fdma_raddr = fdma_waddr;

  36. assign fdma_wsize = FDMA_BURST_LEN;
  37. assign fdma_rsize = FDMA_BURST_LEN;
  38. assign fdma_wdata ={t_data,t_data,t_data,t_data};
  39.    
  40. //delay reset
  41. reg [8:0] rst_cnt = 0;
  42. always @(posedge ui_clk)
  43.     if(rst_cnt[8] == 1'b0)
  44.          rst_cnt <= rst_cnt + 1'b1;
  45.      else
  46.          rst_cnt <= rst_cnt;

  47. always @(posedge ui_clk)begin
  48.     if(rst_cnt[8] == 1'b0)begin
  49.         T_S <=0;   
  50.         fdma_wareq  <= 1'b0;
  51.         fdma_rareq  <= 1'b0;
  52.         t_data<=0;
  53.         fdma_waddr_r <=0;      
  54.     end
  55.     else begin
  56.         case(T_S)      
  57.         WRITE1:begin
  58.             if(fdma_waddr_r==TEST_MEM_SIZE) fdma_waddr_r<=0;
  59.             if(!fdma_wbusy)begin
  60.                     fdma_wareq  <= 1'b1;
  61.                     t_data  <= 0;
  62.             end
  63.             if(fdma_wareq&&fdma_wbusy)begin
  64.                     fdma_wareq  <= 1'b0;
  65.                     T_S         <= WRITE2;
  66.                 end
  67.         end
  68.         WRITE2:begin
  69.             if(!fdma_wbusy) begin
  70.                  T_S <= WAIT;
  71.                  t_data  <= 32'd0;
  72.             end
  73.             else if(fdma_wvalid) begin
  74.                 t_data <= t_data + 1'b1;
  75.             end
  76.         end
  77.         WAIT:begin//not needed
  78.             T_S <= READ1;
  79.         end
  80.         READ1:begin
  81.             if(!fdma_rbusy)begin
  82.                 fdma_rareq  <= 1'b1;
  83.                 t_data   <= 0;
  84.             end
  85.             if(fdma_rareq&&fdma_rbusy)begin
  86.                  fdma_rareq  <= 1'b0;
  87.                  T_S         <= READ2;
  88.             end
  89.         end
  90.         READ2:begin
  91.             if(!fdma_rbusy) begin
  92.                  T_S <= WRITE1;
  93.                  t_data  <= 32'd0;
  94.                  fdma_waddr_r  <= fdma_waddr_r + ADDR_INC;//128/8=16
  95.             end
  96.             else if(fdma_rvalid) begin
  97.                 t_data <= t_data + 1'b1;
  98.             end
  99.         end   
  100.         default:
  101.             T_S <= WRITE1;     
  102.         endcase
  103.     end
  104.   end
  105.   

  106. assign test_error = (fdma_rvalid && (t_data[15:0] != fdma_rdata[15:0]));

  107. always @(posedge ui_clk)
  108.     test_error1 <= test_error;

  109. ila_0 ila_dbg (
  110.     .clk(ui_clk),
  111.     .probe0({fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wbusy}),
  112.     .probe1({fdma_rdata[15:0],t_data[15:0],fdma_rvalid,fdma_rbusy,T_S,test_error1})
  113. );

  114.    IBUFDS #(
  115.       .DIFF_TERM("FALSE"),       // Differential Termination
  116.       .IBUF_LOW_PWR("TRUE"),     // Low power="TRUE", Highest performance="FALSE"
  117.       .IOSTANDARD("DEFAULT")     // Specify the input I/O standard
  118.    ) IBUFDS_inst (
  119.       .O(sysclk),  // Buffer output
  120.       .I(sysclk_p),  // Diff_p buffer input (connect directly to top-level port)
  121.       .IB(sysclk_n) // Diff_n buffer input (connect directly to top-level port)
  122.    );

  123.   system system_i
  124.        (.FDMA_S_0_i_fdma_raddr(fdma_raddr),
  125.         .FDMA_S_0_i_fdma_rareq(fdma_rareq),
  126.         .FDMA_S_0_o_fdma_rbusy(fdma_rbusy),
  127.         .FDMA_S_0_o_fdma_rdata(fdma_rdata),
  128.         .FDMA_S_0_i_fdma_rready(1'b1),
  129.         .FDMA_S_0_i_fdma_rsize(fdma_rsize),
  130.         .FDMA_S_0_o_fdma_rvalid(fdma_rvalid),
  131.         .FDMA_S_0_i_fdma_waddr(fdma_waddr),
  132.         .FDMA_S_0_i_fdma_wareq(fdma_wareq),
  133.         .FDMA_S_0_o_fdma_wbusy(fdma_wbusy),
  134.         .FDMA_S_0_i_fdma_wdata(fdma_wdata),
  135.         .FDMA_S_0_i_fdma_wready(1'b1),
  136.         .FDMA_S_0_i_fdma_wsize(fdma_wsize),
  137.         .FDMA_S_0_o_fdma_wvalid(fdma_wvalid),
  138.         .sysclk(sysclk),
  139.         .ui_clk(ui_clk)
  140.         );        
  141. endmodule
复制代码

5程序分析
1:总流程图
如下图所示,本文的程序工作流程如下,包括请求写数据、FDMA收到写数据请求、写数据完成、请求读数据、FDMA收到读数据请求和读数据完成、校验。
5d397eb9939a44238bdd994919a316ca.jpg
2:FDMA的读写时序
以下是fdma_test.v中读写fdma ip接口的状态机,由于读写代码对称,对fdma的读写操作可以分为2步完成,分别是:1:发送读/写请求 2:读/写有效数据。
7572078dc13f446688c37ecf97426b71.jpg
2-1:FDMA的写时序
24005d2b5dee4562bbf1fedd66867696.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-2:FDMA的读时序
a808e425d2fa4c6bbadd66614803f3e8.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总线协议的使用。
6RTL仿真
1:仿真tb文件
编写仿真tb文件,fdma_bram_test_tb.v,非常简单,只需要给一个时钟
  1. `timescale 1ns / 1ps
  2. module fdma_bram_test_tb();
  3. reg sysclk_p;

  4. fdma_bram_test fdma_bram_test_inst
  5. (
  6.     .sysclk_p(sysclk_p),
  7.     .sysclk_n(~sysclk_p)
  8. );

  9. initial begin
  10.      sysclk_p  = 0;
  11.      #100;
  12. end

  13. always #5 sysclk_p = ~sysclk_p;

  14. endmodule
复制代码


添加fdma_bram_test_tb.v到工程中
b5ad2c9194a641cf88cb846628b3f589.jpg
87e37e8fcf184ee480dd8ba7d816c442.jpg
2:仿真测试
进行RTL行为仿真
24c3f78ae19e4f8f825f156c41066c7d.jpg
c15022e3da1b46f79841e45b71d9f60b.jpg
放大后观察数据,我们可以看到test_error有毛刺,但是test_error打拍后,毛刺就没有了。
470fcc4db497493dbe2bdd88cd8a5675.jpg
FDMA 源码部分的分析,在前面课程中已经分析过,这里不再重复。
7编译测试
添加ila IP CORE 和fpga pin定义
680a16ea0456443289052f40f7a8f0da.jpg
ila的设置如下
5b1df5b377024225961f2cbcf23fd0a2.jpg

e6bbd9c7fd3e4ea38c3b3c4ea3a98df2.jpg
编译产生bit
10337331190a4787ba01a75b8a5927f5.jpg
下载程序到开发板测试,通过在线逻辑分析仪观察

[米联客-XILINX-H3_CZ08_7100] FPGA_PL-DDR篇连载-03使用fdma读写axi-bram测试-59.png
cb75d67de61f415f83771a7ab85d0c3a.jpg




5290dfb8bb0d400db5c9936cb593d9b5.jpg
[米联客-XILINX-H3_CZ08_7100] FPGA_PL-DDR篇连载-03使用fdma读写axi-bram测试-61.png
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则