RTX系统下并行I/O卡驱动程序的开发

2020-04-07 10:41
计算机测量与控制 2020年3期
关键词:板卡寄存器驱动程序

(1.西安现代控制技术研究所,西安 710065;2.中国人民解放军93811部队 保障部装备质量控制与安全监察中心,兰州 730000)

0 引言

PCI-1751卡是一块基于PCI总线的拥有48路并行I/O的板卡。由于可以同时控制多路电平输入输出,该板卡广泛于工业交流/直流I/O设备监控、继电器和开关控制、并行数据传输、感应TTL信号逻辑、驱动LED指示器等环境。同时PCI-1751板卡上也集成了2个8254定时器/计数器,也可用于一些高精度定时计数的功能场景。

RTX操作系统作为Windows系统的扩展系统,受到许多高校研究单位的青睐。而很多板卡在出厂时都不提供RTX驱动程序,PCI-1751板卡也不例外。因此,本文结合研华科技公司的PCI-1751板卡,介绍RTX系统下板卡驱动的编写调试方法及一些经验,以求RTX驱动程序的开发被更多探索。

1 RTX驱动程序机理

1.1 RTX下PCI驱动程序开发实质

寄存器是板卡上的具有特定功能的内存存储。用户可以不了解板卡内部的具体硬件实现,但只要能理解其意义并通过地址访问到寄存器,即可实现板卡功能,故称为板卡与用户之间的软件接口。

因此,RTX下PCI板卡驱动的开发实质就是利用RTX系统函数操纵板卡上的寄存器。

1.2 PCI板卡寄存器的分类

开发驱动的用户需要关心两类寄存器,即PCI配置寄存器与板卡功能寄存器。

1.2.1 PCI配置寄存器

PCI配置寄存器是每块板卡寄存器的“目录”,是PCI协议预定义的256字节的内存[3]。在该寄存器中,标识了该板卡的所有有用信息,其具体内容如表1所示。

表1 PCI配置空间

1)DeviceID与VendorID:

每类板卡独一无二的属性[1],用户在遍历计算机系统中的所有板卡时,可根据这两个值,来判断该板卡是否存在于该计算机系统。

2)基地址寄存器:

用于存放寄存器映射的基地址。基地址是板卡功能寄存器的起始地址,用户可以根据基地址和偏移地址计算板卡上所有功能寄存器的地址。

1.2.2 板卡功能寄存器

板卡功能寄存器是板卡功能的软件接口,用户只需对这些寄存器置数取数,即可完成与之对应的功能。

板卡在出厂硬件手册都会附带寄存器功能说明及地址分布,这些地址都是从基地址开始有规律累加的,每个寄存器相对基地址的累加量称作偏移地址。因此,只要找到了板卡I/O基地址,所有寄存器的地址都可以很容易的推算出来。

在图1所示的计算机环境中,PCI-1751的内存基地址为0xFEBFF400,这与板卡PCI配置空间的基地址寄存器2中的值所吻合,我们可得到其基地址存放在基地址寄存器2中。感兴趣的读者可以通过该方法自己动手验证基地址是否存放于PCI配置寄存器中的基地址寄存器2中。

图1 板卡资源对话框

2 PCI-1751板卡简介

2.1 板卡功能

研华PCI-1751接口卡是一块具有48路并行DI/O输入输出卡,同时该板卡也携带3个定时器/计数器,可以完成高精度的定时计数功能。

该板卡借鉴了8255芯片的设计思路,实现了两块8255芯片的mode 0模式,共具有24x2=48路DI/O通道。同时该板卡的I/O驱动能力远超出于普通的8255芯片。

同时,PCI-1751板卡提供了断电保护功能,当所在机器遭遇突发断电又瞬时恢复的情况,板卡可以保持之前保存的通道输出值。

2.2 板卡DI/O通道分组

