相对于其他嵌入式操作系统,VxWorks以其高可靠性、微内核、可裁减性以及高效的硬实时任务调度、中断管理等优点,被广泛地应用在通信、军事、航空、航天等高精尖技术和实时性要求极高的领域[1]。工程中实际应用的嵌入式系统通常包括以下几个部分:串口、并口、CAN总线和AD/DA等。对于前三种嵌入式硬件,VxWorks内核本身已提供了完备的驱动支持并给出了相应驱动的参考例程,但目前还未包括对A/D及D/A设备的支持;此外,由于相关技术资料的保密性,相应驱动设计的参考文献也较少。因此,本文结合实际系统需要(利用12位D/A输出可调模拟量控制电机转速,利用12位A/D对压电陀螺所敏感的电机转速进行数据采集),对AD/DA设备的驱动进行了相关研究,研究结果具有实际工程应用价值。
本文在简要分析了VxWorks I/O系统及设备驱动基础之上,将A/D与D/A两者整合为一个完整的字符设备挂接到VxWorks的I/O系统中,成功实现了该设备的硬件驱动并附上对应的核心驱动代码,最后在驱动程序测试过程中简要说明了应用层软件的设计方法,为工程应用提供了完善的解决办法。
1 VxWorks I/O系统与设备驱动
了解和掌握VxWorks的I/O系统及设备的驱动结构,是成功设计AD/DA设备驱动的前提和基础。具体来说:VxWorks是一个层次化分明的操作系统,每层各负其责,层与层之间又紧密相连。通常所说的驱动程序属于底层的范畴,而用户的应用程序则属于上层,位于这两层之间的是中间层,无需用户开发,由VxWorks进行维护和管理。这样,操作系统把各层有机地连接在一起,使代码紧凑而高效。VxWorks的I/O系统正是这样的中间层,以本文所要研究的AD/DA驱动系统设计为例,图1详细介绍了三者的关系。
图1中的最底层就是所要编写的设备驱动程序,包括对具体硬件的初始化和各种操作,以及与上层I/O系统的接口;中间层为I/O系统层,VxWorks的I/O系统不但向上提供了7个基本的I/O接口,以供应用程序调用,而且还向下提供与各种设备驱动程序的接口;最顶层为应用层,用户根据实际应用需要编写应用程序,并通过应用程序向下调用I/O系统。与UNIX类似,VxWorks所有的I/O设备都被当作文件来存取。关于VxWorks I/O系统驱动机制的更多内容请参考文献[2][3]。
针对系统需要,选择7个基本I/O接口函数中的open()、read()、write()以及ioctl()进行驱动系统设计,各层函数与相应实现的功能对应关系如表1所示。
此外,D/A输出通道在应用程序中选择,下面给出AD/DA驱动系统的具体设计过程。
2 AD/DA驱动系统设计
2.1 驱动系统开发环境
与其他嵌入式系统开发类似,VxWorks也采用主机-目标机模式[4],如图2所示。
硬件平台中主机使用CPU为迅驰的PC机,运行VxWorks开发环境Tornado2.2;目标机依照系统应用要求选用基于PC104 总线的嵌入式CPU卡MSMP586SEV,该CPU是VxWorks所支持的Intel x86系列CPU。VxWorks自带的板级支持包(BSP)支持该CPU,使得在驱动开发过程中无须过多考虑CPU部分的代码设置。外扩AD/DA采用的同样是PC104总线的数据转换卡ADT-650。开发调试过程中,主机通过网络方式下载VxWorks映像至目标机中,目标机设定为CF卡启动。
2.2 PC104-AD/DA卡硬件结构[5]
PC104-AD/DA卡主要由A/D转换控制器(AD1674)和D/A转换控制器(ADC7724)两个核心器件组成,可提供的硬件资源为12位分辨率的8通道A/D转换和同分辨率的4通道D/A转换;CPU卡通过I/O映射方式对其进行访问,可通过硬件开关选通该卡的I/O映射基地址,为了避免与其他器件地址冲突,在此选择其基地址为:BA=0x240(可根据实际情况选择),其余各寄存器采用偏移地址访问的方式。为便于后续说明,简要将卡上其他寄存器地址及功能列于表2。
在传统非嵌入式实时操作系统(比如DOS)下应用该卡,实际上是在应用程序中对板卡进行初始化和设置相应功能寄存器以完成硬件功能。但由前面对VxWorks的I/O系统和设备驱动结构分析可知,该部分工作在VxWorks操作系统下由底层硬件驱动完成,应用程序中通过调用相应I/O接口函数来实现硬件功能,由此实现分层结构以达到隔离硬件的目的。因此,AD/DA驱动的开发就是依照I/O系统传递过来的应用层各调用接口函数完成对相应寄存器的不同设置。
2.3 AD/DA驱动程序实现
AD/DA驱动的实现方式主要是完成以下6个函数的编写:
设备驱动程序安装函数adcDrv();设备创建函数adcDevCreate();设备打开函数adcOpen();设备读函数(A/D转换) adcRead();设备写函数(D/A转换)adcWrite();I/O控制函数adIoctl()。
其中前三个函数的设计与具体硬件关联较少,与VxWorks下其他字符型设备驱动开发基本类似,不做过多介绍,仅需按照标准代码形式编写即可,具体详细代码可见参考文献[6]。下面详细介绍A/D转换驱动、D/A转换驱动以及设备控制驱动等部分的程序设计,给出核心代码。
2.3.1 A/D转换驱动
A/D转换驱动实际是完成adcRead()函数的编写,在该函数编写之前,首先应明确A/D转换驱动实现过程:当应用程序调用read()函数时,VxWorks的I/O系统将调用底层驱动adcRead()函数,该函数随即依照程序设定对表2所列卡上各相关寄存器进行设置来实现A/D转换的硬件功能,从而实现底层驱动。
A/D转换驱动具体实现的核心代码如下(伪指令为代码说明,以下同):
int adcRead(int adcDevId,char *pBuf,int nBytes)
{…/*触发AD转换*/
sysOutByte(BA+0, 0x00);
while(1)
{/*判断AD转换状态*/
status=sysInByte(BA+5);
if((status&0x01)==0)
{
/*存储A/D转换结果*/
pBuf[1]=sysInByte(BA+0);
pBuf[2]=sysInByte(BA+1);
…
}
}
}
首先选择一个输入通道(通过ioctl选择)并触发A/D转换,随后查询A/D转换状态信息直到A/D转换过程结束,最终将转换结果保存在pBuf[]数组中传送到应用层,应用程序使用得到的数字量信息,至此,A/D驱动完毕。其中sysOutByte()和sysInByte()为VxWorks下对寄存器操作的标准函数。
2.3.2 D/A转换驱动
与上述驱动实现过程类似,D/A转换驱动是完成对adcWrite()函数的编写,转换过程是A/D转换的逆过程,由于其不涉及查询判断,代码相对简化。D/A转换驱动具体实现的核心代码如下:
int adcWrite(int adcDevId, char *pBuf,int nBytes)
{…/*将数据写入缓冲区*/
sysOutByte(BA+2, pBuf[2]);
sysOutByte(BA+1, pBuf[1]);
…
}
首先将应用程序中设定的待转换数字量的低4位和高8位分别存放在pBuf[1]、pBuf[2]中,随后依照先高后低的顺序写入D/A转换缓冲区内,当低位数据写入完成后,硬件将自动开始更新D/A输出的模拟量,至此,D/A驱动完毕。需要说明的是:D/A通道选择是在应用程序中的编码过程中实现的。
2.3.3 设备控制驱动
设备控制驱动用于完成A/D通道选择,实现过程是对BA+3寄存器进行设置,当该寄存器高低位不同时,通道进行自动扫描,每当AD转换完成时切换到下一个通道。以控制A/D对通道0至通道3循环扫描为例,具体代码如下:
int adcIoctl(int adcDevId, int cmd, int arg)
{…/*CH30控制字控制通道0-3转换*/
case CH30:
sysOutByte(BA+3, 0x30);
…
}
通过定义控制参数CH30,实现通道扫描的范围为0、1、2、3、0、1、2、3……,利用该方法的好处是可以省去置通道的软件操作时间,这个功能在高速多通道切换时起很关键作用,同样可定义其他通道的控制参数,如CH20、CH00等等。
3 应用及测试
为了验证上面所设计的驱动系统的有效性,文章对其进行了详细的实验验证。针对本系统而言,D/A能将电机转速控制数字量转换为相应的模拟电压量输出至电机,并且在控制电机运转的同时,还能利用A/D将压电陀螺敏感到的电机转速所输出的模拟电压量转换为数字量后并采集,以此证明驱动系统设计是成功的。下面详细给出实际工程中用于测试驱动程序设计成功的应用程序。
3.1 应用程序设计
首先调用adcDrv()和adcDevCreat()初始化驱动并创建AD/DA设备;并通过fd=open('/adc',O_RDWR,0)操作打开设备。这样,系统为AD/DA卡分配了一个文件描述符fd,通过读写该描述符操作即可完成相应AD/DA变换。
随后发起两个任务[7][8]:写任务和读任务,分别完成上述D/A与A/D的功能。两个任务的核心代码如下:
int Dac()
{…
pBuf[0]=xxx;
pBuf[1]=xxx;
t1=write(fd,&pBuf[0],2);
…
}
int Adc()
{…
ioctl(fd,CH00,0);
t2=read(fd,&pBuf[0],2);
LSB=pBuf[0];
MSB=pBuf[1];
…
}
3.2 测试结果
在WinShell下通过调用iosDevShow()函数可以看到,名为/adc的AD/DA卡设备已经被VxWorks操作系统正确识别,如图3所示。
测试分为两个步骤来验证A/D及D/A驱动的正确性:
步骤1:数字量→模拟量→电机转速(D/A)
步骤2:电机转速→模拟量→数字量(A/D)
步骤1控制电机加减速过程当中,给定的控制电机运转的数字量如图4中data1所示(其中:data1是通过16进制数转换为10进制数实现的)。每隔0.5s对系统进行一次D/A转换,得到电机实际转速rate如图5所示。
对比data1和rate,两条曲线规律一致,说明D/A驱动功能正常。
随后将图5中的电机转速作为输入量,输入到步骤2中进行实验,以相同时间间隔对系统进行A/D采样,转换后的数字量如图4中data2所示,对比data2和rate,两条曲线规律一致,说明A/D驱动功能正常。
data1与data2两条曲线基本重合,二者之间的误差曲线error(data1-data2)如图6。
由图6可得:误差最大值为3.2LSB,最小为2.1LSB。由此可见,AD/DA功能实现的同时精度完全符合要求(4LSB≥error≥2LSB)。实验结果表明:驱动系统设计成功有效。
本文介绍了VxWorks下AD/DA驱动的开发过程,给出了驱动中的核心代码。同时在对驱动程序进行测试的过程中说明了部分应用程序的设计。测试结果表明,所开发的驱动系统满足实际需要(12位AD/DA转换分辨率),可在实际工程中应用。限于篇幅本文未能给出全部代码,但文中驱动程序的设计是完全依照VxWorks的标准I/O机制实现的,具有普遍的指导意义,可为VxWorks下其他字符型设备驱动开发提供参考。
评论
查看更多