PCIe ROOT枚举测试#

实验VIvado工程为“pcie_root”。

Vivado工程建立#

创建新工程#

  1. 新建一个工程名称为“pcie_root”,选择新建一个文件夹,点击“Next”

../_images/image180.png
  1. 工程类型选择“RTL Project”,同时选择“Do not specify sources at this time”,点击“Next”

../_images/image240.png
  1. “Parts”器件家族(Family)选择“Zynq-7000”,封装(Package)选择“ffg676”,然后选择“xc7z035ffg676-2”,点击“Next”

../_images/image329.png
  1. 点击“Finish”完成工程向导

创建block设计#

  1. 从Vivado流程导航窗口中点击“Create Block Design”

../_images/image420.png
  1. 给Block设计起名名字,这里保持“design_1”的默认名称,点击“OK”

../_images/image517.png
  1. 空白设计打开后,点击“Add IP”图标,在IP仓库中选择双击“ZYNQ7 Processing System”

../_images/image615.png
  1. ZYNQ PS block被添加到block设计中,点击“Run Block Automation”来配置目标硬件

../_images/image715.png
  1. 用默认设置,点击“OK”

../_images/image815.png
  1. 双击“processing_system7_0”配置ZYNQ PS

  2. 在“PS-PL Configuration”选项卡中,使能HP Slave AXI接口“S AXI HP0 interface”,HP端口可以让外部AXI Master接口高性能访问ZYNQ PS ddr3内存。

../_images/image915.png
  1. 在“Peripheral I/O Pins”选项中配置Bnak 1电平标准为“LVCMOS 1.8V”,使能Quad SPI Flash,IO使用MIO1-MIO6,使能UART1,IO使用MIO12-MIO13

../_images/image1015.png
  1. 使能Ethernet 0,IO使用MIO16-MIO27,使能USB0,IO使用MIO28-MIO39,

../_images/image1120.png
  1. 使能Ethernet 0的MDIO,IO使用MIO52-MIO53,使能SD 0,IO使用MIO40-MIO45,使能SD 1,IO使用MIO47-MIO51,使能I2C 0,IO通过PL扩展,选择EMIO

../_images/image1216.png
  1. SD 0的Card Detect选择MIO 10

../_images/image1314.png
  1. 使能GPIO MIO,选择Ethernet PHY Reset为MIO7,USB PHY Reset为MIO8

../_images/image1413.png
  1. 在DDR Configuration选择中选择Memory Part为“MT41J256M16 RE-125”

../_images/image1512.png
  1. 在Interrupts选项中使能“Fabric Interrupts”,再使能IRQ_F2Q[15:0],点击OK完成配置

../_images/image1611.png

添加AXI MM to PCIe bridge#

  1. 从IP 仓库添加 “AXI Memory Mapped to PCI Express” block 到设计中

../_images/image1711.png
  1. 双击“axi_pcie_0”配置参数

  2. 在“PCIE:Basics”配置选项中,端口类型选择“Root Port of PCI Express Root Complex”

../_images/image1810.png
  1. 在“PCIE:Link Config”选项中,“Lane Width”选择X4,“Link speed”选择5 GT/s

../_images/image1910.png
  1. 在 “PCIE:ID” 选项中,“Class Code”填写 0x060400. 这是为了以后在Linux下能正确的使用驱动程序。

../_images/image209.png
  1. 在“PCIE:BARS”项中, 设置BAR 0 类型为 “Memory” ,大小为 1 Gigabytes,其他参数都保持默认,点击“OK”

../_images/image2114.png
  1. 添加一个“Utility Buffer”到 block设计

../_images/image2212.png
  1. 双击“util_ds_buf_0”,选择“C Buf Type”为“IBUFDSGTE”,这种类似是收发器专用参考差分时钟BUFFER,开发板上来自SI5338输出,频率为100Mhz

../_images/image2310.png
  1. 连接 utility buffer 的输出“IBUF_OUT” 到 AXI-PCIe 模块的“REFCLK”输入。

../_images/image248.png
  1. 添加一个“Constant”模块到设计中

../_images/image256.png
  1. 双击“Constant”配置参数Const Val修改“0”

../_images/image266.png
  1. 把xlconstant_0输出连接到axi_pcie_0的输入INTX_MSI_Request

../_images/image276.png

添加复位模块#

设计中有2个时钟,都是来自AXI-PCIe bridge模块的输出,分别为“axi_aclk_out”、“axi_ctl_aclk_out”,一个用于PCIe数据传输,一个用于模块的寄存器控制,所以要添加2个复位模块。

  1. 添加“Processor System Reset”到设计中,默认名称为“proc_sys_reset_0”