PCI-1751板卡上两个增强的8255芯片的48路DI/O通道被分为6个组,分别为PA0、PB0、PC0(PC0H、PC0L)、PA1、PB1、PC1(PC1H、PC1L)。每个通道组可以单独配置输入输出方向,PC0和PC1组高低字节也可单独配置,互不影响。

2.3 相关寄存器配置

PCI-1751的寄存器地址列表如表2所示。

板卡上的硬件跳线可以强制配置I/O口输入输出方向。当跳线配置为软件配置模式时,需要在使用前先写入控制字。控制寄存器的偏移地址为0和7,对应Port0和Port1,其内容格式如表3所示。

表2 PCI-1751寄存器地址

表3 Port0、Port1配置寄存器

对于Port0、Port1配置寄存器,写1为输入方向,写0为输出方向。例如,只想配置PC0通道组为输入通道,其他通道均为输出通道,则应将控制字0x09(00001001B)写入偏移地址为3的寄存器中。

配置好输入/输出方向后,对相应的通道寄存器进行读/写即可完成输入/输出操作。例如读取PC0通道组,只需读取base+2的寄存器值即可。

2.4 板卡定时器/计数器

PCI-1751板卡上携带三块8254计数器芯片,定时器连接关系如图2所示。

板卡在设计时,为了提供更多的灵活性,Timer1的CLK引脚可以通过跳线连接到外部信号源CLK1,亦可连接到Timer0的输出端。当Timer1的时钟源连接到Timer0的输出端时,相当于Timer0与Timer1串联形成一个32位的计数器。

板卡内部的定时器晶振频率为10 MHz,使用Timer0与Timer1进行定时,最大定时频率为10 MHz/2=5 MHz;最小定时频率为10 MHz/65 536/65 536=0.002 328 Hz。

图2 定时器/计数器结构图

2.5 板卡中断寄存器

在表2所示的寄存器列表中,特别值得关注的是偏移地址为32的中断控制/状态寄存器。该寄存器在写入时作为控制寄存器,读取时作为状态寄存器,他们使用相同的偏移地址。

1751板卡将PC00、PC04、Timer1、PC10、PC14、Timer2的输出引入到板卡的中断电路中。中断控制寄存器决定了中断源的选择、中断触发模式等设置,中断状态寄存器显示当前中断配置与触发状态,其定义如表4所示。

表4 中断控制/状态寄存器

其中:F是中断标志,作为状态寄存器时,该位表示中断是否发生;作为控制寄存器,写0是对中断标志的清除。E是上升沿/下降沿的配置,1为上升沿,0为下降沿。M1M0是中断源的选择,具体示意如表5所示。

表5 中断模式配置

例如,在本文的第四章节所介绍的实验中,欲检测PC00的上升沿中断,需将0x05写入中断控制寄存器中即可完成配置;中断服务函数中,就是通过该寄存器的D3位即可检测PC00中断是否来临。

有了这些知识储备,即可开始进行板卡驱动的开发。

3 RTX驱动程序开发示例

在本文示例的驱动程序中,主要提供关于DI/O操作的几个重要函数,分别为打开板卡函数、中断配置函数、配置通道组函数、读通道组函数、写通道组函数、等待中断函数。通过这些函数,该板卡可以完成多路电平的输入输出以及上升沿/下降沿中断采集的功能。

3.1 打开板卡函数—OpenCard_PCI1751

PC机可能存在很多板卡,因此在打开板卡函数的实现中,主要操作为根据DeviceID和VendorID搜索PCI-1751板卡是否存在。如果搜寻到板卡,则保存板卡的I/O映射基地址,方便后续读写板卡内部寄存器时使用。

示例代码如下:

for ( bus=0; bFlag; bus++ )

