问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 3669 人浏览分享

开启左侧

米联客-XILINX-H3_CZ08_7100] FPGA_AXI总线入门连载-08 使用 fdma 读写 axi-bram

[复制链接]
3669 0
AMD-FPGA课程
AMD课程: 01-教程内容导读 »
​
软件版本: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 可以完成很多数据读写存储类的应用,本文将展示通过 FDMA 读写 AXI-BRAM 本文实验目的:
1:掌握基于 uiFDMA3.0 的 FPGA 工程设计
2:利用 uiFDMA3.0 提供的接口,编写 BRAM 测试程序 3:对 AXI-BRAM 读写仿真和测试
2 搭建 FPGA 图形化工程
2.1 创建 Block Design 并且命名为 system
c8a7481c214943d6ac21c07818c7f2fa.jpg ​
如下图所示,图形化 system 就是一个代码容器,接着我们要添加一些图像化的 IP
b79677637b80452084f544fcdd6e8b99.jpg ​

2.2 添加图形化 FPGA IP
首先设置自定义 IP 的路径,这里读者可以把我们配套工程根路径下的 uisrc 文件夹复制到目前的工程根路径,单击 Settings 在弹出的 Settings 窗口选择 IP->Repository  设置如下路径
47073921922545e2ad3b72afa716deae.jpg ​
添加+号添加 IP
5729bfbc1e3847e0a29a299a98333a6a.jpg ​
比如输入关键词 FDMA 就可以搜索到我们米联客 uiFDMA IP(注意最新版本是 3.0 版本)
90b1f7c91bac48a0b2d83d2fb20c139a.jpg ​

b5ed9f732f0040ee82257d55ca13b128.jpg ​
用类似的方法添加必要的 IP 如下图所示:
cdba5479dd414651be5ea37b7faac5e6.jpg ​
2.3 完成 IP 之间的信号自动
这种简单的工程可以先让软件先自动化线,然后根据结果手动一些调整
cd8a5372874d4d6da989f510158d4229.jpg ​
可以看到连线结果
256667ad048a4ef7b4e9dd20ff6d06d1.jpg ​
2.4 调整 IP 参数
1:BRAM 参数设置
首先把 IP 的配置参数修改下,双击需要设置的IP 可以进行参数设置 FDMA 设置数据位宽 128bit  可以访问内存地址位宽 32bit  其他默认
150949d8ddc54490b7285bdb04c825a5.jpg ​
BRAM 设置,使用 BRAM Controller  为真双口 RAM
a71fbf7859b54166ac6bbd80662ca4cc.jpg ​

d509c2c8ea0d4604bc652e63b341ec59.jpg ​

6f93c522f56b4adbbbdf8eecb70d57c3.jpg ​
2:BRAM Controller 参数设置
AXI BRAM Controller 设置 axi4 协议,数据位宽 128bit  读延迟 1 个时钟
1aeaa1da4d0b4d25a2e4a0c87bb96a24.jpg ​
3:Clocking Wizard 参数设置
477c5b887e2a4a218bd70df8ea5e0d2c.jpg ​


605d4957b9954d668f00c87182894c99.jpg ​
4:AXI Interconnect IP 设置
双击 AXI Interconnect IP  进行设置
2993d9120653496680c858150ad8e68d.jpg ​
设置 AXI Interconnect IP 的性能参数,其中 Enable Register Slice  用于改善时序,Enable Data FIFO 用于增加 FIFO 大 小,增加数据传输效率
86ad5f92e029493b921d44895282013f.jpg ​

2.5 引出 FPGA 接口信号
分别右击下图 2 个 IP,然后选择 Make External ,把需要引出到顶层的 FPGA 信号引出
541d47aba6ae431897a06180066fefc4.jpg ​
为了引出时钟需先右击信号 PIN 脚断开连接,然后 Make External ,之后重新连接
18ff6b7ac58d4014a1b58d5971ee1971.jpg ​

6fc8381e1a0e403f9f5ef0a022e6cc16.jpg ​


4b32bc0be0e141bab3153c7ae39ca07a.jpg ​
修改后重新连接时钟

801e82f62cc0464382fad5955227fc3c.jpg ​
2.6 修改信号名字
修改默认的时钟名字
155488c116474593b27ffcbf0541d756.jpg ​


2b6246f7dc1e478296ad87e16199401e.jpg ​
2.7 连线最后的遗漏
软件还在提示我们有线没有连接,这种提示是建立在 XILINX 自带的 IP,软件可以识别一部分比如复位时钟等, 不是可以识别所有的信号,一般再最后我们如果看到还有这种提示说明还有未完成的连线
b2b03aa0b7b740e9bbca5e4580d94c7f.jpg ​
这里是 ext_reset_in 没有连接,也是接到 Clocking Wizard 的 Locked
21a0306e347d4f41b63d1448c366a209.jpg ​
2.8 视图优化
右击空白处,弹出菜单选择 Regenerate Layout 优化下视图