../_images/image286.png
  1. 把“axi_pcie_0”模块的输出“axi_ctl_aclk_out”连接到“proc_sys_reset_0”模块的输入“slowest_sync_clk”, 把“axi_pcie_0”模块的输出“mmcm_lock”连接到“proc_sys_reset_0”模块的输入“dcm_locked”,把模块“processing_system7_0”的输出“FCLK_RESET0_N”连接到模块“proc_sys_reset_0”的输入“ext_reset_in”。

../_images/image296.png
  1. 添加“Processor System Reset”到设计中,默认名称为“proc_sys_reset_1”

  2. 把“axi_pcie_0”模块的输出“axi_aclk_out”连接到“proc_sys_reset_1”模块的输入“slowest_sync_clk”, 把“axi_pcie_0”模块的输出“mmcm_lock”连接到“proc_sys_reset_1”模块的输入“dcm_locked”,把模块“processing_system7_0”的输出“FCLK_RESET0_N”连接到模块“proc_sys_reset_1”的输入“ext_reset_in”。

../_images/image306.png

添加DMA模块#

  1. 添加一个“AXI Central Direct Memory Access”到设计中

../_images/image3113.png
  1. 双击“axi_cdma_0”打开配置窗口,“Write/Read Data Width”选择128,不要勾选“Enable Scatter Gather”

../_images/image3210.png

连接中断#

  1. 添加一个“Concat”到设计中

../_images/image337.png
  1. 连接axi_pcie_0模块的中断到xlconcat_0模块的In0端口,连接axi_cdma_0模块的中断到xlconcat_0模块的In1端口,连接xlconcat_0模式的输出dout到ZYNQ PS处理器IRQ_F2P端口。

../_images/image346.png

添加AXI互联模块#

  1. 添加一个“AXI Interconnect”模块到设计中,默认名称为“axi_interconnect_0”

../_images/image356.png
  1. 双击“axi_interconnect_0”,配置参数修改为2个Slave端口,1个Master端口

../_images/image365.png
  1. 连接“axi_interconnect_0”模块的M00_AXI端口到ZYNQ PS处理器的S_AXI_HP0端口

../_images/image375.png
  1. 添加一个“AXI Interconnect”模块到设计中,默认名称为“axi_interconnect_1”

  2. 双击“axi_interconnect_1”,配置参数修改为2个Slave端口,3个Master端口

../_images/image385.png
  1. 连接 “axi_interconnect_1”模块的“M00_AXI” 端口到AXI-PCIe模块的 “S_AXI”端口,连接 “axi_interconnect_1”模块的“M01_AXI” 端口到AXI-PCIe模块的 “S_AXI_CTL”端口,连接 “axi_interconnect_1”模块的“M02_AXI” 端口到CDMA模块的 “S_AXI_LITE”端口

../_images/image395.png
  1. 添加一个“AXI Interconnect”模块到设计中,默认名称为“axi_interconnect_2”

  2. 连接 “axi_interconnect_2”模块的“M00_AXI”端口到 “axi_interconnect_0”模块的“S01_AXI” 端口,连接 “axi_interconnect_2”模块的“M01_AXI”端口到 “axi_interconnect_1”模块的“S01_AXI” 端口,连接 “axi_interconnect_2”模块的“S00_AXI”端口到 “axi_cdma_0”模块的“M_AXI” 端口

../_images/image403.png

连接时钟#

  1. 连接 “axi_aclk_out”时钟到Zynq PS的输入 “M_AXI_GP0_ACLK” 和 “S_AXI_HP0_ACLK”

../_images/image4110.png
  1. 连接 “axi_aclk_out”时钟到“axi_cdma_0”的输入 “m_axi_aclk” 和 “s_axi_lite_aclk”

../_images/image424.png
  1. 连接“axi_interconnect_0”所有时钟到“axi_aclk_out”

../_images/image433.png
  1. 连接“axi_interconnect_1”除了“M01_ACLK”的所有时钟到“axi_aclk_out”

../_images/image443.png
  1. 连接“axi_interconnect_2”所有时钟到“axi_aclk_out”

../_images/image452.png
  1. 连接“axi_interconnect_1”的时钟“M01_ACLK”到“axi_ctl_aclk_out”

../_images/image462.png

连接复位信号#

  1. 连接复位模块“proc_sys_reset_0”的输出“peripheral_aresetn”到AXI互联模块“axi_interconnect_1”的复位输入“M01_ARESETN”。

