0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

PCI设备两种底层访问方法的实现及比较分析

牵手一起梦 来源:电子技术应用 作者:姜万波,徐兴 2020-10-04 17:25 次阅读

介绍了在VB开发环境下,对PCI设备进行底层访问的两种方法:一种是通过用用户自己编写的动态连接库(DLL)实现,二是利用WINDRIVER提供的VB运行库编写直接访问硬件接口函数,并对两种方法行了比较。

VB集成化编程语言一种功能强大而容易上手的开发工具,在用户界面、数据库、多媒体、网络编程等方面,VB可谓得心应手。然而VB有限的硬件编程能力以又使得许多硬件开发者对此深感无奈。尤其在工业控制,测控技术等领域,自行设计开发的I/O卡,数据采集卡等在WIN32下的驱动常常需要借助DDK,VtooIsD等工具进行艰苦而又长期的内核模式开发。本文介绍了在VB开发环境下访问PCI设备的方法。对于其他设备,方法与此大同小异。

在VB开发环境下,用户要访问诸如数据采集卡之类硬件上的PCI设备,一般来说有两种途径:一是直接访问,即用VB直接编写访问PCI设备的接口函数(这种方法要有相关软件的支持);二是间接访问,即VB调用其它编程语言(如汇编,C/C++等)写的底层驱动模块(一般封装成动态连接库DLL的形式)实现。

1 PCI总线的配置空间

PCI规范定义了三种地址空间,除了存储器和I/O地址空间外,为支持PCI设备系统资源的自动配置,还定义了配置地址空羊。

PCI总线的配置空间由256个字节组成,分为预定首区和设备关联区。预定首区包括开始64个字节,对所有的PCI设备来说,都必须支持该区的设置;设备关联区的寄存器有不同的的PCI设备厂家自己定义。

配置空间的预定的首区分两个部分,前16个字节的定义对各类PCI设备而言都是相同的,后48个字节空间根据设备支持的功能有不同的分配。首区类型定义了该空间的分配情况(目前只有一种类型00H)。表1是首区的组织结构。

PCI设备两种底层访问方法的实现及比较分析

所有的PCI设备必须支持首区的供应商ID、设备ID、指令和状态区。对于其他寄存器的使用可根据设备的楞能来选择。对于不同的PCI设备,其供应商ID由PCI

SIG分配以确保唯一性,而设备ID则由供应商自己分配。

2 PCI设备的配置过程

PCI总线的配置空间规范保证了所有PCI设备对“即插即用”的支持。

系统在上电后,“即插即用”BIOS通过隔离算法读取每一个“即插即用”设备的资源申请数据,并分配相应的系统资源,同时检查资源的冲突情况,然后引导、加载操作系统,并将控制权交给操作系统;如果加载的是“即插即用”操作系统(WINDOWS

95及以后版本),那么操作系统将接管系统的资源管理权,它首先从BIOS读取“即插即用”设备的资源配置信息,并仲载资源冲突情况,然后配置BIOS尚未配置的“即插即用”设备,将设备的配置信息写入配置管理器,最后激活无资源冲突的“即插即用”设备,装载相应的设备驱动程序。

对于PCI设备来说,系统完成引导之后,除了将资源的分配写入系统的配置管理器外,还写入了相应的PCI配置寄存器。程序可以通过直接读取设备的配置寄存器来得到设备的I/O,存储器等资源配置情况。

3 VB下PCI设备的访问

驱动程序访问PCI设备的过程一般包括扫描PCI总线,相找指定的PCI设备,确定I/O等资源分配情况,进行I/O、存储器、中断以及DMA等操作。VB本身并不能实现上述对PCI设备的访问过程,下面介绍在VB下通过其他途径实现对PCI设备的访问。

3.1 VB直接访问

WINDRIVER为VB只提供了非常有限的I/O访问能务(如串口通信),在VB下直接访问PCI设备时需要借助其它软件。目前WINDRIVER是KEFTech公司主推产品,是许多PCI厂家所推荐的首选驱动器程序开发工具。

