[X]关闭

[米联客-XILINX-H3_CZ08_7100] FPGA_PCIE通信(linux)连载-03基于XDMA实现PCIE通信

文档创建者:FPGA课程
浏览次数:404
最后更新:2024-09-18
文档课程分类-AMD-ZYNQ
AMD-ZYNQ: ZYNQ-FPGA部分 » 2_FPGA实验篇(仅旗舰) » 7-FPGA PCIE通信(Linux)
本帖最后由 FPGA课程 于 2024-9-18 10:05 编辑

​软件版本: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概述
本方案基于XDMA IP搭建FPGA工程,并且以本课中已经编译好的驱动和测试程序为演示demo。
本方案内容作为通用的教程内容,适合XILINX各类支持PCIE通信的板卡。并且米联客在XDMA中使用了自己编写的FDMA控制IP,可以简单方便的完成数据之间的交换。
2系统构架
本系统中演示的关键在于我们编写了一个uixdmairq的IP。该用来配合驱动处理中断,uixdmairq提供了AXI-LITE接口,上位机通过访问user空间地址读写uixdmairq的寄存器。该IP在user_irq_req_i输入的中断位,寄存中断位号,并且输出给XDMA IP ,当上位机的驱动响应中断的时候,在中断里面写uixdmairq 的寄存器,清除已经处理的中断。
另外本方案中通过AXI-BRAM来演示用户user空间的读写访问测试。
ccfbe868a9f944dca727018bdb9bc457.jpg
3XMDA概述
Xilinx 提供的DMASubsystem for PCIExpressIP是一个高性能,可配置的适用于PCIE2.0,PCIE3.0的SG 模式 DMA,提供用户可选择的 AXI4 接口或者 AXI4-Stream接口。一般情况下配置成 AXI4 接口可以加入到系统总线互联,适用于大数据量异步传输,通常情况都会使用到 DDR,AXI4-Stream 接口适用于低延迟数据流传输。
XDMA 是SGDMA,并非Block DMA,SG 模式下,主机会把要传输的数据组成链表的形式,然后将链表首地址通过BAR 传送给XDMA,XDMA 会根据链表结构首地址依次完成链表所指定的传输任务。
01fafd20e1f442c581e53acba9dd2dfc.jpg
AXI4、AXI4-Stream,必须选择一个,用于数据传输
AXI4-Lite Master可选,用于实现PCIE BAR地址到AXI4-lite 寄存器地址的映射,可以用于读写用户逻辑寄存器。
AXI4-Lite Slave可选,用来将XDMA 内部寄存器开放给用户逻辑,用户逻辑可以通过此接口访问 XDMA 内部寄存器,不会映射到BAR。
AXI4 Bypass接口,可选,用来实现PCIE 直通用户逻辑访问,可用于低延迟数据传输。
4基于XDMA的PCIE FPGA工程搭建
4.1XDMA IP配置
1:添加XDMA IP核
b949c6e2b1da4760bd969e2edf097bd8.jpg
81f9b5c1a51b4012983d479bbad8eed1.jpg
2:配置XDMA IP
双击XDMA IP进行配置
Mode:配置模式,选择 BASE配置
Lane Width:选择PCIE的通道数量对于MZ7035FC为8个通道,每个开发板支持通道数量不一样,通道数量越多通信速度越快,用户需要根据硬件的实际通达数量选择正确的通道数。
Max Link Speed:选择5.0GT/s 即PCIE2.0,对于ultrascale或者ultrascale+的FPGA可以支持PCIE3.0实现更高速度Reference Clock :100MHZ,参考时钟 100M
DMA Interface Option:接口选择 AXI4 接口
AXI Data Width:128bit,即 AXI4 数据总线宽度为128bit
AXI Clock :250M,即AXI4 接口时钟为250MHZ
DMA Interface option 设置为AXI Memory Mapped方式
f35e7f213c6445d39e194efa0bd0efdf.jpg
PCIE ID 配置,这里选择默认的配置就可以,默认的设备类型是Simple communication controllers
d3b44156d76f42d4b869cdee4b4302b7.jpg
PCIE BAR 配置,这里面的配置比较重要,首先使能 PCIE to AXI Lite Master Interface ,这样可以在主机一侧通过PCIE 来访问用户逻辑侧寄存器或者其他 AXI4-Lite 总线设备映射空间选择 1M,当然用户也可以根据实际需要来自定义大小。
PCIE to AXI Translation:这个设置比较重要,通常情况下,主机侧PCIE BAR 地址与用户逻辑侧地址是不一样的, 这个设置就是进行BAR 地址到AXI 地址的转换,比如主机一侧 BAR 地址为0,IP 里面转换设置为0x44A00000, 则主机访问 BAR 地址 0 转换到AXI LIte 总线地址就是0x44A00000
PCIE to DMA Interface :选择64bit 使能
DMA Bypass 暂时不用
e894615807364f16a87654fb5b6cfa52.jpg
PCIE 中断设置
User Interrupts:用户中断,XDMA提供16条中断线给用户逻辑,这里面可以配置使用几条中断线。
Legacy Interrupt:XDMA支持Legacy中断,我们这么不选
MSI Capabilities:选择支持MSI中断 ,支持4个中断消息向量
注意:MSI 中断和 MSI-X 中断只能选择一个,否则会报错,如果选择了 MSI 中断,则可以选择 Legacy 中断, 如果选择了 MSI-X 中断,那么 MSI 必须取消选择,同时Legacy 也必须选择None。此 IP 对于7 系列设置有这个问题,如果使用Ultrascale 系列,则可以全部选择
MSI-X Capabilities:不选
Miscellaneous:选Extended Tag Field
Link Status Register:选Enable Slot Clock Configuration
73941de856ca4f25afa20fd06ba85dc6.jpg
配置DMA 相关内容
Number of DMA Read Channel(H2C)和Number of DMA Write Channel(C2H)通道数,对于PCIE2.0 来说最大只能选择2,也就是 XDMA 可以提供最多四个独立的写通道和四个独立的读通道,独立的通道对于实际应用中有很大的作用,在带宽允许的前提前,一个PCIE 可以实现多种不同的传输功能,并且互不影响。这里我们选择2 Number of Request IDs for Read (Write)channel :这个是每个通道设置允许最大的 outstanding 数量,按照默认即可
ea9830b5b8654c38b2d4f18fd60afa13.jpg
4.2完成自动连线
配置完成以后,点击 Run Block Auto,可以看到之前的配置信息,如果有发现和目标配置不一样的,需要手动 修改,点击 OK,完成配置。
e4173f4d3f7f4a75bc4c9897d42559d1.jpg
12cb0d95dec8422890d6673abdf5f90d.jpg

