刘敬辉,简献忠,肖儿良,姜冠祥,蔡留美,郑照平
(1.上海理工大学 光电信息与计算机工程学院,上海 200093;2.上海雄博精密仪器股份有限公司,上海 200444)
基于WinDriver的高速PCI卡驱动开发
刘敬辉1,简献忠1,肖儿良1,姜冠祥2,蔡留美2,郑照平2
(1.上海理工大学 光电信息与计算机工程学院,上海 200093;2.上海雄博精密仪器股份有限公司,上海 200444)
针对目前大数据背景下如何提高PCI卡高速传输稳定性的问题,文中提出了基于内核中断处理及DMA传输的PCI卡驱动程序设计方法。在WinDriver生成驱动框架的基础上,采取基于VC++6.0平台进行了DMA 数据传输的实现和中断响应处理的PCI驱动程序开发。将驱动程序封装为动态链接库,用户程序调用DLL驱动PCI卡,进行高速数据传输检测。实验发现,当数据传输速度达到131 MB/s时,驱动程序运行稳定可靠不丢帧不错帧,为高速稳定PCI卡驱动程序的设计供了一种思路。
WinDriver;PCI;驱动程序;DLL
目前大数据[1]越来越受到人们的重视,如何提高高速数据传输的稳定性具有重要意义。外设部件互联总线(PCI)标准是一种高速的传输协议,经过几年的发展已经替代ISA、MAC等总线成为PC机主流总线标准[2]。它是一种地址线和数据线复用的高性能的32/64总线[3];且支持DMA传输机制[4]。因此PCI得到了广泛的应用。
基于Windows环境下PCI驱动程序的开发工具主要包括DDK[5],DriverStudio[6]和WinDriver[7]。相较于前两者Jungo公司的WinDriver改变了传统驱动程序开发方法,整个程序都工作在用户态下,使开发者不需要掌握两者所需要的预备知识就可以开发出与之相媲美的程序,大幅降低了开发难度[8]。目前国内外学者进行了广泛的研究[9-10],但存在高速传输稳定性的隐患,如文献[5]清中断标志没有在内核中进行,导致清中断标志操作滞后,增加了中断误响应的概率;文献[9]采用直接调用函数锁定DMA缓冲区,该方式存在当关闭程序并未停止数据传输时,会出现DMA缓冲区已经解锁,而PCI仍然向该内存地址写数据,从而导致PC机死机或重启等问题。
针对目前PCI卡高速传输稳定性存在的问题,本文提出了基于内核中断处理及DMA传输的PCI卡驱动程序设计方法。为了实现主控计算机与目标板的快速数据传输,采用乒乓DMA方式传输数据。软件开发基于VC++6.0平台,为了便于用户程序的调用,按照模块化软件思想,驱动程序以DLL动态链接库的方式进行封装。为了提高驱动程序的稳定性采用内核清中断操作。为了提高驱动程序的容错率采用开机时分配DMA缓冲区的方式。为提高工作效率,缩减开发周期选用WinDriver为开发工具。
1.1 WinDriver
Jungo公司的WinDriver是一款简洁高效不涉及操作系统底层编程且兼容性很好的驱动开发工具。把所有复杂的底层操作都封装在一个内核模块中,提供给用户标准的WinDriver API函数来实现硬件访问,加快了开发周期[10]。WinDriver体系结构如图1所示,它由用户模式和内核模式2部分组成[11]。用户模式由WinDriver的用户模式库以及用户编写的驱动程序代码组成,驱动程序通过调用WinDriver库函数(Windrvr.h)实现对硬件的操作。内核模式分WinDriver内核模块和内核嵌入两部分。WinDriver内核模块对用户态库提供服务支持,硬件通过内核模块来传递中断请求信息和对I/O端口以及内存映像地址的读写信息,同时内核模块将中断处理以及端口读写信息传递给内核嵌入部分,内核嵌入完成用户态代码的嵌入,实现代码核态下运行。
图1 WinDriver体系架构图
1.2 基于WinDriver驱动程序开发步骤
WinDriver开发PCI驱动程序步骤如下:
(1)将PCI板卡插到机箱对应PCI插槽中运行DriverWizard,在设备列表中找到并选中PCI设备,生成 INF文件,然后添加新硬件;
(2)测试硬件,利用Wizard来自动诊断硬件的地址读写操作能否进行,检查寄存器及相关中断是否正常;
(3)生成基于C++语言的驱动程序代码框架;
(4)在生成驱动程序代码框架的基础上调试修改制作符合用户程序要求动态链接库;
(5)打包驱动程序(INF文件,DLL文LIB文件,函数头文件);
(6)用户程序调用动态链接库,完成定制功能。
本驱动程序的主要功能是实现PCI卡的I/O以及内存映射地址的读写,还有对PCI卡发出中断的处理;针对高速传输稳定性问题,主要进行DMA缓冲区锁定方式,数据传输机制,中断机制和DLL接口4个方面的设计。
2.1 DMA缓冲区的锁定
PCI进行DMA传输数据到上位机,需要通过WinDriverAPI函数锁定内存区域作为数据缓冲区。而WinDriver锁定DMA缓冲区有两种方式,一种是分配一整块连续的指定大小的内存块(WDC_DMAContigBufLock())另一种是分配离散的指定大小的内存块(WDC_DMASGBufLock())[12]。
但是,不管用哪种方式,若只是简单的调用函数锁定DMA缓冲区就会出现以下问题:当关闭程序时并未停止数据传输,就会出现DMA缓冲区已经解锁,而PCI仍然向该地址写数`据,从而导致PC机死机或重启等状况。
WinDriver V12.0.0的一项新功能[13]可以完美解决此问题,即可以实现在开机时分配内存,即使程序不正常关闭,该内存区域却不会解锁,大幅提高了驱动程序的容错性,要实现该功能需要使用前者锁定缓冲区,所以采用函数WDC_DMAContigBufLock()。
整体操作流程如下:首先更改驱动INF文件的注册项目[UpdateRegistryDevice]下的语句,更改要锁定两块内存的大小,这样在开机时就会自动锁定两块内存缓冲区;在驱动程序初始化锁定内存时调用WDC_DMAContigBufLock(),参数要设置成与INF文件中的相匹配,这样所锁定的内存区域就会自动分配到开机时已经锁定的内存块中。缺点是所锁定的内存会一直被占用,优点是极大的提高了驱动程序的稳定性和容错性。
2.2 乒乓高速DMA传输
为完成大批量数据的高速传输,现开辟两块固定大小的DMA缓冲区通过WinDriver的API函数将该内存映射到PCI可以直接访问的物理地址中。通过寄存器将PCI访问内存的物理地址通知PCI。当开始传输寄存器有效时,PCI开始循环以DMA的方式向两块DMA缓冲区写入数据,每传输完一次数据发出一次中断,并置位内存块选择标志寄存器。
WinDriver中提供了WDC_DMASyncCpu()函数来完成DMA数据搬运,作用是将DMA缓存快中的数据搬移到CPU缓存中。PC机收到中断响触发事件,然后通过内存块选择标志寄存器判断读哪一块内存。通过乒乓DMA数据传输方式保证数据传输的高速稳定。传输机制如图2所示。
图2 PCI与PC机传输示意图
2.3 内核清中断机制
当PCI传输数据到DMA缓存区后,每完成一块缓存区的数据传输,则触发一次PCI中断。
当PCI在高速传输数据的过程中,每秒可触发中断100次,高速有效的中断响应机制对PC机来说尤为重要。PCI中断是电平触发中断,收到中断后需要立即清除,即向中断清除寄存器写1,否则会导致中断重复响应;并且由于PCI采用中断共享,同一个中断号会被多个硬件设备所共用,为防止中断误响应,需添加中断标志寄存器用于区别于其它设备的中断,而中断标志的清除同样要在中断触发时立即执行,否则操作系统可能误响应其它设备发出的中断。针对此问题,WinDriver中可以设计实现在内核中进行中断信号的判断和清除[14]。在开发者调用WDC_IntEnable()函数时可以向内核传递一条WD_TRANSFER结构体指令,在结构体中可以定义中断来时内核的操作,现共定义了3个操作:
(1)读命令:读中断标志寄存器;
(2)CMD_MASK命令:判断中断标志寄存器中读出的的数据是否为1,是则继续向下执行,否则忽略该中断;
(3)写命令:清除中断标志,清除中断信号。
通过以上中断初始化操作后,每当触发中断,内核便会立刻执行WD_TRANSFER结构体定义的指令,即立刻清除中断信号和中断标志。然后调用中断处理函数,进而进行数据传输和处理。中断响应流程如图3所示。
2.4 PCI驱动程序DLL接口设计
为了便于用户程序访问驱动程序,驱动程序将被封装为动态链接库(DLL),用户程序通过调用DLL的接口函数从而达到对PCI卡发送控制命令从而实现PCI到PC机的数据传输。为了方便用户程序调用,现以模块化的软件设计思想,接口函数设计在满足用户程序所需功能的基础上尽可能简单规范,主要接口及其功能描述如下:
BOOL OpenDevice();打开设备
BOOL CloseDevice();关闭设备
BOOL CreateEvents(HANDLE hEvent);将建立好的事件句柄给驱动程序
BOOL ClearEvent(HANDLE hEvent);清除事件
BOOL CreateDMABuffer(ULONG size, PUSER_DMA_ADDRESS DMAAddess);分配数据缓存区
BOOL CloseDMABuffer (PUSER_DMA_ADDRESS pdma_address);关闭数据缓存区
ULONG MemReadDword(int memrange, ULONG offset);读pci空间
BOOL MemWriteDword(int memrange,ULONG offset,ULONG val);写pci空间
图3 中断响应流程图
3.1 PCI用户程序开发
PCI驱动程序成功实现并进行DLL封装后,下一步即考虑实际应用。DLL不能单独运行,必须作为应用程序的一个软件模块,与应用程序一起完成既定的功能。应用程序通过对驱动程序DLL的有效使用完成设备初始化、开辟缓冲区、读写寄存器、DMA数据采集等操作。
图4 中断响应流程图
具体操作流程如下:(1)打开设备,调用函数OpenDevice();(2)开辟两块DMA缓冲区(每块大小640×513×4Byte),调用函数CreateDMABuffer();(3)创建事件,调用函数CreateEvents()输入事件句柄给驱动程序;(4)初始化参数设置,通过写寄存器设置光纤源、图片规格、像素格式等参数;(5)开始传输,新建一线程循环等待事件被触发,并向传输开始寄存器写1;(6)事件被触发,PC机从缓冲区地址读取传输的数据,将数据保存到本地文件,并实时显示图像及帧号等信息实时显示在MFC界面上被触发,如图4所示;(7)结束传输,向开始传输寄存器写0,即停止传输。调用函数CloseDMABuffer(),关闭两块缓冲区,调用函数CloseDevice()关闭设备。
3.2 实验结果分析
在硬件方面,PCI卡采用Xilinx公司XC7A200T-2FFG1156 主芯片作为硬件主控平台,设有两块光纤模块,分别用于传输16位和32位的数据,总线时钟频率设置为66 MHz保证FPGA内部数据传输速率。
现设计数据源每秒产生100帧640×513×32 bit(数据源的产生速度为131 MB/s)的灰度图像数据,通过光纤1传进PCI采集卡。此灰度图像数据前512行数据为图像每个像素点的像素信息;第513行为图像信息,其中第513行的第111个32位数为帧号,每帧图片帧号依次加1。在工程中,PCI内部对发出的中断数进行计数;驱动程序在中断服务程序中进行中断计数,用户程序计数最终响应事件的次数,截取从第一次传输数据开始到1 200 s时间内各个数据的变化如下。
表1 1 200 s后帧号与各部分中断计数值变化
从表中可以看出,4个差值完全相同,即1 200 s中数据源发送的帧数与PCI向PC机发送的帧数,驱动程序响应中断数和传输事件激活次数相同。以每秒100帧的速度,理论上1 200s应该传输120 000帧数据,与测得120 024有误差,是由于计时本身存在误差。
尽管WinDriver是一款功能强大,使用方便的驱动开发工具,但若要使编写的代码更加的稳定高效,还需要认真研读WinDriver生成的驱动框架,进而完成代码的精简和优化。在本文中主要对以下几个方面做出优化:内核中进行中断的判断和清除,避免中断误响应;开机时锁定DMA缓存区,保证该缓存区一直处于被锁定状态;设计规范通用的DLL接口函数方便用户程序调用。该接口卡目前应用到三维免模板磨边机系统中,进行高速数据传输实验发现,设计的PCI接口卡驱动程序具有传输速率高,稳定可靠等特点, 能够实现在131 MB/s的速度下,数据传输稳定,满足项目高速稳定传输数据的需要。
[1] 冯永强,张良,冯怡,等. 大数据应用的现状与展望[J].信息化建设,2015(12):292-298.
[2] PCI.PCI local bus specification revision 2.1[M]. PCI Special Interest Group,1996.
[3] 邢林峰.PCI总线接口技术在高速数据传输系统中的应用[J].自动化仪表,2007(S1):182-185.
[4] 李小龙,孟李林,邵瑞瑞,等.基于FPGA的PCI Express应用平台设计[J].电子科技,2014,27(12):108-111.
[5] 李晃,巩峰,陈彦化.基于PCIE驱动程序的数据传输卡DMA传输[J].电子科技,2014,27(1):117-120.
[6] 赵彬,田泽,陈佳. 基于DDK的PCI设备驱动程序设计[J].电脑知识与技术,2011(7):1534-1536.
[7] 杨波,柳征,姜文利. 用DriverStudio开发PCI总线设备驱动程序[J]. 微计算机信息,2007(25):279-281.
[8] 刘映杰,张在峰,刘玮,等. 用WinDriver开发PCI设备驱动程序[J].信息技术,2004(2):78-80.
[9] 王聪,王彬,薛洁,等. 基于PCIe总线协议的设备驱动开发[J].信息技术,2013(3):32-35.
[10] 龙杨喜,孙书鹰,宋新民,等.基于Windriver的设备驱动开发[J].微计算机信息.2004(7):63-64.
[11] 景琦,殷永红,李鹏. 利用WinDriver开发设备驱动[J]. 现代电子技术,2005(19):67-69.
[12] 孙晓晔.基于PCIE的SGDMA高速数据传输系统[J].计算机技术与发展,2013(9):195-198.
[13] Jungo Ltd.WinDriver PCI/ISA/CardBus user’s manual v12.0.0[M].US: Jungo Ltd,2015.
[14] 胡波,原新晶. WinDriver开发驱动程序的KernelPlugIn技术的研究与应用[J]. 计算机应用,2003(11):134-136.
Design on Driver Program of High Speed PCI Card Based on WinDriver
LIU Jinghui1,JIAN Xianzhong1,XIAO Erliang1,JIANG Guanxiang2,CAI Liumei2,ZHENG Zhaopin2
(1. School of Optical-Electrical and Computer Engineering, University of Shanghai for Science and Technology, Shanghai 200093,China; 2.Shanghai SUPORE Instruments Co.Ltd, Shanghai 200444,China)
The method of designing the driver of PCI card was proposed which based on the kernel interrupt handling and DMA transfers, with regard to the problem of improve the stability of high-speed transmission PCI card and the environment of big data. PCI driver had been designed at platform of VC++6.0, which Based on the framework of driver generated by WinDriver, include the DMA data transfer and interrupt response processing. Then the driver was encapsulated into a DLL. User program drove PCI card by calling DLL, and processed the data transfers and detection. It was found that when the speed reached 131 MB/s, the driver was stable and reliable without losing frame or error frame, which provided a new way for the driver of high-speed and stable PCI card.
WinDriver; PCI; driver; DLL
2016- 06- 02
上海市宝山区科委产学研基金资助项目(bkw2015130)
刘敬辉(1991-),男,硕士研究生。研究方向:嵌入式系统。简献忠(1969-),男,博士,教授。研究方向:新能源等。
10.16180/j.cnki.issn1007-7820.2017.04.010
TP319
A
1007-7820(2017)04-040-04