引言
嵌入式技术在各个领域的应用与日俱增,基于微软公司研发的Windows CE嵌入式操作系统的电子设备更是渗透到各行各业。随着网络技术的发展,以太网几乎成为了电子通信设备首选的通信方式。Windows CE 6.0提供的网络接口驱动器标准(NIDS)固然得到系统的良好支持,但其驱动程序的实现较为复杂,且通过NIDS实现应用程序对网络底层驱动的操作难度较大。
针对Windows CE6.0系统下应用程序对设备硬件难以灵活控制的问题,本文介绍一种使用流接口驱动实现应用程序对硬件进行控制的方法。考虑到Windows CE6.0在内核访问机制上有别于以往版本,且以太网接口的广泛使用及其基于NIDS的开发难度较大,故而以DM9000A网络芯片的驱动及控制为例进行介绍。
1 Windows CE 6.0的设备驱动机制
Windows CE所有的驱动程序都是以DLL文件的形式存在的,系统在执行驱动程序代码之前必须先将相应的DLL文件加载到地址空间。Wind owsCE 6.0提供3个系统进程来加载和执行驱动程序的DLL文件,它们分别是Device.exe、GWES.exe和FileSys.exe。它们各自加载的驱动类型如图1所示。
2 流接口驱动工作原理
2.1 流接口驱动架构
应用程序根据加载的流驱动的名称和操作码调用文件API,文件API被系统转发到FileSys.exe进程中;FileSys.exe一旦发现转发过来的文件API是对设备的操作,则会交给设备管理器进行处理;设备管理器将根据具体的请求,调用相应的流驱动接口程序。对于Windows CE系统应用层而言,使用流接口驱动的硬件设备被抽象为一个具有固定接口函数的动态链接库(DLL)。应用程序调用文件API函数与流接口驱动程序进行通信,把对硬件的操作转化为对文件的读写控制,从而达到应用程序操作硬件的目的。流接口驱动程序的体系结构如图2所示。
2.2 流驱动接口函数
流接口驱动程序具有统一的接口函数,只需根据硬件没备的操作时序在相应的接口函数里编写控制指令。Windows CE系统下流接口函数功能描述如表1所列。
表1中XXX代表驱动文件的名称,Windows CE中流接口驱动的文件名称规定为3个大写的字母/数字。在进行流接口驱动程序编程时,并非所有的接口函数都要编写,一般比较重要的是XXX_Init()和XXX_IOControl()两个函数。前者在设备驱动被加载时调用,主要编写初始化硬件设备的相应控制指令,其中包括很是关键的地址映射操作;后者则主要实现对硬件设备的各种控制,可以实现数据的读写等操作,对设备的所有控制都可以在这个接口函数下实现,只需分配好相应的控制码。对于本文介绍的DM9000A,DM9_Init()实现虚拟地址的获取及初始化操作,DM9_IOControl()则实现数据的发送与接收,其中发送控制码定义为DM9_SendData,接收控制码为DM9_ReceiveData。
3 DM9000A流驱动程序的实现
DM9000A支持IEEE802.3x全双工模式流控制,提供IP/TCP/UDP校验、产生及检测功能;内部集成10/100M自适应PHY,同时具有13 KB的接收缓冲区和3 KB的发送缓冲区,支持8位和16位数据接口。
S3C6410与DM9000A的接口电路如图3所示。在流驱动程序中是将DM9000A内部寄存器地址空间映射到S3C6410内部划分的SROM的BANK1空间上,物理基地址是0x18000000。在Windows CE 6.0系统下对硬件寄存器的访问首先需要进行地址映射,将寄存器物理地址映射为系统可访问的虚拟地址。最为简单的方法就是从系统目录(C:\wince600\platform\studk6410\src\inc)下找到基于OEM层的地址配置表(oemaddrt ab_cfg.inc),从文件中找到所使用的SROM的BANK1的虚拟地址,在驱动程序中直接访问该地址(如同访问芯片的寄存器地址)。
流接口驱动的实现将集中体现在对初始化接口函数和I/O控制接口函数的操作,函数主要代码如下:
其中,0x94000000正是从地址配置表文件中获取的虚拟地址,dwEthernetIOBase经映射后则如同DM9000A内部寄存器的首地址。由于硬件线路上是使用S3C6410的地址线中的位2作为DM9000A的数据/地址访问信号(高电平为访问数据),故以“dwEthernetIOBase+4”作为访问数据的基地址。
其中,参数Handle为流接口设备的句柄;dwIoControICode为I/O控制码,可以根据需要自由定义;pInBuf为传入数据指针;nInBufSize为数据长度。除了初始化函数和I/O控制函数外的其他流驱动接口函数无需任何处理,直接给出返回值即可。
发送函数dm9000_send(pInBuf,nInBufSize)获取流接口函数传入的发送数据指针和相应数据长度,然后驱动DM9000A发送数据,其工作流程如图4所示。
4 Windows CE 6.0系统下流驱动程序的使用
4.1 流驱动程序的加载
流接口驱动程序需要按一定的方式配置后才能被系统识别并编译。其配置的主要流程如图5所示。
将流驱动程序加入定制系统之后还需要添加相应的注册表启动信息,在platform.reg文件中添加以下内容:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\DM9]
“Index”=dword:1
“Order”=dword:30
“Prefix”=“DM9”
“DLL”=“DM9.dll”
为使生成的DLL文件能够被包括在烧写文件中并下载到开发板上,还需在platform.bib文件中加入相应代码,内容如下:
IF BSP_NODM91
DM9.dll $(FLATRELEASEDIR)\DM9.dll NK SHK
ENDIF BSP_NODM9 !
经过以上的配置之后,流接口驱动程序已经配置完成,只需要对Windows CE 6.0的系统定制工程重新编译,并将生成的镜像文件下载到开发板上,即可通过文件API操作DM9000A的数据收发。
4.2 应用程序对流驱动程序的调用
Windows CE启动时会自动枚举注册表HKEY_LOCAL_MACHINE\Drivers\BuiltIn目录下的驱动信息,并加载相应驱动程序的动态链接库,然后执行初始化接口函数——DM9_Init()。在驱动程序成功加载之后,应用程序对硬件的操作就只需调用文件API便可实现,但前提是相应的操作必须在驱动程序中有定义,并且分配了操作码。对于DM9000A的数据发送,其文件API代码如下:
……
hDm9=CreateFile(TEXT(“DM91:”),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
该代码调用文件API打开设备进行读写操作,得到文件操作的句柄名hDm9。
DeviceIoControl(hDm9,DM9_SendFrame,&SendData,sizeof(SendData),NULL,0,&dwReturn,Null);
……
该代码调用文件API对设备发送操作命令。其中,hDm9告诉系统要操作的设备为DM9000A;DM9 SendFrame为发送数据的操作码,这必须与驱动程序中定义的相一致,也就是让系统知道进行的是什么操作;&SendData为发送的数据帧首地址;sizeof(SendData)为发送数据的长度……
4.3 实验验证
将基于Windows CE 6.0的DM9000A流接口驱动程序应用于电子式互感器合并单元的以太网数据通信模块设计中,其通过DM9000A发送的数据帧在PC机上使用WinPcap软件进行以太网数据包抓取,从而验证流驱动程序及其应用程序是否正确实现Windows CE下以太网数据的发送。在实验中以IEC61850-9-2数据帧格式发送标识为NCEPU的采样值测试数据,其实验结果如图6所示。
抓取的以太网数据说明了PC机接收到的数据和开发板上通过流接口驱动发送过来的数据是一致的,从而验证了流接口驱动程序正确可行。
结语
本文介绍的流接口驱动虽然不支持WIndwos CE提供的标准接口,无法通过系统标准函数库进行操作,但可以直接根据硬件设备的操作时序编写驱动,具有极大的操作灵活性,非常适合在Windows CE应用程序中对硬件设备底层进行操作。