for(deviceNumber=0;deviceNumber

for(functionNumber=0;functionNumber

{

bytesWritten = RtGetBusDataByOffset(…)

if(( PciData->VendorID == vendorID ) && ( PciData->DeviceID == deviceID ))

base_add = base_add_register[2];//get add

}

这三层循环会遍历所在计算机系统中的所有板卡。通过RTX系统提供的接口RtGetBusDataByOffset,可以获得PCI配置空间的内存指针,即表1所示的内存区域,将该内存中的DeviceID和VendorID成员与PCI-1751板卡的进行对比,即可验证当前所遍历板卡是否为1751板卡。如果找到,保存I/O映射基地址。

对于PCI-1751板卡而言,DeviceID为0x1751,VendorID为0x13FE。

3.2 打开中断——EnableInterrupt_1751

打开中断函数内部完成两个操作。

首先根据用户需求,对中断控制寄存器进行配置,其次使用RTX提供的API函数RtAttachInterruptVector对PCI中断进行挂接响应。

完成上述两个设置之后,板卡上被使能的中断就可以触发中断服务函数。

中断寄存器的配置示例代码如下:

IntCmd = IntMode<<(port*4);

RtWritePortUchar(BaseAdd+32, (UCHAR)IntCmd);

其中,IntMode对应表5中的中断模式选择,取值0~3;port定义为Port口编号,Port0为0,Port1为1。

3.3 配置通道组——SetPortDirection_1751

在配置通道组函数中,主要操作就是对欲使用的通道组的控制字进行设置,然后将控制字写入对应的寄存器中。

示例代码如下:

dirsetting=PA<<4+PCH<<3+PB<<1+PCL;

RtWritePortUchar(BaseAdd+(port+1)*4-1, (UCHAR)dirsetting);

在形参列表中,PA、PCH、PB、PCL是通道组输入输出方向,定义为输出传0,输入传1;port定义为Port口编号,Port0为0,Port1为1。

3.4 读通道组——ReadPort_1751

读取通道组,就是读取指定通道对应的寄存器。

示例代码如下:

if (channel >= 3) channel += 1;

cResult=RtReadPortUchar(BaseAdd+channel);

在形参列表中,channel代表I/O口编号,定义为PortA0、PortB0、PortC0、PortA1、PortB1、PortC1依次为0~5。

3.5 写通道组——WritePort_1751

输出通道组,就是向指定通道对应的寄存器上写值。

示例代码如下:

if (channel >= 3) channel += 1;

RtWritePortUchar(BaseAdd+channel, (UCHAR)value);

在形参列表中,channel代表I/O口编号,定义为PortA0、PortB0、PortC0、PortA1、PortB1、PortC1依次为0~5。

3.6 等待中断——WaitPortInterrupt_1751

3.6.1 原理解析

对于像Windows、RTX这样的多任务操作系统,每个任务对应一个运行的进程,每个运行的进程中又可以包含很多线程。如果没有同步机制,所有的线程会任意运行。然而,多个线程可能会要求同一个资源,这就需要同步处理。

等待中断函数就使用到了同步机制。调用等待函数后,其内部的等待同步对象的函数,例如WaitForSingleObject函数,就会处于等待状态,对于用户,其表征为“卡死”状态,只有当中断触发后,中断服务函数内部对该同步对象使能后,等待同步对象的函数才会释放线程占有权,等待中断函数才能继续运行下去。

RTX操作系统提供的等待信号量的函数为RtWaitForSingleObject,形参和用法兼容Windows操作系统函数。形参1是信号量的句柄,形参2是等待时间,当形参2传入INFINITE时,永久等待,直至信号量有效。等待中断函数就是利用永久等待信号量来实现的。

3.6.2 函数实现

等待中断函数内部对两个port口,3类中断进行等待。当用户调用该函数时,先清空对应信号量,然后等待信号量,此时该函数处于阻塞状态。

中断服务函数检测到中断触发后,将对应信号量激活。等待中断函数才能继续进行,达到了“卡死”等待的作用。

这里对port0口的PC00中断进行示意。

IntCmd = 0x01;//中断源,对应表5

RtWritePortUchar(BaseAdd+32, (UCHAR)IntCmd);//写中断控制寄存器

RtWaitForSingleObject(hInterHandle[0], INFINITE);

Printf(“PC00 Int found/n”);//中断到达了

return 0;

在中断服务函数内部,其核心代码如下:

temp1=RtReadPortUchar(base+32);//得到中断状态寄存器

if (temp1 & 0x08)//对比表4中的D3位

RtSetEvent(hInterHandle[0]);

4 RTX驱动程序测试

4.1 测试原理

对于板卡驱动性能的测试,这里使用了一个“自发自收”的闭环测试模型,即板卡PA00自己产生上升沿,板卡PC00采集该上升沿,通过对比上升沿产生前后的时间间隔来衡量驱动程序的性能。测试流程如图3所示。

图3 驱动测试流程

4.2 测试方法

板卡硬件上用导线连接引脚1与引脚19,即PA00引脚与PC00引脚。

软件上将PA口配置为输出方向,PC口设置为输入方向,这样PA00的电压会被PC00实时采集。

I/O口方向设置好后,使PA00口先输出低电平,再输出高电平,等待PC00口检测到该上升沿触发中断。

Windows与RTX的测试程序均按照图3所示流程进行编写,具体流程如下:

1)打开板卡,配置PA口为输出方向,PC口为输入方向;

2)配置中断控制寄存器,使能PC00上升沿中断;