WINDRIVER为VB 4.0以上版本提供了一个类模块(WINDRIVER.CLS),利用这个类模块,用户可以手工编写自己需的接口函数来访问相应的设备。下面以具体例子来说明WINDRIVER.CLS的使用方法。

3.1.1 扫描PCI总线得到指设备的数目

利用WINDRIVER.CLS提供的应用程序接口函数(APIs),编写一个扫描PCI总线,获得指定PCI设备数目的函数下:

Function GetCardsNum (dwVendorID As)

Long, dwDeviceID As Long) As Integer

Dim pciScan As WD_PCI_SCAN_CARDS

Dim hWD As Long

HWD = WD_Open()

If Hwd =INVALID_HANDLE_VALUE Then

MsgBox “设备打开出错”

Exit Function

End If

PciScan.searchId.dwVendorId =

DwVendorID

pciScan .searchId.dwDeviceID =

dwDeviceID

WD_PciScanCards hWD, pciScan

WD_Close (hWD)

GetCardsNum = pciScan.dwCards

End Function

该函数可以通过输入参数:PCI设备的供应商ID和设备ID得到所需的PCI设备数目。如查找AMCC公司的PCI适配芯片S5933,则输入参数为:&H10E8和&H4750。

下面例子用于读写S5933的PCI配置寄存器。在工程的全局模块中需要先定义下列数据结构,同时设备必须处于打开状态。

Type AMCC_INNTERRUPT

Int As WD_INTERRUPT

HThread As Long

Trans(O To 1)As WD_Transfer

End Type

Type AMCC_ADDR_DESC

dwLocalBase As Long

dwMask As Long

dwBytes As Long

dsAddr As Long

dwAddrDirect As Long

flsMemory As Boolean

End Type

Type AMCC_STRUCT

HWD As Long

CardLock As WD_CARD

PciSlot As WD_PCI_SLOT

CardReg As WD_CARD_REGISTER

AddrDesc(0 To AD_PCI_BARS-1)As

AMCC_ADDR_DESC

fUseInt As Boolean

int As AMCC_INTERRUPT

End Type

3.1.2 读写PCI配置寄存器

完成以上数据结构的定义后,用下面的函数可写S5933的PCI配置寄存器内容。

Function AMCC_ReadPCIReg (hAmcc As

AMCC_SETRUCT, dwReg As Long)

Dim pciCnf As WD_PCI_CONFIG_DUMP

Dim dwVal As PVOID

pciCnf.pciSlot = hAmcc.pciSlot

pciCnf.pBuffer = dwVal

pciCnf.dwOffer = dwReg

pciCnf.dwBytes = 4

pciCnf.flsRead = True

WD_PciConfigDump hAmcc.hWD, pciCnf

AMCC_ReadPCIReg = dwVal

End Function `读函数

Sub AMCC_WritePCIReg (hAmcc As

AMCC_STRUCT, dwReg As Long, dwData As PVOID)

Dim pciCnf As WD_PCI_CONFIG_DUMP

pciCnf.pciSlot = hAmcc.pciSlot

pciCnf.pBuffer = dwVal

pciCnf.dwOffer = dwReg

pciCnf.dwBytes = 4

pciCnf.flsRead = False

WD_PciConfigDump hAmcc.hWD, pciCnf

End Sub `写过程

参数说明:

hAMCC 设备打开后系统分配的句柄

dwReg 读写的PCI配置寄存器

dwVal 读出的寄存器数据

dwData 写入寄存器的数据

以上例子仅仅是抛砖引玉。WINDRAR.CLS类模块提供了功能极为强大的底层驱动的API函数,用户通过编写相应的驱动模块可以方便地实现对各类硬件的I/O、存储器映射、中断以及DMA等操作,同时可以实现WIN32下物理内存空间的申请、读写等处理。另外对于实时性要求较高的设备,WINDRIVER提供的“内插”(Plug-In)特性可以让程序的相关模块运行于Ring 0内核模式(Kernel mode),以提高性能。

开发完成的底层驱动模块既可直接为VB的应用程序调用,也可以在VB下封装成DLLs供其它的WIN32开发工具调用。