3719bcb237a442e6b520cedebcd9498f.jpg ​
ddb7bfdc9b4744d4a00a067654490fd7.jpg ​
2.9 地址分配
AXI 总线必须分配地址,设置 uiFDMA 的地址空间分配,起始地址可以任意设置,我们设置从 0x0000_0000 开始, 大小 64KB
36575152fd794cacbaecd6ac99373c27.jpg ​
2.10 自动校验
保存工程

ec8fe0cfd6d54b5c85d60542297d8137.jpg ​
单击下图中的控件可以对图形化编程进行校验
2205d1d2c4c14382a83a53beda5beecd.jpg ​
2.11 自动产生顶层文件
右击 system,在弹出的菜单中选择 Create HDL Wrapper
61de9679c27249328974193327de03ab.jpg ​
6c3d509907b145638b24e0d13030c267.jpg ​

b1c46e165b9547cfbbddf6eabc77af0f.jpg ​
3 编写 FDMA 的 BRAM 测试代码
刚刚以上自动产生的顶层文件,只是引出的信号接口,并不能完成对 FDMA 的控制,所以我们需要自定义一 个顶层文件,可以复制刚才产生的文件,修改,这样可以省一些编写调用接口的时间。
为了方便文件的管理,我们新建一个 fdma_bram_test.v 文件,并且复制以上代码,到这个文件夹。
ebb79268425e4c5b9de44dbb9b2f686f.jpg ​
右击删除刚刚自动产生的文件
c122b9c349034eb585f9012cb15ea156.jpg ​
添加 fdma_bram_test.v 文件
1607600ccbf948e29ae6f47fe615cca6.jpg ​
9e6454e2aa014efea4cdd60c2924beed.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 [0:0]    fdma_rstn;
  19. wire          ui_clk;
  20. parameter TEST_MEM_SIZE   = 32'd64*1024;//64KB
  21. parameter FDMA_BURST_LEN  = 16'd512;
  22. parameter ADDR_MEM_OFFSET = 0;
  23. parameter ADDR_INC = FDMA_BURST_LEN * 16;
  24. parameter WRITE1 = 0;
  25. parameter WRITE2 = 1;
  26. parameter WAIT   = 2;
  27. parameter READ1  = 3;
  28. parameter READ2  = 4;
  29. reg [31: 0] t_data;
  30. reg [31: 0] fdma_waddr_r;
  31. reg [2  :0] T_S = 0;
  32. wire          sysclk;
  33. //对差分时钟采用 IBUFGDS IP 核去转换
  34. IBUFGDS CLK_U(
  35. .I(sysclk_p),
  36. .IB(sysclk_n),
  37. .O(sysclk)
  38. );
  39. assign fdma_waddr = fdma_waddr_r + ADDR_MEM_OFFSET;
  40. assign fdma_raddr = fdma_waddr;
  41. assign fdma_wsize = FDMA_BURST_LEN;
  42. assign fdma_rsize = FDMA_BURST_LEN;
  43. assign fdma_wdata ={t_data,t_data,t_data,t_data};
  44.   
  45.   
  46. //delay reset
  47. reg [8:0] rst_cnt = 0;
  48. always @(posedge ui_clk)
  49.     if(rst_cnt[8] == 1'b0)
  50.          rst_cnt <= rst_cnt + 1'b1;
  51.      else
  52.          rst_cnt <= rst_cnt;
  53. always @(posedge ui_clk)begin
  54.     if(rst_cnt[8] == 1'b0)begin
  55.         T_S <=0;   
  56.         fdma_wareq  <= 1'b0;
  57.         fdma_rareq  <= 1'b0;
  58.         t_data<=0;
  59.         fdma_waddr_r <=0;      
  60.     end
  61.     else begin
  62.         case(T_S)      
  63.         WRITE1:begin
  64.             if(fdma_waddr_r==TEST_MEM_SIZE) fdma_waddr_r<=0;
  65.                 if(!fdma_wbusy)begin
  66.                     fdma_wareq  <= 1'b1;
  67.                     t_data  <= 0;
  68.                 end
  69.                 if(fdma_wareq&&fdma_wbusy)begin
  70.                     fdma_wareq  <= 1'b0;
  71.                     T_S         <= WRITE2;
  72.                 end
  73.         end
  74.         WRITE2:begin
  75.             if(!fdma_wbusy) begin
  76.                  T_S <= WAIT;
  77.                  t_data  <= 32'd0;
  78.             end
  79.             else if(fdma_wvalid) begin
  80.                 t_data <= t_data + 1'b1;
  81.             end
  82.         end
  83.         WAIT:begin//not needed
  84.             T_S <= READ1;
  85.         end
  86.         READ1:begin
  87.             if(!fdma_rbusy)begin
  88.                 fdma_rareq  <= 1'b1;
  89.                 t_data   <= 0;
  90.             end
  91.             if(fdma_rareq&&fdma_rbusy)begin
  92.                  fdma_rareq  <= 1'b0;
  93.                  T_S         <= READ2;
  94.             end
  95.         end
  96.         READ2:begin
  97.             if(!fdma_rbusy) begin
  98.                  T_S <= WRITE1;
  99.                  t_data  <= 32'd0;
  100.                  fdma_waddr_r  <= fdma_waddr_r + ADDR_INC;//128/8=16
  101.             end
  102.             else if(fdma_rvalid) begin
  103.                 t_data <= t_data + 1'b1;
  104.             end
  105.         end   
  106.         default:
  107.             T_S <= WRITE1;     
  108.         endcase
  109.     end
  110.   end
  111.   
  112. wire test_error = (fdma_rvalid && (t_data[15:0] != fdma_rdata[15:0]));
  113. ila_0 ila_dbg (
  114.         .clk(ui_clk),
  115.         .probe0({fdma_wdata[15:0],fdma_wareq,fdma_wvalid,fdma_wbusy}),
  116.         .probe1({fdma_rdata[15:0],t_data[15:0],fdma_rvalid,fdma_rbusy,T_S,test_error})
  117. );
  118.   system system_i
  119.        (.FDMA_S_0_fdma_raddr(fdma_raddr),
  120.         .FDMA_S_0_fdma_rareq(fdma_rareq),
  121.         .FDMA_S_0_fdma_rbusy(fdma_rbusy),
  122.         .FDMA_S_0_fdma_rdata(fdma_rdata),
  123.         .FDMA_S_0_fdma_rready(1'b1),
  124.         .FDMA_S_0_fdma_rsize(fdma_rsize),
  125.         .FDMA_S_0_fdma_rvalid(fdma_rvalid),
  126.         .FDMA_S_0_fdma_waddr(fdma_waddr),
  127.         .FDMA_S_0_fdma_wareq(fdma_wareq),
  128.         .FDMA_S_0_fdma_wbusy(fdma_wbusy),
  129.         .FDMA_S_0_fdma_wdata(fdma_wdata),
  130.         .FDMA_S_0_fdma_wready(1'b1),
  131.         .FDMA_S_0_fdma_wsize(fdma_wsize),
  132.         .FDMA_S_0_fdma_wvalid(fdma_wvalid),
  133.         .sysclk(sysclk),
  134.         .ui_clk(ui_clk)
  135.         );        
  136. endmodule
复制代码

4RTL 仿真
4.1 仿真 tb 文件
编写仿真 tb 文件,fdma_bram_test_tb.v ,非常简单,只需要给一个时钟
  1. `timescale 1ns / 1ps
  2. module fdma_bram_test_tb();
  3. reg sysclk_p;
  4. reg sysclk_n;
  5. fdma_bram_test fdma_bram_test_inst
  6. (
  7.     .sysclk_p(sysclk_p),
  8.     .sysclk_n(sysclk_n),
  9. );
  10. initial begin
  11.    sysclk_p  <= 1'b0;   //系统时钟设置初值
  12.    sysclk_n  <= 1'b1;
  13.      #100;
  14. end
  15. always #5 sysclk_p = ~sysclk_p;
  16. always #5 sysclk_n = ~sysclk_n;
  17. endmodule
复制代码
添加 fdma_bram_test_tb.v 到工程中
e812b152a9c1498c8e0cba359160b517.jpg ​
a6675248ae1b41bca67de553c55539ef.jpg ​
4.2 仿真测试
进行 RTL 行为仿真
845d86fef9c84b9d924da805a2e7b692.jpg ​
5909e74a542b45ccb9e2c1a2077c8658.jpg ​
放大后观察数据
1ffdd364988043619006f0015a4885c8.jpg ​
我们也可以继续深入看 FDMA 源码里面的信号工作情况,这个读者可以自己区分析下,我们米联客计划出一 份专门讲解 AXI 总线部分的教程,里面详细分析 FDMA 的设计过程,以及信号仿真。本章节主要是侧重 FDMA 的 应用,只要会熟练应用可以了!
5 编译测试
添加 ila IP CORE  和 fpga pin 定义
0e2cd62a6757423cbc114526a594204e.jpg ​
ila 的设置如下
750c4dadabdb487083c13c21b343a975.jpg ​
4ab89b87addc4fbf975eafcad7f2440b.jpg ​
编译产生 bit
05f831ca95024fba9c80506afb7ade34.jpg ​
下载程序到开发板测试,通过在线逻辑分析仪观察
d73f356c72854287ac85a62ee7be0d10.jpg ​
b1466b77cf5148a88613d706303e9e34.jpg
6 程序分析
6.1 总流程图
如下图所示,本文的程序工作流程如下,包括请求写数据、FDMA收到写数据请求、写数据完成、请求读数据、FDMA收到读数据请求和读数据完成、校验。
7b14ea65efea415088c95938ce9a531b.jpg ​
6.2FDMA 的读写时序
以下是 fdma_test.v 中读写 fdma ip 接口的状态机,由于读写代码对称,对 fdma 的读写操作可以分为 2 步完成,分别 是:1:发送读/写请求 2:读/写有效数据。
fe63f010fa9e4f2f85d004eb32b4dcd9.jpg ​
1:FDMA 的写时序
70080c2232a14f2a813912c198ca44f5.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 的读时序
cff2bb0ab5de4890bc17236be61a8f3a.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 总线协议的使用。

​

















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

本版积分规则

0

关注

0

粉丝

303

主题
精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版