../_images/image472.png
  1. 连接复位模块“proc_sys_reset_1”的输出“peripheral_aresetn”到AXI互联模块“axi_interconnect_1”的其他复位输入,连接到“axi_interconnect_0”、“axi_interconnect_2”的全部复位输入。

../_images/image482.png

其他连接#

  1. 连接“axi_pcie_0”的“M_AXI”到“axi_interconnect_0”的“S00_AXI”

../_images/image491.png
  1. 连接ZYNQ处理器的“M_AXI_GP0”到“axi_interconnect_1”的“S00_AXI”

../_images/image501.png

端口设置#

  1. util_ds_buf_0差分时钟输入,右键“Make External”

../_images/image518.png ../_images/image522.png
  1. 修改名称为“pcie_ref”

../_images/image532.png
  1. 同样扩展出“axi_pcie_0”的“pcie_7x_mgt”端口,修改名称

../_images/image541.png
  1. 将IIC_0端口引出,端口名为“si5338_iic”,用于配置SI5338

../_images/image551.png
  1. 选择复位模块“proc_sys_reset_0”的输出“peripheral_aresetn”,右键然后选择“Create Port…”

../_images/image561.png
  1. 端口名称填写“pcie_rstn”

../_images/image571.png

地址分配#

  1. 在“Address Editor”窗口点击自动分配图标

../_images/image581.png
  1. 出现一个警告

../_images/image591.png
  1. 把axi_pcie_0的BAR0地址范围改为256M后,重新点击自动分配

../_images/image60.png
  1. 重新分配以后的地址,然后保存block设计

../_images/image616.png

创建HDL封装#

  1. 在“Sources”选项卡中选择Block设计右键,然后“Create HDL wrapper”

../_images/image621.png
  1. 点击“OK”

../_images/image631.png

添加xdc约束#

  1. 在约束选项下点击“Add Sources”,在弹出的窗口选择“Add or create constraints”

../_images/image641.png
  1. 点击“Create”,名称填写pcie,然后点击“Finish”

../_images/image651.png
  1. 修改xdc文件,文件内容不再给出,在开发板给的工程里可以找到(pcie_root/pcie_root.srcs/constrs_1/new/pcie.xdc)。

../_images/image661.png

关键步骤#

pcie模块会自动带上管脚约束信息,但是和我们的硬件设计是不相符的,这个时候需要我们把自带的xdc文件添加不使用属性。

  1. 在模块设计“design_1_i”右键选择“Generate Output Products…”

../_images/image671.png
  1. 在“IP Sources”选项卡中搜索xdc文件,axi_pcie_X0Y0.xdc就是我们要找的文件

../_images/image681.png
  1. 选择这个文件然后右键“Disable File”

../_images/image691.png
  1. 编译生成bit文件

../_images/image70.png

Vitis下载调试#

  1. 导出硬件

../_images/image716.png
  1. 选择包含bit文件

../_images/image721.png
  1. 运行Vitis

../_images/image731.png
  1. 新建一个BSP

../_images/image741.png
  1. 保持默认的工程名,“Board Support Package OS”选择“standalone”

../_images/image751.png
  1. 保持默认配置,选择“OK”

../_images/image761.png
  1. 点击“Board Support Package”/Modify BSP Setting,在“axi_pcie_0”这一行选择“Import Examples”,导入一个例程

../_images/image771.png
  1. 选择“xaxipcie_rc_enumerate_example”

../_images/image781.png
  1. 复制文件用于si5338的配置,相关文件可以到开发板例程的Vitis目录找到

../_images/image791.png
  1. 在Vitis的工程目录选择src目录,右键“Paste”把上面复制的三个文件粘贴到src目录

../_images/image80.png
  1. 修改“xaxipcie_rc_enumerate_example.c”文件,添加si5338的相关配置,先添加头文件

../_images/image816.png
  1. 在PcieInitRootComplex函数中添加si5338的配置,保存编译。

../_images/image821.png
  1. 打开运行配置

../_images/image831.png
  1. 选择“Single Application Debug”双击

../_images/image841.png
  1. 在PCIe 插槽插入PCIe设备,例如SSD,网卡等,连接串口调试终端,选择复位整个系统并编程FPGA,开发板上电后点击“Run”

../_images/image851.png
  1. 串口终端软件输入了一些信息,包括Si5338配置,PCIe设备的一些信息

../_images/image861.png

实验总结#

本实验建立了PCIe Root的Vivado工程,然后通过Vitis裸机程序测试了PCIe枚举设备的功能,为我们PCIe Root应用打下基础,后面教程我们会通过Linux来使用PCIe Root功能。