3)记录当前时刻t1;

4)PA00输出低电平;

5)PA00输出高电平;

6)等待PC00上升沿中断,记录中断触发时刻t2;

7)计算“闭环”时间t2-t1;

8)程序结束。

4.3 测试环境与考核指标

本次试验使用研华610L原装机箱作为测试硬件环境,系统环境为Windows XP SP3+RTX8.1,编译器使用Visual Studio 6.0。

Windows与RTX实验程序均按照4.2节中的流程开发,t1和t2通过系统函数获取,t2与t1的差值作为最终考核指标。

4.4 测试结果与分析

实验100次取平均值作为测试最终结果,Windows驱动与RTX驱动的“闭环”测试结果如表6所示。

表6 驱动测试结果 ms

通过平均值的对比可以看到,RTX驱动程序相比Windows驱动,响应时间缩短了68%,性能提升相当明显。

同时,通过极值对比可以看到,RTX驱动的闭环时间相对稳定,波动保持在0.003 ms之内;Windows驱动的闭环时间相对不稳定,波动在0.008 ms之内。

本次实验表明,无论在响应时间方面,还是在稳定性方面,RTX驱动的性能都处在领先地位,对于追求实时、稳定的环境而言,RTX驱动无疑是首选。

由于系统设计出发点的不同,无论是在线程调度算法、线程优先级定义、定时器精度方面,Windows系统均不是RTX对手。因此,Windows驱动的落败也是在预料之中的。

这也表明,RTX可以对一个单一的低成本的平台进行扩展,使其满足一个广泛的嵌入式应用程序的要求。之所以很多高校和研究所广泛使用RTX,确实是有一定依据的。

5 结束语

本文介绍了PCI-1751接口卡在RTX实时系统下驱动程序的编写方法,出色的实现了板卡提供的DI/O功能、中断采集功能,可以满足绝大多数工业、生产、仿真的实时性要求。同时对于其他类型的接口卡,亦可借鉴本文中列举的方法和框架进行开发驱动。对于PCI-1751板卡的定时器/计数器等功能,由于篇幅所限未能介绍,感兴趣的读者可以参考本文的思路,自己探索尝试。

猜你喜欢
板卡寄存器驱动程序
避免Windows系统更新反复安装显示驱动
阻止Windows Update更新驱动程序
飞思卡尔单片机脉宽调制模块用法研究
航空电子设备维修方法分析与研究
航空电子设备维修方法分析与研究
移位寄存器及算术运算应用
数字电路环境下汽车控制电路信号设计
板级备件通用测试系统设计
妙用鼠标驱动
驱动程序更新与推荐