驱动程序设计实现

数据采集卡驱动程序完成以下功能:应用程序控制数据采集卡工作方
式,向数据采集卡工作方式缓冲器发送工作方式控制字;应用程序查询数据采集卡
工作状态,从数据采集卡工作状缓冲器读取工作状态字;为了使应用程序能实时处
理数据采集卡上采集到的数据,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。

你可能感兴趣的:(fpga开发)