摘 要 介绍了一种基于cpci总线的高速数据采集卡硬件及其wdm驱动程序设计方法,详细说明了计算机通过驱动程序与数据采集卡硬件进行高速数据交换的方法,利用driverworks完成了满足高速数据传输要求的wdm驱动程序设计,实现了数据采集卡与主机内存之间数据传输的dma方法。
关键词 数据采集;wdm ;cpci;driverworks;dma
1 引言
cpci总线机械特性上有vme总线的坚固特性,在数据传输方面采取与pci一致的传输方法。高速数据采集系统中,总线数据传输能力要求强,数据采集系统采用cpci总线,极大提高了数据采集卡的数据传输能力。为了充分发挥cpci总线数据传输快、高可靠的优势,要解决好基于cpci总线的数据采集卡与计算机主机之间的通信问题。WWW.133229.COMwindows2000操作系统对cpci总线提供良好的支持,该操作系统下,驱动程序的编写基于一种新的驱动模型wdm(windows driver model),wdm为windows98/2000/xp操作系统的设备驱动程序的设计提供了统一的框架。本文介绍的基于cpci总线的高速数据采集卡用于某数字化仪(digitizer)中,借助用driverworks开发的wdm设备驱动程序,用户应用程序和数据采集卡之间相互通信,实现主机命令的即时传送和板卡采集数据的高速传输。
2 硬件系统设计
针对不同的应用要求,cpci接口卡设计采用的设计方案,一是使用pci专用接口芯片与fpga相结合的方案,专用接口芯片完成从pci总线到本地用户总线的转接;fpga灵活的转换逻辑时序,以适应不同的外设时序要求;二是采用可编程逻辑器件实现通用pci总线接口,很多生产可编程逻辑器件的厂商都提供经过严格测试的pci接口功能模块,由用户进行简单的组合设计即可。考虑到开发周期,本cpci数据采集卡采用前一种设计方法,用pci专用接口芯片实现。系统硬件组成如图1所示。
本数据采集卡pci接口芯片选用plx公司的pci9054, pci9054提供两个独立的可编程dma控制器,有两个dma通道,每个通道均支持block(块传输)和scatter/gather(散/集传输)的dma方式,pci总线端支持32位/33mhz;本地端可编程实现8、16、32位数据宽度,传输速率最高可达到132m字节/秒。本地总线端时钟最高可达50mhz,支持复用(j模式)和非复用的32位地址/数据(c模式)。pci9054工作方式有:直接主模式,直接从模式和dma模式。直接主模式由本地处理器访问pci总线上的i/o接口和计算机内存资源,本地处理器发起数据的传输。直接从模式指pci总线作为主控设备发起对本地总线资源的访问,包括对本地处理器的控制和对本地内存的访问。dma模式支持pci总线与本地总线之间的突发传输。pci9054实现了pci总线到局部端总线的转接,用该芯片做设计时,不必对pci规范作全面深入理解,方便用户在设计时专注于具体功能的实现。
本设计中pci9054设置为非复用的32位地址/数据,即c模式,采用直接从模式和dma方式分别传输主机命令和数据采集卡采集到的数据;可编程逻辑器件fpga里边配置一个fifo作为缓冲器,当主机向数据采集卡发送命令时,fifo作为命令数据的缓冲器,命令数据发送完毕,引起dsp的一个中断,dsp从fifo里读出命令数据,对命令解析,完成实际的硬件操作;当主机要读取数据采集卡采集到的数据时,dsp对sram中数据作预处理,上传到fpga里边配置的fifo中,这时fifo作为数据采集卡上传数据的缓冲器,当fifo数据满时,引起pci中断,通知上层应用程序读取数据。eeprom中存放设备号,厂商号以及本地总线的基地址空间,i/o空间,中断控制信号等信息,初始化时,系统将eeprom配置参数装入pci配置寄存器,并根据本地总线对内存,i/o端口和中断的需求统一划分,自动分配系统资源。
3 数据采集卡wdm驱动程序设计
3.1 wdm模型(windows driver model)简述
wdm模型(windows driver model) 是微软公司为windows98和windows2000的驱动程序设计的一种架构,在wdm驱动程序模型中,每个硬件设备至少有两个驱动程序。其中一个为功能驱动程序,它了解硬件工作的所有细节,负责初始化i/o操作,处理i/o操作完成时所带来的中断事件,为用户提供与设备相适合的控制方式;另一个驱动程序为总线驱动程序,它负责管理硬件与计算机的连接,总线驱动程序由操作系统提供。window2000 系统结构图如图2所示,应用程序调用windows子系统win32 api,这个调用由系统服务接口作用到i/ o 管理器,i/ o 管理器进行必要的参数匹配和操作安全性检查,然后由这个请求构造出合适的irp(i/o request package) 。irp是ddk定义的一个数据结构,具有丰富的成员,对于单层驱动程序,直接接受并执行这个请求包,完成对硬件的操作,从而完成i/ o请求工作,并将执行的结果通过i/ o 管理器返回应用程序;对于多层驱动则将驱动程序分成若干层,每层驱动再把i/ o 请求划分成更简单的请求,以传给更下层的驱动执行。
图2 windows2000 系统结构
3.2 驱动程序设计实现
该数据采集卡驱动程序完成以下功能:应用程序控制数据采集卡工作方式,向数据采集卡工作方式缓冲器发送工作方式控制字;应用程序查询数据采集卡工作状态,从数据采集卡工作状缓冲器读取工作状态字;为了使应用程序能实时处理数据采集卡上采集到的数据,sram与主机内存之间要实现dma方式的数据传输。
采用vc+ddk+driverworks进行驱动程序开发,driverworks为驱动程序开发提供向导,可以方便的建立一个驱动程序框架。下面分别说明控制命令和dma方式传输数据的实现方法。
1)主机发送数据采集卡控制命令实现
driverworks利用kmemoryrange和kiorange实现内存和i/o映射空间的读写,通过配置eeprom,将pci9054的base2空间设定为一个内存映射空间,局部端fpga上配置的fifo地址空间映射到该内存空间,这样对fifo的访问,就是访问base2空间。驱动程序中,创建对象kmemoryrange m_memoryrangeforb2,并在onstartdevice(kirp i)例程中对该对象初始化,使该对象与base2空间关联,初始化以后,驱动程序其他例程就可以使用对象
m_memoryrangeforb2,调用kmemoryrange类的成员函数ind、inw、inb、outd、outw、outb完成对pci9054 base2空间的双字、字、字节的输入输出操作,也就是对数据采集卡fpga里边fifo双字、字、字节的输入输出操作。对io端口的访问类似,只是使用的是kiorange类来完成。
需要注意的是pci9054 base0、base1固定设置为内存映射空间和i/o映射空间,用于pci9054内部寄存器的访问,base2、base3用户自己根据eeprom配置来设定为内存映射空间或者i/0映射空间。在驱动程序设计过程中,经常需要设置和查询pci9054内部寄存器,访问pci9054内部寄存器,要用到base0或base1空间,本设计中,对pci9054内部寄存器访问利用base1,即io映射空间,比如:pci9054 dma通道0传输字节数寄存器偏移为0x8c,若要设定dma通道0一次传输的字节数,可以通过初始化了的kiorange对象m_iorange0的成员函数outd来实现。
下面以主机由驱动程序向数据采集卡发送工作方式控制字为例,说明kmemoryrange成员函数访问硬件的方法,代码中m_memoryrangeforb2为kmemoryrange对象,用于base2空间的访问。
ntstatus dzdevice::dzdriver_ioctl_write_handler (kirp i)
{
ntstatus status = status_success;
pulong pbuffer=(pulong)i.ioctlbuffer();//输入参数
ulong m_offset=*pbuffer; //控制字寄存器在局部地址空间上的偏移
ulong m_data=*(pbuffer+2) ;//控制字
m_memoryrangeforb2.outw(m_offset,m_data);//向寄存器写控制字
i.information() = sizeof(ulong); //本次操作传输的字节数
return status;
}
驱动程序控制字写函数中,首先取得从应用程序传递的偏移地址和控制字的指针,偏移地址和控制字存储在irp的associatedirp域中systembuffer指针指向的缓冲区,驱动程序先取得指向该缓冲区的指针,然后分别取得偏移地址和控制字,最后向该偏移地址写控制字,程序执行后,即向硬件上的寄存器写入了相应的控制字。
2)dma方式读取fpga上fifo数据实现
driverworks提供了3个类kdmaadapter、kdmatransfer、kcommondmabuffer用于实现dma操作,kdmaadapter类用于建立一个dma适配器对象,说明dma通道特性和提供串行化访问的服务;kdmatransfer类用于启动,控制dma的传输以及dma传输结束后数据由公用缓冲区拷贝靠应用程序数据缓冲区;kcommondmabuffer类用于申请系统提供的公用缓冲区。driverworks中,实现dma传输过程如图3所示。
首先在设备启动例程(onstartdevice)中创建一个kdmaadapter类实例且在适配器对象描述表中正确描述适配器对象;创建一个kcommondmabufer类实例,调用该类的成员函数initialize初始化公用缓冲区大小;创建一个kdmatransfer类实例,并初始化为使用公用缓冲区作为dma数据区。然后编写kdmatransfer回调函数ondamready,回调函数中,先调用成员函数byteremaining(),判断数据是否传输完成。若完成,则调用函数terminate()完成相应当irp;未完成,则调用gettransferdescripters(),获取当前传输数据的物理地址,传输字节数,然后进入startdma例程设置pci9054的dma寄存器,开始真正数据传输。当前段传输完成时,pci9054的dma中断控制器产生一个dma中断,进入中断服务例程(isr),中断服务例程中,首先判断是否为dma通道的中断,然后禁止本次中断,再清除本次中断,最后连接到延时过程调用(dpc)。延时过程调用(dpc)中,调用kdmatransfer类的continue()成员函数,继续下一个段传输,直到dma数据传输结束,完成该irp。
3.3 驱动程序和应用程序之间的通信
驱动程序和应用程序之间的通信包括应用程序与驱动程序通讯和驱动程序与应用程序的通信。应用程序与驱动程序通信过程为,应用程序先用createfile函数打开设备,然后用deviceiocontrol和驱动程序通信, deviceiocontrol使用不同的命令字来调用驱动程序中的函数,包括从驱动驱动程序读取数据和写数据给驱动程序两种情况。也可以用readfile从驱动中读取数据或者用writefile写数据给驱动程序,当应用程序退出时,用closehandle关闭设备。
当驱动程序捕捉到特点事件发生时,应当通知应用程序,与应用程序通信,驱动程序和应用程序通信的方法主要有两种,deviceiocontrol异步调用和win32事件通知。deviceiocontrol异步调用时,驱动程序先将此irp保存起来,然后调用i.markpending(),最后驱动程序返回status_pending,当一个事件发生时,驱动程序再完成这个irp;使用win32事件通知和应用程序通信时,应用程序首先创建一个事件,直接将该事件句柄传递给驱动程序,应用程序等待驱动程序发送事件消息。
4 结束语
数据采集是现实世界模拟信号到便于计算机处理的数字信号的第一步,数据采集卡是实现数据采集的关键设备。根据上述数据采集卡硬件,用driverworks成功开发了基于cpci总线的数据采集卡驱动程序。为测试驱动程序工作正常与否,编写了上层测试应用程序,测试表明,驱动程序能够快速加载主机控制命令,通过dma方式高速读取板卡上的数据,数据采集卡工作正常,传输速率符合要求。
参考文献
[1]武安河,邰铭,于洪涛.window 2000/xp wdm设备驱动程序开发.北京:电子工业出版社,2003.
[2] 李贵山,陈金鹏著.pci局部总线及其应用.西安:西安电子科技大学出版社. 2003.
[3]waler oney.programming the windows driver model.微软出版社,1999.
[4]pci9054 data book .version 2.1 plx technology, january 2000.
[5] microsoft1windows2000 驱动程序开发大全[m].北京:机械工业出版社,2001.