赞
踩
目录
本文主要以xapp1052作为学习材料,以Sparten6/Kintex-7芯片作为搭建BMD工程举例。
关于BMD工程的仿真环境的搭建,可以参考“Xilinx PCIE DMA 仿真环境搭建”。
相关博客可以参考:
六、Xilinx PCIE DMA--Sparten6/Kintex-7 BMD
本文仅是基于xapp1052,搭建两种芯片的BMD工程。
关于xapp1052有几点说明:
(1)首先,官方提供的xapp1052工程,主要用于测试DMA收发数据的效率,
官方提供完整的DMA收发示例、PIO仿真文件、示例工程可以板级调试;
(2)其次,该xapp1052工程没有将PC发送的FPGA的数据存储下来,而仅是与一个固定数值做比较,测试DMA传输效率;
(3)以及,该xapp1052工程发送的数据,仅是发送 通过PIO配置WDMATLPP寄存器里的数据,即用于测试DMA传输效率;
(4)最后,鉴于本人是初学者,整理的比较浅显,还是请读者多看看参考文献吧!
软件:ISE14.4/14.7
官网:xapp1052
简述PIO与DMA的区别:
PIO操作:通常,PIO传输的数据仅有一个,即MWr、CPLD这类TLP报文里,仅包含一个有效数据。
DMA操作:通常,DMA传输的数据有多个,即MWr、CPLD这类TLP报文里, 包含多个有效数据。
只不过,为了进行DMA的操作,需要提前配置一些控制寄存器;这些配置控制寄存器的过程,是PIO操作。
当MWr、CPLD开始传输多个有效数据时,才是DMA操作。所以,显的复杂一点。
DMA数据传输概述:
首先需要说明:
下面介绍的传输类型,是FPGA作为master主动发起读写请求,PC作为从机进行响应;
实际使用中,FPGA、PC谁都可以作为master,下面的介绍仅是一种参考。
(1)FPGA发DMA数据到PC
首先,PC通过下文figure3配置步骤1-7,该过程是PIO操作,每次配置一个寄存器;
然后,DMA发送模块,发起 存储器写访问事务(MWr),给PC 发送包含数据的写TLP数据包,举例如下图7-5所示。
即这个TLP数据包,包含 1个头标 +n个DW数据,实现DMA数据的传输!
最后,待数据传输完毕,FPGA应该会发送一个中断信号,提示PC数据传输结束;
(2)PC发DMA数据到FPGA
首先,PC通过下文figure4配置步骤1-6,该过程是PIO操作,每次配置一个寄存器;
然后,FPGA的DMA发送模块,发起存储器读请求事务(MRd),给PC发送一个存储器 读请求TLPs,该过程是PIO操作;
再然后,PC返回带数据的完成报文CPLD,FPGA的DMA接收模块、接收该数据流,该过程是DMA操作;
PC返回的CPLD报文如下图所示,下图仅是个举例,可能不完全正确。
该CPLD数据包,包含:一个头标 + n个数据,实现数据的DMA传输!应该类似于下图吧,下图可能不完全正确!
仅是方便理解,才贴上下图的 ....... =。=
最后,带数据传输完毕,FPGA应该会发送一个中断信号,提示PC数据传输结束;
详细传输流程,见下文吧。
有一点需要说明一下,
在上面的步骤4中,组织PCIe Memory Write TLPs时,发送模块发送的是写MEM数据包,即存储器写访问事务(MWr)类型,将待发送的DMA数据发送给PC;
这里FPGA发送模块并不是通过CPLD完成报文的形式将数据发送给PC的。
读者可以细细品味一下两者的区别。
下图是官方提供的xapp1052中,测试FPGA发DMA数据到PC的步骤。
关于下图步骤6有一点需要说明,
PC通过PIO操作配置WDMATLPP寄存器,将测试数据data写入WDMATLPP寄存器;
然后,当启动DMA操作时,发送引擎将WDMATLPP中的数据data重复发送给PC,用以测试DMA写MEM(指PC内存)的效率。
下图是官方提供xapp1052中发送模块对应的几种事务类型,这里引用博主CLGo 的博客里的相关介绍。
值得注意的是:
(1)BMD_64_CPLD_FMT_TYPE:是PIO模式,
标志着发送一个带数据的完成包,这个使用在PC端向FPGA发送一个存储器读请求后,FPGA通过这个报文将存储器信息返回到PC端;
(2)BMD_64_MWR_FMT_TYPE、BMD_64_MWR64_FMT_TYPE:是DMA模式,
标志着FPGA发送存储器 写请求TLPs(MWr),这个使用在启动DMA写时,发送引擎组建存储器写请求包将数据发送到PC上;
(3)BMD_64_MRD_FMT_TYPE、BMD_64_MRD64_FMT_TYPE :是DMA模式,
标志着FPGA发送存储器 读请求TLPs(MRd),
这个使用在PC配置启动DMA读时,发送引擎组建存储器读请求包,PC发送带数据的完成包到FPGA上,被接收引擎接收。
大概过程如下:
(1)首先电脑申请一片连续内存,
(2)接着电脑通过PIO模式配置FPGA上的控制状态寄存器(就是表格中的Step1~Step6),
(3)然后FPGA检测到读DMA请求后,发送引擎组装 存储器 读请求报文(MRd) 并发送,
(4)接收引擎接收电脑反馈的完成包CPLD,
(5)最后,FPGA发送中断结束传输。
下图是官方提供的Xapp1052中,测试PC发DMA数据到FPGA的步骤。
关于Xapp1052提供的BMD接收引擎,并结合上面的步骤(4)和下面的步骤1-8有一点需要说明一下:
在接收引擎开始接收来自PC返回的CPLD数据包时,接收引擎并没有将该DMA数据存入FPGA内部缓存MEM,
而是将接收到的数据与RDMATLPP寄存器中的数据进行数据比较,但配置RDMATLPP寄存器的过程,却没有在下面的步骤1-8中体现。在xapp1052的PDF中,相关描述如下:
下图是官方提供xapp1052中接收模块对应的几种事务类型,这里引用博主CLGo 的博客里的相关介绍。
值得注意的是:
(1)BMD_MEM_RD32_FMT_TYPE 、BMD_MEM_WR32_FMT_TYPE :是PIO事务,
两种标头对应的TLP是以PIO的模式传输,其作用是上位机读写DMA控制状态寄存器,就是上文的DMA体系结构中的Control and Status Registers。
(2)BMD_CPL_FMT_TYPE 、BMD_CPLD_FMT_TYPE :是DMA事务,
是FPGA发送 DMA读请求(MRd)后,PC端反馈的完成包CPLD是DMA模式。
下图是PIO配置一些寄存器的整理:
目前对PCIe 部分的上位机驱动开发的软件比较常用的是windriver 和DDK 这2 款开发工具。DDK 是Device Development Kit,设备开发包的意思。为windows 设备驱动程序开发包。一般是在VC 或者VS 软件环境下进行开发。相对于Windriver,DDK 需要开发人员对驱动更加深入的了解。
Windriver 是jungo 公司为驱动程序开发提供的一个工具,特别适合初学者使用。它把PC 硬件系统的驱动程序开发进行了高度的集成和封装,开发者甚至不需要设计驱动程序,所需要做的工作几乎仅仅是保证设备的硬件和相应固件设计正确,然后进行
应用程序的设计,而应用程序的设计也可以通过对Windriver 产生的debug 程序进行修改而得到。
WinDriver™ PCI / ISA User's Manual
软件驱动开发
安装好Windriver后,即可完成PCIe驱动的开发了。首先你需要安装VS2008,用来打开Windriver的驱动源码,并进行修改和测试。下面我们来详细的了解整个软件
开发和测试的流程。
Step1 : 我们首先找到Windriver的安装目录,如图所示,在安装目录下有各个公司的开发工程以及开发软件包。这里我们找到xilinx文件夹,进入下一步。
打开Windriver 软件,并新建工程项目,用户可以为自己的设备生成相关的INF 驱动文件,这里如果用户下载了我们板卡所提供的PCIE 文件至开发板,则可在如图8-2-4 中找到我们的XILINX PCIe 设备,点击Gneratate .INF file。
如图8-2-5所示,用户可以自定义厂商的ID,设备ID以及设备类型,修改相关属性后,勾选上automatically install the INF file,即可完成PCIE的驱动安装。
安装完成后,用户即可在设备管理器中找到自定义的设备
软件驱动开发
Step1 : 我们首先找到Windriver的安装目录,如图8-2-7所示,在安装目录下有各个公司的开发工程以及开发软件包。这里我们找到xilinx文件夹,进入下一步。
Step2 : 使用VS2008 打开“安装路径\xilinx\virtex5\bmd\diag\x86\msdev_2008”里的工程,如图8-2-8所示。本工程虽然是Virtex5型号的FPGA PCI驱动代码,但也同样适用于大部分Xilinx公司的PCIE的驱动代码的开发。
Step3 :此时如果你确定已经下载好了PCIE DMA的FPGA文件,我们可以点击菜单栏下的“启动调试(F5)”,来进行工程调试。
这里我们更加关注DMA的相关测试,我们选择测试项7,即Direct memoryaccess(DMA)-Interrupts completion method,按照操作步骤选择open dma,并选择From device或者to device,来确定数据的传输方向,填入TLP的个数,以及TLP的测试数据。
OK,现在我们大致已经知道如何通过Windriver所提供的开发工具在VS2008的测试与开发,那么接下来我们再来分析下VS2008下的驱动代码。
VS2008驱动代码分析
1.通过VS2008打开Virtex5的BMD工程,如图8-2-11所示,包含6个c文件。图8-2-11 BMD 驱动文件
实际上用户几乎不需要做大量的修改,如果用户只需要进行DMA方面开发的话,只需要通过MenuDMAOpen函数
将需要配置的DMA数据大小,数据缓存,以及完成方式配置到该函数中,并启动DMA即可。
- static void MenuDMAOpen(WDC_DEVICE_HANDLE hDev, PDIAG_DMA pDma, BOOL fPolling)
- {
- DWORD dwStatus, dwOptions, dwTotalCount, i;
- UINT32 u32Pattern;
- WORD wSize, wCount;
- BOOL fIsRead;
- BOOL fEnable64bit;
- BYTE bTrafficClass;
- /* Get input for user */
- if (!MenuDMAOpenGetInput(&wCount, &u32Pattern, &dwOptions))
- return;
- fIsRead = dwOptions & DMA_FROM_DEVICE ? FALSE : TRUE;
- pcie_opratetype = dwOptions & DMA_FROM_DEVICE ? FALSE : TRUE;
- /* The BMD reference design does not support s/g DMA, so we use contiguous
- */
- dwOptions |= DMA_KERNEL_BUFFER_ALLOC;
- /* Get the max payload size from the device */
- wSize = VIRTEX5_DMAGetMaxPacketSize(hDev, fIsRead) / sizeof(UINT32);
- dwTotalCount = (DWORD)wCount * (DWORD)wSize;
- /* Open DMA handle */
- dwStatus = VIRTEX5_DMAOpen(hDev, &pDma->pBuf, dwOptions,dwTotalCount * sizeof(UINT32),
- &pDma->hDma);
- if (WD_STATUS_SUCCESS != dwStatus)
- {
- printf("\nFailed to open DMA handle. Error 0x%lx - %s\n", dwStatus,
- Stat2Str(dwStatus));
- return;
- }
- printf("\nDMA handle was opened successfully (handle 0x%lx)\n", pDma->hDma);
- printf("Payload packet size in dwords 0x%hx\n", wSize);
- /* Prepare the device registers for DMA transfer */
- fEnable64bit = FALSE;
- bTrafficClass = 0;
- VIRTEX5_DMADevicePrepare(pDma->hDma, fIsRead, wSize, wCount, u32Pattern,fEnable64bit,
- bTrafficClass);
- if (!fPolling) /* Enable DMA interrupts (if not polling) */
- {
- VIRTEX5_DmaIntEnable(hDev, fIsRead);
- if (!VIRTEX5_IntIsEnabled(hDev))
- {
- dwStatus = VIRTEX5_IntEnable(hDev, DiagDmaIntHandler);
- if (WD_STATUS_SUCCESS != dwStatus)
- {
- printf("\nFailed enabling DMA interrupts. Error 0x%lx - %s\n",
- dwStatus, Stat2Str(dwStatus));
- goto Error;
- }
- printf("\nDMA interrupts enabled\n");
- }
- }
- else /* Disable interrupts (polling) */
- VIRTEX5_DmaIntDisable(hDev, fIsRead);
-
-
-
- /*
- 在下面代码中
- 我们可以将所需要dma写入的数据填入pDma->pBuf,
- 该试验我们填入的是一串递增数据i,然后PCIE DMA将会按照用户设置的TLP包的个数,
- 当前TLP所支持的最大TLP的数据大小wSize,以及本次操作的读写类型fIsRead设置为0
- 选择DMA写。
-
- */
-
-
- /* Initialize the DMA buffer with user defined pattern */
- for (i = 0; i < dwTotalCount; i++)
- {
- if (fIsRead)
- ((UINT32 *)(pDma->pBuf))[i] = i;
- else ((UINT32 *)(pDma->pBuf))[i] = 0xdeadbeaf; /* to be overwritten by
- WRITE dma */
- }
- /* Start DMA */
- printf("Start DMA transfer\n");
- VIRTEX5_DMAStart(pDma->hDma, fIsRead);
- TimeStart();
- /* Poll for completion (if polling selected) */
- if (fPolling)
- {
- if (VIRTEX5_DMAPollCompletion(pDma->hDma, fIsRead))
- {
- DmaTransferVerify(hDev, pDma->pBuf, dwTotalCount, u32Pattern,
- fIsRead);
- }
- else
- printf("timeout\n");
- }
- return;
-
-
-
-
-
- Error:
- DIAG_DMAClose(hDev, pDma);
- }
-
-
-
-
如果用户需要读取从PCIE的设备端返回的数据,则从中断处理函DiagDmaIntHandler中读取pIntResult->pBuf即可,如下表代码所示。
- static BOOL DIAG_DMAVerifyPattern(WDC_DEVICE_HANDLE hDev, PVOID pBuf,
- DWORD dwTotalCount, UINT32 u32Pattern, BOOL fIsRead)
- {
- DWORD i;
- /* Transfer to device, check HW error bit */
- if (fIsRead)
- return VIRTEX5_DmaIsReadSucceed(hDev);
- //Transfer from device, check DMA buffer
- for (i = 0; i < dwTotalCount; i++)
- {
- if (((UINT32 *)(pBuf))[i] != i)
- {
- VIRTEX5_ERR("Data mismatch, pBuf[%ld] = %08X, u32Pattern = %08X\n",i, ((UINT32
- *)(pBuf))[i], u32Pattern);
- return FALSE;
- }
- }
- return TRUE;
- }
Step1:登录www.xilinx.com官网,在搜索栏中输入xapp1052,xapp1052是xilinx专为用户PCIe DMA开发应用的demo,里面包含有PCIE DMA开发与应用的硬件代码与上位机的驱动代码。如图8-3-1所示,用户需要下载图中的xapp1052.pdfxapp1052.zip。
Step2:将xapp1052.zip解压后我们即可发现以下文
在下图的代码中,有几个.V文件需要说明一下,
(1)xilinx_pcie_2_1_ep_7x.v :来自IPCore的 example 的 顶层。
在该文件里,例化的app pcie_app_7x 可能一些管脚比较多,而这些多出来的管脚,在pcie_app_7x_bmd.v文件里不存在,这样会导致PIO仿真报错。因此注意对比删除。
(2)pcie_app_7x_bmd.v :来自xapp1052里的128事例工程,复制过来后,需要将128修改为64即可。
(3)axi_trn_top.v等 :来自xapp1052里的128事例工程,直接复制过来即可。
(4)其他所有文件 :从xapp1052里复制即可。
代码层次如下:
将BMD_PCIE_20.V如下图所示,设置为全局的文件。这样我们的工程就基本建立完成。
暂不更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。