3.2 自定义DLL访问

DLL使VB的功能得到极大的增强,使得VB的应用范围不断扩大,使用更加灵活。VB通过调用自定义DLL可以实现对硬件的底层访问。下面用例了说明VB对DLL的调用及DLL的编写过程。

3.2.1 DLL的功能和编写

本例中的DLL通过扫描PCI总线,得到总线上S5933接口芯片的数目,打开指定设备,向S5933的输入邮箱子中写入命令字,然后从输出邮箱1中读取返回数据,最后关闭设备。

extern “C” _declspec (dllexport)

int _stdcall GetCardsNum()

{

AFX_MANAGE_STATE (AfxGetStaticModuleState());

int cards;

cards=AMCC_CountCards (0x10e8,0x4750);

return cards;

} //此函数得到S5933的数目;

extern “C” declspec (dllexport)

DWORD_stdcall Send-

Command(int CardNum, DWORD dwCmd)

{

AFX_MANAGE_STATE (AfxGetStaticModuleState());

DWORD data;

If (AMCC_Open (&Hamcc, 0x10e8,0x4750,

Card-

Num, 0)) //打开指定设备

{

AMCC_WriteRegDWord(hAMCC, OMB1_ADDR);

dwCmd); //写入命令字

do{

data=AMCC_ReadRegDWord(hAMCC,MBFF_ADDR);

}while((data&0x000f0000)==0x00000000);

//等待输入邮箱1满

data=AMCC_ReadRegDWord(hAMCC,IMB 1_ADDR);

//读取返回数据

if(Hamcc) AMCC_Close(Hamcc)

//关闭设备

return data;

else

{AfxMessageBox(“打开设备失败!”);

return 0;}

程序中用到的函数包含在WINDRIVER的API函数库中,在VC++下编译时加上头文件:

#include “amcclib.h”

#include “amcclib.c”

同时在DEF文件中列出DLL的导出函数名,生成的DLL即可为VB即可为VB所调用。读者也可用其它工具编写驱动模块,最后封装成DLL即可。

2.2.2 VB调用DLL

VB调用动态连接库(DLL)时,首先声明DLL,然后即可像调用VB的语句或函数一样使用DLL中的例程。下面介绍VB调用上例生成的DLL(假设文件名为Test.dll)。

声明

Public Declare Function GetCardsNum Lib

“Test.dll”()

As Integer

Public Declare Function SendCommand Lib

“Test.dll”

(ByVal dwCmd as Long) As Long

在声明时需要注意:DLL的路径;参数传递的方式;参数的类型。

另外,VB遵从_stdcall的参数传递约定,而VC++默认_cdecl的传递约定,因此在DLL中的导出声明需采用_stdcall的装饰符。

调用

一旦声明后,在VB的应用程序中就可调用DLL中的例程。如:

Private Sub Form_Load()

Dim CardsNum As Integer

CardsNum = GetCardsNum()

MsgBox“系统中有”+ Str(CardsNum)+“块S5933插卡!”

End Sub

WINDRIVER包括了诸如AMCC、Altera、PLX、Galileo、V3、PLDA等公司PCI芯片的专用C/C++的

API函数库,其中包含了I/O读写,内存映射,中断处理以及DMA等底层驱动的函数,可以非常方便地用VC++,BC++以及C++Builder等工具编译成DLLs供VB调用。

本文提供了两种在VB的开发环境下访问PCI设备的方法。第一种方法需要有WINDRIVER的VB运用库支持,可以在VB环境下直接编写所需的接口函数,但对WINDRAR。CLS类模翰中定义的内核数据结构要有较深的了解;第二种方法具有一定的灵活性、普遍性,编写的DLL的工具较多,DLL除了可用于VB外,还可用于其他的WIN32开发工具,有较强的适应性。

以上方法在北京航空航天大学测控技术研究所研制的PHD2000高速并行数据采集系统中得到实际应用,取得了良好的效果。

责任编辑:gt

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 存储器
    +关注

    关注

    38

    文章

    7122

    浏览量

    161927
  • PCI
    PCI
    +关注

    关注

    4

    文章

    608

    浏览量

    129573
  • 总线
    +关注

    关注

    10

    文章

    2697

    浏览量

    87158
收藏 人收藏

    评论

    相关推荐

    两种verilog语言写法的实现问题!求解答~

    在看verilog代码时,看到这样两种表示方法:一是:“ wirea;assigna=b;”一是:“wirea=b;”请教各位大神这两种
    发表于 01-29 14:33

    AVR的两种位操作及比较

    必须通过软件来实现。下面对我所知道的两种方法进行一个简单的比较。 1、位域方式。先定义一个位域, typedef struct _bit_struct{ unsigned char bit0
    发表于 09-06 10:24

    怎么比较两种FPGA设计

    比较两种设计时使用什么更实用?来自地图报告的占用切片或来自综合报告的实际比率以上来自于谷歌翻译以下为原文What is more practical to use in comparing two
    发表于 10-22 11:17

    基于IP模块实现PCI接口设计

    和TECHNOLOGY VIEW两种原理图,有利于关键路径的寻找和分析,它还提供了许多功能强大的属性参数,但同时也增加了软件使用的复杂性。  VHDL语言中例化的FPGA IP模块(PCI核,双端口RAM等
    发表于 04-17 07:00

    接口芯片PCI 9030开发PXI模块的过程和方法

    调试也是一个很好的帮助工具。用WinDriver开发PCI设备驱动程序一般有两种方法:一是使用向导(Driver Wizard),Driver Wizard能够自动生成驱动程序的框架
    发表于 05-05 09:29

    采用IP模块实现PCI接口设计

    VIEW两种原理图,有利于关键路径的寻找和分析,它还提供了许多功能强大的属性参数,但同时也增加了软件使用的复杂性。VHDL语言中例化的FPGA IP模块(PCI核,双端口RAM等)应该不参与逻辑综合,可以在
    发表于 05-08 07:00

    基于PCI总线的CPLD实现

    独立的配置空间,可实现即插即用。这些优点使得PCI总线在数据采集、嵌入式系统和测控等领域得到广泛应用。实现PCI总线协议目前主要有专用接口芯片和CPLD
    发表于 05-29 05:00

    突发功率测量的两种方法

    对于无线信号功率测试来说,TDMA信号、Bluetooth蓝牙信号或者雷达脉冲信号都是基于时域中周期性重复的突发结构来实现的。与连续平稳信号的功率测量不同,这种突发信号的功率测量受到频谱分析仪捕获时间的影响,相对来说比较复杂,突
    发表于 06-10 07:31

    两种使用C#实现ADSL自动拨号的方法

    在网络编程中,有时候会需要重新拨号建立网络连接(如Ad点击软件通过重新拨号形成有效点击) ,下面介绍两种程序中拨号的方法.
    发表于 07-12 06:33

    怎么实现PC机的软件对PCI设备访问

    、稳定性和可移植性,对应用程序访问硬件资源加以限制,这就要求设计设备驱动程序以实现PC机的软件对PCI设备
    发表于 09-17 08:12

    Matlab提供的两种聚类分析

    Matlab提供的两种聚类分析提供源程序代码
    发表于 04-29 11:21

    PCI 设备 RTX 驱动开发方法

    to an RTX Device 一节或者参考附件 2. PCI驱动程序的特点 在设计驱动程序之前,首先要对欲控制的硬件设备进行细致地分析,更需要详细了解硬件设备的特性。硬件
    发表于 09-06 12:43

    两种键盘扫描方法对比分析哪个好?

    两种键盘扫描方法对比分析哪个好?
    发表于 06-01 06:50

    两种空间矢量脉宽调制生成方法分析比较

    两种空间矢量脉宽调制生成方法分析比较
    发表于 03-30 18:24 11次下载

    访问PCI/PCIe设备的流程

    访问 PCI/PCIe 设备的流程 PCI/PCIe 设备的配置信息 PCI/PCIe
    的头像 发表于 07-30 09:44 1018次阅读