基于Win CE的EP9315_SPI驱动程序设计
2009-08-13张东许弟建
张 东 许弟建
摘 要:编写联系操作系统和相应硬件设备的驱动程序至关重要。在Platform Builder 4.2开发环境下,基于流接口驱动程序模型,详细阐述嵌入式操作系统Win CE下EP9315芯片的SPI接口的驱动程序设计方法,就设计步骤、虚拟地址映射实现和关键程序代码编写等进行具体分析,并论述驱动程序与EVC编程环境下SPI应用程序之间的关系。驱动程序和相应应用程序能正确运行于优龙的FS_EP9315开发平台。实践证明,该方法正确可行。
关键词:嵌入式操作系统;Win CE;SPI;驱动程序
中图分类号:TP311文献标识码:B
文章编号:1004-373X(2009)10-069-04
Design of EP9315-SPI Driver Based on Win CE
ZHANG Dong1,XU Dijian2
(1.Chongqing University of Arts and Sciences,Chongqing,402160,China;2.Chongqing University of Science and Technology,Chongqing,401331,China)
Abstract: It is very important to compile driver connecting operating system with corresponded hardware device.Based on stream interface driver model,the design of SPI driver in embedded operating system Win CE in development environment of platform builder 4.2 and design method are introduced and analysed,realizing virtual address map,key code and the relationship between driver and SPI application program in EVC program environment is discussed.Driver and corresponded application program can be operated on FS_EP9315 development platform of ucdragon rightly.Experience indicates the methord is right and feasible.
Keywords:embedded operating system;Win CE;SPI;driver program
0 引 言
嵌入式是“以应用为中心,以计算机技术为基础,软硬件可裁剪,适合应用系统对功能、可靠性、成本、体积、功耗严格要求的计算机系统”。Windows CE.NET是Microsoft推出的功能强大的紧凑、高效、可伸缩的32位嵌入式操作系统,主要面对各种各样嵌入式系统的产品[1,2]。
该系统具有多线程、多任务、完全抢占式的特点,是为各种具有严格资源限制的硬件系统所设计的。为了将操作系统和硬件设备连接起来,硬件和软件的驱动联系就显得很重要。SPI是一种高速、全双工、同步的通信总线,在芯片的管脚上只占用4根线,节约了芯片的管脚,同时为PCB的布局节省了空间,提供了方便,正是出于这种简单易用的特性,现在越来越多的芯片都集成了这种通信协议。SPI的工作模式有两种:主模式和从模式,SPI总线可以配置成单主单从、单主多从、互为主从。为了充分利用芯片的SPI接口进行相应的驱动程序设计以及应用程序设计,通用方法的研究就显得十分重要。
1 Win CE提供的驱动模型
Win CE操作系统支持两种类型的驱动程序,一种为本地驱动程序,是把设备驱动程序作为独立的任务实现的,直接在顶层任务中实现硬件操作,因此有明确和专一的目的。本地驱动程序适合于那些集成到Win CE平台的设备,诸如键盘、触摸屏等设备。另一种是具有定制接口的流接口驱动程序,它是一般类型的设备驱动程序,为用户一级的动态链接库(DLL)文件,用来实现一组固定的函数称为“流接口函数”,这些流接口函数使得应用程序可以通过文件系统访问这些驱动程序。这里论述的SPI驱动就属于流接口驱动。
2 SPI驱动程序的设计
2.1 EP9315芯片及SPI接口简介
EP9315是一款基于ARM920T,由Cirrus Logic公司生产的工业级芯片[3,4] ,内带MMU,16 KB的指令Cache,16 KB的数据Cache和数学协处理器,主频为200 MHz,系统总线为100 MHz。该芯片拥有一组SPI接口,利用它可方便实现与外围SPI器件进行通信,可大大简化工程应用的硬件设计软件。
SPI驱动程序采用Win CE流驱动的标准形式。下面从驱动程序具体设计步骤以及驱动代码的编写两个方面做较为详细的阐述。
2.2 SPI驱动程序设计步骤
在Platform Builder 4.2下设计Win CE流接口驱动程序可按照以下步骤进行[5-7]:
(1) 在C:\Win CE420\PLATFORM\ep931x\drivers目录下新建一个目录SPI;
(2) 从其他驱动目录下复制makefile文件到SPI目录下;
(3) 用文本编辑器建立4个文本文件,文件名分别为SPI.c,SPI.h,SPI.def和sources;
(4) 编辑目录C:\Win CE420\PLATFORM\ep931x\driver下的dirs文件。用文本编辑器打开该文件,找到“DIRS=”等式,在该等式最后添加一行, 如下面所示:
DIRS=…
SPI
(5) 在Platform Builder 4.2中打开Platform.bib文件,在该文件最后和FILES之前加入一行,指明在生成Windows CE内核映射时自动将SPI.dll加入到内核映像中,添加内容如下:
SPI.dll MYM(_FLATRELEASEDIR) SPI.dll NK SH
(6)具体的流接口驱动程序跟注册表密不可分,在Platform Builder 4.2中打开platform.reg文件,在该文件最后加入如下所示注册表信息,以使在生成操作系统映像时,Platform Builder将注册表信息加入到注册表中。在Platform.reg中添加内容如下:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\SPI]
"Prefix"=" SPI "
"Dll"=" SPI.dll"
"FriendlyName"=" SPI Driver"
"Index"=dword:1
"Order"=dword:0
(7) 为了通知Windows CE驱动的函数,需要在SPI.def文件中指出要导出的函数,编写内容如下:
LIBRARYSPI
EXPORTS
SPI_Init
SPI _Deinit
SPI _Open
SPI _Close
SPI _Read
SPI _Write
…
其中LIBRARY表示该驱动的动态库和静态库名称,EXPORTS段后面列出要从驱动的动态链接库文件中导出的函数名称。
(8) 编辑sources文件的内容,告诉编辑器和连接器如何编译及连接本驱动程序。
TARGETNAME=SPI
RELEASETYPE=PLATFORM
TARGETTYPE=DYNLINK
TARGETLIBS= MYM(_COMMONSDKROOT) \lib\MYM(_CPUINDPATH)\coredll.lib
DEFFILE=MYM(TARGETNAME).def
PREPROCESSDEFFILE=1
DLLENTRY=DllEntry
SOURCES=SPI.c
FILE_VIEW_INCLUDES_FOLDER=SPI.h
(9) 改写并导入新的ep931x.cec文件
在C:\Win CE420\PLATFORM\ep931x\bspfiles文件夹下,打开并改写ep931x.cec文件。
在Platform builder 4.2环境下,删除原来的cec文件,并导入添加SPI部分后的ep931x.cec文件。在catalog窗口中选择SPI驱动加入到要编译的映像中。
至此,SPI驱动程序的框架已经搭建完毕,剩下的工作就按照流接口驱动要求编写驱动程序代码。
2.3 驱动代码编写
每个流接口驱动程序必须实现1组标准函数,用来完成标准的文件I/O函数和电源管理函数,这些函数提供给Win CE操作系统的内核使用。
SPI流接口驱动程序重点要实现的dll接口函数如下:
SPI_Init:驱动程序加载函数;
SPI_Deinit:驱动程序卸载函数;
SPI_Open:驱动程序打开函数;
SPI_Close:驱动程序关闭函数;
SPI_Write:写函数;
SPI_Read:写函数。
下面重点对SPI _Init,SPI _Write两个函数做阐述,其他函数代码可参照相关资料编写。
(1) SPI_Init函数设计。
在Win CE中,程序访问的地址都是虚拟地址,因此要访问硬件物理地址,必须将物理地址空间映射到虚拟空间。
在SPI_Init函数中,首先通过函数VirtualAlloc()和VirtualCopy(),把EP9315芯片中针对SPI的物理地址和操作系统的虚拟空间联系起来。在其他流接口函数中,即可对申请到的虚拟地址进行操作,按照Win CE中的流驱动模型进行驱动的编写,对虚拟地址空间的操作就相当于对芯片的物理地址进行操作[1]。SPI_Init的函数中,有关地址映射如下实现:
① 在SPI.h头文件中定义数据结构。
EP9315芯片SPI寄存器物理地址分配如表1所示[5],包括控制寄存器、数据寄存器、状态寄存器、频率设置寄存器、与中断有关的寄存器。
因而定义的数据结构为:
#define IOP_BASE0x808A0000
typedef struct {
// SPI PORT
unsigned int rSPICR0;
unsigned int rSPICR1;
unsigned int rSPIDR;
unsigned int rSPISR;
unsigned int rSPICPSR;
unsigned int rSPIIIR;
unsigned int rSPIICR;
}IOPreg;
② 在SPI_Init()中地址映射实现。
地址映射通过VirtualCopy()和VirtualCopy()两个函数实现。VirtualCopy()函数是Win CE中分配连续虚拟地址的API,利用该函数为SPI接口各个寄存器物理地址申请虚拟地址。VirtualCopy()函数负责把SPI接口各个寄存器物理地址映射到申请到的虚拟地址。
为方便驱动程序调试,可利用ERRORMSG()函数在程序适当位置加上一些调试信息,这些调试信息在驱动程序运行时可通过超级终端口输出,方便驱动程序调试。
结合EP9315的SPI接口,需要设置控制寄存器和波特率寄存器。
为实现对标准SPI接口的LED屏幕进行显示控制,需要配置EP9315的SPII总线为单主单从模式,可通过设置SPI接口控制寄存器实现。为调整LED的刷新频率,可通过设置SPI接口频率设置寄存器实现。
SPI_Init()中包含有如下重要代码:
// VirtualAlloc()申请虚拟地址
v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0,sizeof(IOPreg), MEM_RESERVE,PAGE_NOACCESS);
if (v_pIOPregs == NULL)
RetValue = FALSE;
else
{
// VirtualCopy()实现虚拟地址的映射
if (!VirtualCopy((PVOID)v_pIOPregs,
(PVOID)(IOP_BASE >> 8),sizeof(IOPreg),PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
RetValue = FALSE;
Else
// ERRORMSG()输出调试信息
ERRORMSG(1,(TEXT("For IOPregs :VirtualCopy success!\r\n")));
//设置控制寄存器和波特率寄存器
v_pIOPregs->rSPICPSR = 0x18;
v_pIOPregs->rSPICR0 = 0x18;
(2) SPI_Write写函数设计。
文中涉及的工程需要通过EP9315的SPI接口,实现对一个带有标准SPI接口的LED屏进行写入数据操作,实现对LED屏的显示控制。
下列写函数程序代码中,通过MapPtrToProcess()获取应用程序编辑框中输入的数据:
v_pIOPregs->rSPIDR = *pWriteBuffer;
向SPI接口发送一个8位数据。通过一个for循环实现一个1 024(128×8) b的数据的发送,以满足所涉及的LED屏数据位的要求。
具体程序代码如下:
DWORD SPI_Write
(DWORD hOpenContext,LPVOID pBuffer,DWORD Count)
{uchar i;
uchar * pWriteBuffer;
…
pWriteBuffer=MapPtrToProcess(pBuffer,GetCallerProcess());
// Write 1024(=128x8) bits
for(i=0;i<128;i++)
{
while( (v_pIOPregs->rSPISR & 0x01) != 1 );
v_pIOPregs->rSPIDR = *pWriteBuffer;
}
// Wait to complete write data
while( (v_pIOPregs->rSPISR & 0x01) != 1 );
return 1;
}
上述写函数设计实现了对SPI接口的写操作,应用程序通过调用该函数,即可实现对带有标准SPI接口的LED屏进行显示控制。对写函数进行相关改动,即可设计出SPI_Read函数,实现对SPI接口器件数据读取操作,限于篇幅,在此不再赘述。
3 SPI应用程序设计
设计的SPI驱动程序是否正确,可在EVC 4.0环境下编写相关应用程序验证。
编写SPI接口的应用程序[5,8],可实现加载驱动、卸载驱动、打开驱动、关闭驱动、接口功能设置、接口读写等操作。在此仅编写了一个读写SPI接口的应用程序,以对前面设计的SPI_Init,SPI_Deinit,SPI_Open,SPI_Close,SPI_Write等流接口函数进行验证。EVC 4.0编程环境下设计界面如图1所示。
通过RegCreateKeyEx(),WRITE_REG_SZ(),WRITE_REG_DWORD()等函数创建注册表,实现加载驱动;通过CreateFile()调用SPI_Open(),打开驱动程序;通过WriteFile()调用SPI_Write()实现,对SPI接口的写入操作。通过ReadFile()调用SPI_Read(),实现对SPI接口的读取操作。
由于篇幅关系,现仅列 “数据写入SPI”部分的关键代码。其他代码可参照相关资料编写。
void CGpioDlg::OnWrite()
{
DWORD actlen;
if(hFile==INVALID_HANDLE_VALUE)
{return; }
UpdateData(TRUE);
BOOL ret=WriteFile(hFile,&m;_WriteByte,1,&actlen;,NULL);
}
4 实验结果
在Platform Builder 4.2环境下编译并下载内核到优龙公司的FS_EP9315开发平台,Win CE运行正常。在Win CE操作系统下运行SPI应用程序,在运行界面的“写入SPI数据”下面的编辑窗口输入待写入数据0x55,按“数据写入SPI”按钮,能实现对SPI接口的写入操作。通过示波器观察EP9315的SPI接口的输出引脚、SSPTX1引脚,波形如图2所示。由分析图中的波形可知,高低电平间隔出现,证明发送数据正确。
整个实验表明,上述设计方法正确可行,驱动程序和应用程序运行正常。
5 结 语
这里主要论述了在嵌入式操作系统Win CE下SPI驱动程序的开发步骤及关键代码的编写,并对SPI应用程序设计以及驱动程序和应用程序二者之间的联系进行对比分析。文中对其他流接口驱动程序的设计和应用程序的设计具有一定的指导意义。
参考文献
[1]傅曦,陈黎.Windows CE.Net嵌入式开发入门基于Xscae架构.北京:人民邮电出版社,2006.
[2]姜波.Windows CE.Net程序设计.北京:机械工业出版社,2007.
[3]Cirrus Logic.EP9315 User′s Guild.2004.
[4]Cirrus Logic.EP9315 Date Sheet.2004.
[5]周立功.ARM&Win; CE实验与实践.北京:北京航空航天大学出版社,2007.
[6]王小芳,王典洪,陈飞.基于Win CE的I2C驱动程序设计.单片机与嵌入式系统应用,2006(4):28-30.
[7]彭少武,宋娟.Windows CE的CAN总线驱动程序设计.单片机与嵌入式系统应用,2007(11):79-81.
[8]汪兵.EVC高级编程及其应用开发[M].北京:中国水利水电出版社,2005.
[9]孙丰军,余春暄.SPI串行总线接口的Verilog实现.现代电子技术,2005,28(16):105-106,109.