配置完成后,VIVADO会自动进行必要的连线
8cde26f95b2f42f59e0a964383609e35.jpg
到此为止,XDMA IP 配置就完成了。为了让XDMA和上位机可以密切配和工作,我们还要继续搭建其他部分的功能模块。
4.3基于图形设计的XDMA工程
4991198ce4814ac992de214868f794fb.jpg
4.4添加中断测试代码
  1. `timescale 1ns / 1ps

  2. /*******************************MILIANKE*******************************
  3. *Company : MiLianKe Electronic Technology Co., Ltd.
  4. *WebSite:https://www.milianke.com
  5. *TechWeb:https://www.uisrc.com
  6. *tmall-shop:https://milianke.tmall.com
  7. *jd-shop:https://milianke.jd.com
  8. *taobao-shop1: https://milianke.taobao.com
  9. *Create Date : 2021/10/15
  10. *File Name : pcie_top.v
  11. *Description :
  12. *Declaration :
  13. *The reference demo provided by Milianke is only used for learning.
  14. *We cannot ensure that the demo itself is free of bugs, so users
  15. *should be responsible for the technical problems and consequences
  16. *caused by the use of their own products.
  17. *Copyright: Copyright (c) MiLianKe
  18. *All rights reserved.
  19. *Revision : 1.0
  20. *Signal description
  21. *1) _i input
  22. *2) _o output
  23. *3) _n activ low
  24. *4) _dg debug signal
  25. *5) _r delay or register
  26. *6) _s state mechine
  27. *********************************************************************/
  28. module pcie_top
  29. (
  30. output [14:0]DDR3_addr,
  31. output [2:0]DDR3_ba,
  32. output DDR3_cas_n,
  33. output [0:0]DDR3_ck_n,
  34. output [0:0]DDR3_ck_p,
  35. output [0:0]DDR3_cke,  
  36. output [0:0]DDR3_cs_n,
  37. output [7:0]DDR3_dm,   
  38. inout [63:0]DDR3_dq,   
  39. inout [7:0]DDR3_dqs_n,
  40. inout [7:0]DDR3_dqs_p,
  41. output [0:0]DDR3_odt,
  42. output DDR3_ras_n,
  43. output DDR3_reset_n,
  44. output DDR3_we_n,
  45. input  sysclk_p,
  46. input  sysclk_n,

  47. input  [7 :0]pcie_mgt_rxn,
  48. input  [7 :0]pcie_mgt_rxp,
  49. output [7 :0]pcie_mgt_txn,
  50. output [7 :0]pcie_mgt_txp,
  51. input  [0 :0]pcie_ref_clk_n,
  52. input  [0 :0]pcie_ref_clk_p,
  53. input pcie_rst_n
  54. );

  55. wire sysclk;
  56. IBUFDS CLK_U(.I(sysclk_p),.IB(sysclk_n),.O(sysclk));

  57. wire axi_aclk;
  58. wire user_irq_en_o;
  59. reg  [21:0]timer_cnt;
  60. reg  timer_r1,timer_r2;
  61. reg [1:0]int_p;
  62. reg [3:0]user_irq_req_i;
  63. wire inter = !timer_r2 && timer_r1;

  64. always @(posedge axi_aclk)begin
  65. if(user_irq_en_o == 1 'b0)begin
  66. timer_cnt <= 22 'd0;
  67. end
  68. else begin
  69. timer_cnt <= timer_cnt + 1 'b1;
  70. end
  71. end
  72. always @(posedge axi_aclk)begin
  73. if(user_irq_en_o == 1 'b0)begin
  74. timer_r1 <= 1 'd0;
  75. timer_r2 <= 1 'd0;
  76. end
  77. else begin
  78. timer_r1 <= timer_cnt[20];
  79. timer_r2 <= timer_r1;
  80. end
  81. end


  82. always @(posedge axi_aclk)begin
  83. if(user_irq_en_o == 1 'b0)begin
  84. int_p[1:0]  <= 4 'd0;
  85. user_irq_req_i <= 4 'd0;
  86. end
  87. else begin
  88. if(inter)  int_p <= int_p + 1 'b1;
  89. user_irq_req_i <= 4 'd0;
  90. user_irq_req_i[int_p] <= 1 'b1;
  91. end
  92. end

  93. pcie_system pcie_system_i(
  94. .DDR3_addr(DDR3_addr),
  95. .DDR3_ba(DDR3_ba),
  96. .DDR3_cas_n(DDR3_cas_n),
  97. .DDR3_ck_n(DDR3_ck_n),
  98. .DDR3_ck_p(DDR3_ck_p),
  99. .DDR3_cke(DDR3_cke),
  100. .DDR3_cs_n(DDR3_cs_n),
  101. .DDR3_dm(DDR3_dm),
  102. .DDR3_dq(DDR3_dq),
  103. .DDR3_dqs_n(DDR3_dqs_n),
  104. .DDR3_dqs_p(DDR3_dqs_p),
  105. .DDR3_odt(DDR3_odt),
  106. .DDR3_ras_n(DDR3_ras_n),
  107. .DDR3_reset_n(DDR3_reset_n),
  108. .DDR3_we_n(DDR3_we_n),

  109. .pcie_mgt_rxn(pcie_mgt_rxn),
  110. .pcie_mgt_rxp(pcie_mgt_rxp),
  111. .pcie_mgt_txn(pcie_mgt_txn),
  112. .pcie_mgt_txp(pcie_mgt_txp),
  113. .pcie_ref_clk_n(pcie_ref_clk_n),
  114. .pcie_ref_clk_p(pcie_ref_clk_p),
  115. .pcie_rst_n(pcie_rst_n),
  116. .axi_aclk(axi_aclk),
  117. .user_irq_en_o(user_irq_en_o),
  118. .user_irq_req_i(user_irq_req_i),
  119. .sysclk(sysclk)
  120. );


  121. endmodule
复制代码


进行地址分配:
这里我们把挂在M_AXI上的DDR地址分配从0开始(对于widnows系统必须为0)M_AXI是需要进行DMA操作的。而M_AXI_LITE挂载的BRAM和uixdmairq中断控制单元是映射到用户BAR地址空间,这个地址就是前面我们XDMA IP里面设置的地址。默认情况下,需要设置uixdmairq中断控制单元的地址和XDMA里面设置的用户BAR地址空间一致。如下图0x44A0_0000。BRAM的地址空间0x44A01_0000。关于地址空间的具体含义,结合软件的使用会更加清晰,初学者暂且根据教程设置。
3a707567c0bf4d0fadfe01449832533f.jpg
5硬件安装
注意确保TF卡里面没有程序吗,或者拔掉TF卡。
先下载程序,调试阶段下载bit文件,然后再开电脑。这样才能正确识别和后续测试工作正常开展。
9935d259261e4d8f8d9ae33490d53f0b.jpg
6编译安装驱动
1.修改驱动,找到xdma-core.c的第4657行,将原来的:

  • rc = pci_enable_msix(pdev, lro->entry, req_nvec);
修改为:

  • #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
  •   rc = pci_enable_msix(pdev, lro->entry, req_nvec);
  • #else
  •   rc = pci_enable_msix_range(pdev, lro->entry, req_nvec, req_nvec);
  • #endif
4f89a293cddf43168b082e89ea8ae635.jpg

2.修改驱动,找到xdma-core.c的第1016行,将原来的:

  • mmiowb();
修改为:

  • #if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 1, 0)
  • mmiowb();
  • #endif
bdcf7eab949647718e562d7d3ff15c8e.jpg
3.修改驱动,找到xdma-core.c的第1675、1683行,修改为下图所示:
439dffaa37c94e45b1276b0fc4ac24be.jpg
4.驱动编译(本课APP_linux下的驱动是已经修改好的
1adbc034c5f24679a1678c24de01be44.jpg
b10b06dcbb77481ca9bfbb287f550e66.jpg

在准备加载驱动前,确保你的开发板已经下载PCIE工程的bit文件,而且已经重启过电脑。好了,现在加载驱动。
(每一次下载程序后重启都要再重新加载驱动,后面课程就不在说明)
aa44d8a4f708471c814196cadb3b1125.jpg
7应用程序测试1.在终端执行命令:
./dma_from_device -d /dev/xdma0_c2h_0 -f ./test.bin -s 4096 -a 0 -c 1
b05306f6f3044fd5a08ef0f9b70716ed.jpg
./dma_to_device -d /dev/xdma0_h2c_0 -f ./test.bin -s 4096 -a 0 -c 1
925b1b7ef3b14b8c8bb4fdc07eb68983.jpg

-d:device 设备.
-f:file 文件
-s:size 大小
-a:addr 起始地址
-c:count

这两个操作分别是从板卡读 4096 Bytes 数据到文件 test.bin 以及从 test.bin 读出4096 Bytes 数据发送给板卡。
2.xdma中断测试
04bed61f005643db8ba19789c9afe3a1.jpg
打开终端,输入以下命令:
sudo ./pcie_irq
292f84ae163d4a328a9b96f77eada79a.jpg
可以看到运行结果是 4 个中断事件,实际上 XMDA 最大支持 16 个中断事件。更多的中断时间可以更好的发挥
CPU 多核多线程的性能。
好了,到此 XDMA 的 PCIE 方案核心内容就已经讲完了。XILINX 官方给的资料往往没有细化,我们米联客已经对以上驱动稍加修改,以更好的支持中断。


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

本版积分规则