时间:2023-03-02 15:08:39
引言:易发表网凭借丰富的文秘实践,为您精心挑选了九篇驱动程序设计范例。如需获取更多原创内容,可随时联系我们的客服老师。
关键词:wince 驱动程序;开发;设计
1 引言
WINCE和Windows 98或Windows 2000不同,它可以工作在12种不同的处理器体系结构、180余种CPU上;同时,WINCE是一个实时操作系统(实时系统的意义就是输入的指令不必进入队列就可以马上处理,过去我们使用的DDS就是实时系统),可以满足应用程序所需要的实时性要求。
Windows CE的模块化设计使得它能够在大量的平台上定制使用,从客户电子设备到专用的工业控制器。由于它是模块化的,因而我们可以使用满足平台系统需求的最小软件模块和组件集合来设计嵌入式系统平台,从而使内存用量最小,但最大可能地提高操作系统的性能。因此外围扩展设备就必须要有硬件驱动才能正常工作。
和其它的操作系统一样,Windows CE也提供设备驱动软件,这些软件的目的是驱动内部和外围的硬件设备,或为它们提供接口。设备驱动程序将操作系统和设备链接起来,使得操作系统能够识别设备或者为应用程序提供设备服务。
Windows CE支持广泛的基于各种CE平台的设备驱动程序。也提供一些用于驱动程序开发的模型(model) ,其中包括来自其它操作系统的驱动程序模型(model),因为这些丰富多变的驱动程序模型, Windows CE适应大部分的内部和外围设备口Microsoft Windows CE设备驱动程序工具包配备了文档资料,这些文档资料使得你能够为Windows CE创建设备驱动程序。目前,Windows CE提供了四种设备模型,其中两种是专用于Windows CE的模型,另外两种外部模型来自其它操作系统。
2 驱动程序开发简介
2.1 开发工具
Windows CE驱动可以使用Platform Builder或者Visual Studio开发,但是开发人员一般都使用Platform Builder开发设备驱动程序,对于部分驱动也会使用Visual Studio开发,应用程序开发人员更多的使用Visual Studio开发驱驱动程序。作为BSP(Board Support Package)的一部分进行整体编译开发。
2.2 驱动分类
2.2.1 按加载方式和接口类型分类
1) 本机驱动程序(Built-In Drivers)
通常由GWES加载,驱动接口一般都是定制的(Custom Purpose)。
2) 流驱动程序(Stream Drivers)
通常由Device Manager加载,驱动接口是标准的流式接口。
3) 混和型驱动程序
同时有定制式和流驱动两套驱动接口,但是和系统交互只使用流式驱动接口,比如PC卡槽驱动。
2.2.2 按驱动层次分类
1) 层次型驱动程序(Layered Driver)
> MDD(Model Device Driver),与硬件无关,面向上层应用程序,一般由微软建立统一框架;
> PDD(Platform Dependent Driver),针对具体硬件平台的操作代码,一般由驱动开发商实现MDD和PDD之间通过标准的设备驱动服务供应商接口DDSI连接。
2) 独立型驱动程序(Monolithic Driver)
> 独立驱动程序包含了MDD面向上层应用和PDD面向硬件平台两方面的代码;
> 适用于操作不复杂的驱动;
> 减少了MDD和PDD传递之间传递信息的开销,实时性更强;
3 流驱动程序的实现
流驱动程序必须实现一套标准接口,流驱动程序适用于IO操作,这也是嵌入式系统中最常见的设备驱动,操作接口和文件系统操作相似,通过CreateFile,ReadFile,WriteFile,IOControl函数等来操作应用程序和流驱动交互,可以把设备当作文件操作。
3.1 文件前缀名确定
根据文件前缀名在系统中必须唯一这一特点,在定义文件前缀名必须是三个字母,若有多个同类设备,由后缀一个阿拉伯数字区分,例如COM1,LPT3等等。文件前缀名将会在驱动的标准接口函数中体现,比如XXX_Init,XXX_Close等。
3.2 通用函数
根据设备的不同,所需函数不同,通用函数如下所示:
1) XXX_Init:通知设备管理器为设备初始化分配资源;
2) XXX_Deinit:通知设备管理器回收设备初始化时分配的资源;
3) XXX_Open:打开设备。应用程序调用CreateFile时,通过文件系统映射为XXX_Open;
4) XXX_Close:关闭设备。应用程序调用CloseFile时,通过文件系统映射为XXX_Close;
5) XXX_PowerUp:设备上电时,操作系统调用该函数完成必要的上电操作;
6) XXX_PowerDown:设备掉电时,操作系统调用该函数完成必要的关机操作
7) XXX_Read:从打开的设备文件中读取数据,可以通过ReadFile映射;
8) XXX_Write:向打开的设备文件写数据,可以通过WriteFile映射;
9) XXX_Seek:文件定位,根据设备情况决定是否支持;
10) XXX_IOControl:IO操作扩展,可以根据设备情况来决定支持何种特殊的操作模式。
3.3 DEF文件建立
流驱动一般以DLL形式存在,DEF文件定义了DLL需要导出的接口集,因此DEF文件的名称与设备驱动名称相同。
3.4 写注册表
在wince中任何设备的识别都是通过注册表来实现的,因此必须在注册表中添加具体的设备驱动项,以便系统识别。具体方法如下:
在注册表中增加驱动程序入口点,找到注册表项,注册项位于注册表的Root Key下,一般为[HKEY_LOCAL_MACHINEDriversBuiltInSampleDrv],建立必要的子键和键值,“Prefix”和“DLL”是两个重要,而且是必须的键,分别描述了设备前缀名和驱动程序的动态连接库名,然后根据具体设备的需要建立驱动程序需要的其子他键。
4 调试驱动程序
驱动程序编写完毕后,就应该进行硬件的调试。具体方法如下:
4.1 调试区信息(Debug Zone)
调试区一般和WinCE的控制台调试工具Cesh.exe配合调试,在不打断OS运行情况下,进行驱动的实时调试,利用宏开关,可以选择需要输出的调试区信息,可以得到进程,线程和调试状态信息。并且可以利用IDE环境,动态选择开关调试区信息,但是打印驱动程序输出调试信。必须借助于至少一种外设显示调试信息,比如串口或者网卡或者其他通过调用RETAILMSG或者DEBUGMSG完成,不影响OS的运行,保证驱动程序运行的真实性,动态输出设备的状态信息,调试相对简单,也是最广泛使用的一种调试方法。
4.2 核心调试工具(Kernel Debugger)
核心调试工具将会禁止所有硬件中断,挂起操作系统,因此可以单步调试OS或者核心代码,可以访问堆栈信息,但是必须在Platform的环境下,利用至少一种外设进行通信。
4.3 硬件辅助调试方法
利用硬件调试工具可以观察物理设备的真实状态,一般常用的方法可以利用JTAG工具实时查看CPU内部寄存器,利用逻辑分析仪或者示波器实时查看物理外设的输入输出状态。利用指示LED来显示驱动程序实时状态信息。
4.4 Visual Studio调试
可以利用VS内置的调试工具进行单步跟踪,状态调试等。
5 测试驱动程序
驱动程序经过调试以后就需要对驱动的功能进行测试。其常用的方法如下:
1) 写一个应用程序来测试驱动程序的正确性
2) 模拟各种可能发生的硬件输入状态来测试驱动程序的正确性
3) 利用Windows CE自带的测试工具CETK来测试驱动程序的性能和完备性
6 驱动程序的集合和
6.1 驱动程序集成
驱动程序经过调试和测试确定其正确性后,就可以对驱动程序进行集成了。具体过程如下:
1) 在BSP的Driver目录下建立新的驱动文件夹MyDrv
2) 实现MyDrv驱动以及相关的DEF文件
3) 如果需要用到硬件中断资源,修改原BSP中的相关中断处理函数OEMInterruptEnable,OEMInterruptDisable,OEMInterruptDone,OEMInterruptHandler
4) 在Platform.reg中,增加驱动程序相关项
5) 在Platform.bib中,增加驱动程序的相关注册表项MyDrv.Dll$(_FLATRELEASEDIR)MyDrv.dll NK SH
6.2 驱动程序
驱动程序进过集成以后就可以使用了,具体的过程如下所示:
1) 利用CAB Wizard生成.cab驱动包
2) 直接提供驱动程序文件夹以及相关注册表项和修改说明
7 总结
本为详细的介绍了,wince下驱动开发的流程,介绍了驱动程序开发到的详细过程,并详细说明了各个部分的实现和操作方法,使是初学者对wince下驱动程序的开发流程和一般的开发工具有了初步的了解。
关键词:PCI; vxworks;驱动程序;运动控制卡
中图分类号:TP311 文献标识码:A 文章编号:1009-3044(2012)29-6966-03
VxWorks是目前世界上用户数量最大的实时嵌入式操作系统, 它具有高度可剪裁的微内核结构、高效的多任务调度、灵活的任务间通信手段、快速灵活的I/O系统、确定的微妙级中断延迟时间等优点。
本文介绍了基于PCI 接口规范的通用运动控制卡在VxWorks下的驱动程序的设计。对其设计驱动程序需要对实时操作系统、实时软件设计、硬件设备有深入的了解。因此, 该设计不仅本身具有很高的应用价值, 也为实时驱动程序的设计提供了一个样例。
1 系统组成
在基于微机的数据采集、处理与控制系统中,计算机接口卡常常是其中的关键硬件设备。目前在运动控制领域,各类运动控制卡得到广泛运用,其中以工控机通过ISA或PCI等系统总线连接运动控制卡的主从式结构最为流行,由工控机发出控制指令和参数,控制卡根据接收到的指令及参数完成具体控制功能。由于PCI总线的高速和即插即用特性,使其取代ISA被广泛应用于高速数据采集与传输等系统中,有效地解决了实时采集、实时传输和实时存储等问题。
2 PCI 配置空间
PCI系统具有三种地址空间:存储器空间、I/O空间和配置空间。每个PCI设备都有64个配置双字用于实现配置寄存器,64个配置双字分为两部分,⑴PCI协议定义了开头16个双字的格式和用途,称为设备的配置头区域;⑵其它48个双字的用途是由设备指定的。目前PCI协议定义了两种头区域格式,第1类配置头区域用于定义PCI-PCI桥,而第0类配置头区域用于定义其它PCI设备。所有的PCI设备,包括PCI-PCI桥都必须实现下述配置寄存器:厂商标志、设备标志、命令、状态、分类码、版本标志和头区域类型寄存器。如表1所示为PCI配置寄存器。这些寄存器对编程访问PCI设备至关重要,我们就是利用vendor ID 和device ID来枚举出对应的设备,再进一步获得设备的其他信息的。
3 驱动程序的开发
VxWorks 提供在指定目标系统上运行的板级支持包(BSP),本文选用的是针对pentium的板级支持包。VxWorks是支持PCI总线的,提供了一些库函数专门用来访问PCI设备。为了调用这些函数以方便开发,需要包含如下头文件"iosLib.h"、"pciConfigLib.h"、"pciIntLib.h"、"sysLib.h"和"pciLocalBus.h",还需要导入sysOutLong()和sysInByte()等函数。在config.h里面定义INCLUDE_PCI以添加VxWorks对PCI的支持,还可以定义PCI_CFG_TYPE为PCI_CFG_FORCE、PCI_CFG_AUTO 或 PCI_CFG_NONE,我们一般定义为PCI_CFG_NONE,Vxworks只需把配置好的信息读出来就可以了。
针对PCI 总线结构的数据采集模块,其驱动程序的主要开发步骤如下:确定设备的PCI 配置信息确定设备的内部存储器、寄存器基地址及中断号设备初始化中断服务程序设备各功能函数。以下按照程序执行的顺序分步骤给出源代码,并加以详细的说明。
4 结束语
利用上文所述的方法编写的驱动程序,达到了本项目所要求的性能指标,系统经过实际验证是高速稳定可靠的,而且由于PCI总线的即插即用特性,不需要用户去手动跳线,极大得方便了使用。
参考文献:
[1] microsoft msdn[EB].2001.
引言
近年来电力行业为了快速部署变电站,采用了建造整体变电所的方法:在生产基地将变电站的内部设备安装、调试完成,只留下与外界的接口,整体运到变电站所在地后进行安装和简单调试即可投入运行。其内部设备通过CAN总线进行通信,系统原有的监控软件基于DOS系统,维护调试比较困难,因此想要寻求更方便、友好的系统支持。经过比较,嵌入式操作系统市场上风头正劲的Windows CE .NET成为最终选择。微软的最新产品Windows CE.NET提供了端对端的开发、调试手段,可以不拆卸设备的情况下通过Telnet登录到WindowsCE上进行调试和维护,其系统本身为嵌入式市场进行重新设计,包括创建一个基于WindowsCE的定制设备所需的一切。这样就需要将原来DOS下的程序移植到WindowsCE.NET下,但是各个硬件厂商目前还没有提供CAN通信卡在Windows CE.NET下的驱动,所以开发Windows CE.NET下的CAN卡驱动成为项目推行中的关键一环。
本文主要针对研华的双口CAN卡PCM3680进行分析,介绍在WindowsCE.ENT系统下进行底层设备驱动开发的方法并提供CAN通信的实例。
1 CAN总线通信协议及CAN通信卡介绍
CAN总线是德国Bosch公司20世纪80年代初为解决现代汽车中众多的控制与测试仪器之间的数据交换而开的一种串行数据通信协议。它是一种多主总线,废除了传统的站地址编码,而代之以对通信数据块进行编码。这种方法使网络内节点个数在理论上不受限制,扩展格式中的29位的标识码便可以定义2 29个不同的数据块。
在本项目中使用的是研华的PCM3680,这是一块嵌入式PC104的双口CAN总线通信卡;CAN控制器采用Philips的独立CAN控制器SJA1000芯片;CAN收发器采用Philips的P82C250,可以同时操作两个CAN网络,提供高达1Mb/s的传输速度。PCM3680支持很宽的中断范围:中断3、4、5、6、7、9、10、11、12、15,同时1000V的光电隔离提供系统高可靠性。在CAN卡通信中,要用到CAN控制器中的很多寄存器,各个寄存器的含义和作用可以参考控制芯片的说明书。图1列出驱动程序设计中用到最主要的寄存器结构。
2 CAN卡驱动底层函数设计
本方案设计CAN驱动是放在Windows CE操作系统的内核下层,位于OEM adaptation layer(OAL)层的一个真正的驱动,而不是在主程序中的串口操作。在Windows CE的设备管理器可以看到CAN1和CAN2两个端口,并且可以查看其工作的正常与否和对其进行配置。如:中断号和I/O地址。
2.1 CAN卡寄存器读写函数
CAN卡的通信是通过操作CAN卡上的CAN控制器进行的。在CAN控制器中有很多寄存器,如控制寄存器、命令寄存器、状态寄存器、中断寄存器等,通过读写这些寄存器中的命令状态字可以检测和控制CAN卡的行为。在Windows CE.NET下,通过调用DOK中的API函数HalTranslateBusAddress,将CAN卡分配的物理地址映射为逻辑地址。这样各个寄存器对应的就是CAN卡基地址的偏移地址,因此,对寄存器的读写就转化为对内存地址的读写。下面是CAN卡寄存器的读写函数:
*在偏移量为off的地址读取一个字节的数据inline BYTE CANR(LPCAN_HW_OPEN_INFO hCan,DWORD off)
{
return hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr[off];
*将一个字节数据写到偏移量为off的地址中inline VOID CANW(LPCAN_HW_OPEN_INFO hCan,DWORD off,BYTE val)
{
hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr[off]=val;
}
参数LPCAN_HW_OPEN_INFO定义的是CAN卡的数据结构,其中成员lpMappeBaseAddr[0]表示的是映射后基地址,lpMappedBaseAddr[1]就是基地址+1的地址,对应CAN卡的寄存器是命令寄存器。通过上述两个函数可操作CAN卡上的所有寄存器。
2.2 CAN卡初始化
CAN卡的控制器比较复杂,在通信前必须确认硬件信息正确性、初始化各寄存器。初始化函数的基本流程如图3所示。
第一步,检查端口号和硬件信息的正确性,主要是CAN卡中断号是否有效。
第二卡,设置CAN卡默认参数:
CanCardConfigInfo CAN_DEFAULT_SETTING=
{0X00,0XFF,0X03,0X1C};/*设置默认波特率为125Kbps*/
DWORD dwThreadID =0;
PHYSICAL_ADDRESS phyAddr={hwInfo->dwIOBaseAddr *16,0 };
第三卡,用WinCE API函数LocalAlloc为CAN卡驱动中用到的数据结构分配缓冲区;通过HalTranslateBusAddress和MmMapIoSpace函数映射I/O地址,提供直接访问设备的虚拟地址:
if(!HalTranslateBusAddress(Isa,0,phyAddr,0,&phyAddr))
goto _ExitInit;
hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr=
(LPBYTE)MmMapIoSpace(phyAddr,CANCARDADDRLEN,FALSE);
if(!hCan->lpCanHWInfo->lpCanObj->lpMappedBaseAddr)
goto _ExitInit;
如果分配内存或映射逻辑地址失败,则退出初始化程序,CAN卡初始化失败。
第四步,初始化读写属性、共享模式、读超时时间和第二个CAN口的基地址。
第五步,创建CAN卡事件和数据接收事件:hCan->lpCanHWInfo->hCanEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
hCan->lpCanHWInfo->hRecvMsgEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
第六步,初始化中断,如果CAN卡有复位请求就退出初始化程序。设置好中断后启动数据接收线程,设置线程优先级继续线程处理;最后配置CAN卡参数,进入正常运行状态。
2.3 CAN卡信息发送
CAN卡的信息发送分为两个步骤。在对CAN卡基本信息进行检查后,首先设置发送缓冲的ID号。CAN标准模式的ID号为11位,偏移地址10中存放的是ID号的高8位,偏移地址11的高3位存放的是ID号的低3位,剩下5位分别是RTR位(远程传送请求位)和数据长度。通过CANW函数将处理后的数据写入到相应的偏移地址,设置完相应的地址数据后,通过循环将偏移地址12~19的数据采集回来存到数组中。然后,设置CAN卡的传输请求为允许并不断侦测状态寄存器的变化,当传输缓冲满标志或传输结束标志为1时通出程序,完成一次数据采集。传输缓冲区的寄存器如表1所列。
表1
ID号10ID.10ID.9ID.8ID.7ID.6ID.5ID.4ID.3RTR,数据长度码11ID.2ID.1ID.0RTRDLC.3DLC.2DLC.1DLC.0数据1~812~19数据数据数据数据数据数据数据数据表2
ID号20ID.10ID.9ID.8ID.7ID.6ID.5ID.4ID.3RTR,数据长度码21ID.2ID.1ID.0RTRDLC.3DLC.2DLC.1DLC.0数据1~822~29数据数据数据数据数据数据数据数据CAN消息发送函数的实现如下:
BOOL CAN_SendMessage(LPCAN_HW_OPEN_INFO hCan,LPCanCardMessageBuflpMsg)
{
BOOL bSuc=FALSE;
ASSERT(hCan && lpMsg && lpMsg->dwMessageLen <=8); /*防错处理*/
if(0= =(hCan->dwAccessCode & GENERIC_WRITE))
return FALSE;
:: EnterCriticalSection(&hCan->lpCanHWInfo->
TransmitCritSec); /*进入临界区*/
BYTE byV=static_cast<BYTE>(1pMsg->dwMsgID>>3);
CANW(hCan,10,byV); /*设置ID值高8位*/
byV=static_cast<BYTE>=((lpMsg->dwMsgID & 7)<<5);
if(lpMsg->bRTR) byV|=0x10;
byV+=static_cast<BYTE>(lpMsg->dwMessageLen);
CANW(hCan,11,byV);/*设置ID值低3位、RTR及数据长度*/
for(UINT i=0;<lpMsg->dwMessageLen;++i)
{
CANW(hCan,12+i,lpMsg->byMsg[i]);
} /*采集数据*/
CANW(hCan,1,1);/*重置传输请求*/
while(TRUE)
{byV=CANR(hCan,2);
if(byV & 0X40) /*传输缓冲区满,退出*/
{break;}
if(byV & 0X8){ /*传输结束,正确返回退出*/
bSuc = TRUE;
break;}
}
::LeaveCriticalSection(&hCan->lpCanHWInfo->TransmitCritSec); /*离开临界区*/
return bSuc;
}
2.4 CAN卡信息接收
CAN卡的信息接收是发送的逆过程,当接收缓冲区标志为1时,表示缓冲区已满可以接收数据,将数据接收到数组后释放接收缓冲区,然后对接收到的数据进行分解并存储到CAN卡信息缓冲区的结构体。接收缓冲区的寄存器结构如表2所列。
CAN消息接收函数的实现如下:
BOOL CAN_RecvRecvMessage(LPCAN_HW_OPEN_INFO
HCan,OUT LPCanCardMessageBuflpMsg)
{……
if(CANR(hCan,2)&1){ /*判断接收缓冲区是否已满*/
for(UINT i=0;i<10;++i)
recvBuf[i]=CANR(hCan,20+i);/*将数据暂存到临时缓冲区*/
CANW(hCan,1,4); /*释放接收缓冲区*/
LpMsg->dwMsgID=recvBuf[0]<<3; /*取出ID的高8位*/
BYTE byV =recvBuf[1];
LpMsg->dwMsgID+=byV >>5;/*取出ID低3位,然后和高8位合并*/
LpMsg->bRTR =byV &0x10?TRUE:/*返回RTR状态*/
LpMsg->dwMessageLen = byV &0XF; /*返回数据长度*/
……
}
else
{++hCan->lpCanHWInfo->dwErrorMsgCount;}/*没有收到数据,错误计数加1*/
::LeaveCriticalSection(&hCan->lpCanHWInfo->
ReceiveCritSec); /*离开临界区*/
Return bSuc;
}
2.5 CAN卡事件处理
CAN卡事件处理函数是CAN卡驱动程序中很重要的部分。驱动设计要求具有消息通知的功能,当事件发生时及时捕获事件并进行消息处理。
下面是事件处理函数的实现:
staric DWORD WINAPI CAN_EventHanle(LPVOID lpParam)
{
ASSERT(lpParam);
LPCAN_HW_OPEN_INFO hCan=(LPCAN_HW_OPEN_INFO)lpParam;
CanCardMessageBuf bufMsg;
while(TEUE)
{ /*循环等待CAN卡消息产生,然后进行处理*/
::WaitForSingleObject(hCan->lpCanHWInfo->hCanEvent,0XFFFFFFFF);
if(hCan->lpCanHWInfo->bKillCanThread) break; /*若CAN线程已关闭则中断*/
if(CAN_RecvMessage(hCan,&hufMsg)){ /*正确接收数据后*/
CAN_RecvBufPush(hCan,&bufMsg);} /*将数据压入缓冲*/
BYTE byV=CANR(hCan,3); /*将3号寄存器读出然后立即写入*/
CANW(hCan,3,byV);/*能够获取每次中断*/
InterruptDone(hCan->lpCanHWInfo->lpCanObj->dwSysIrqt);
} /*本次中断结束,等待下次中断*/
return 0;
}
2.6 其它函数
为了提供更多的功能和更方便地使用CAN卡进行通信,在CAN卡驱动程序中还设计了一些函数如CAN_Config用CAN卡信息配置、CAN_RecvBufPop用于处理接收缓冲区、CAN_Reset用于复位CAN卡、CheckHWInfo用于硬件信息检查等。这些函数提供了对CAN通信卡的设置、检查等功能,在这里不再详述了。
3 CAN卡驱动封装设计
CAN卡底层驱动函数虽然功能完整,但是对于用户使用比较复杂并且一般用户不需要了解底层实现的机制。为了便于使用,最后对CAN卡的驱动进行了封装,提供CanOpenFile、CanSendMsg等五个函数用于CAN总线的通信,以动态连接库(DLL)的形式提供给用户调用。封装函数及功能如下:
*CanOpenFile;初始化并打开CAN卡的一个端口。
*CanCloseFile;关闭由CanOpenFile打开的CAN卡端口。
*CanRecvMsg;接收CAN卡数据,打开CAN卡时必须具有GENERIC_READ权限。
*CanSendMsg;通过CAN卡发送数据。打开CAN卡时必须具有GENERIC_WRITE权限。
*CanIOControl;设置或获取CAN卡I/O参数支持的I/O控制包括:IOCTL_CAN_CONFIG,IOCTL_CAN_RESET,IOCTL_CAN_TIMEOUT,IOCTL_CAN_SENDREADY,IOCTL_CAN_RECVREADY。
下面是CanSendMsg函数实现的代码:
BOOL CanSendMSg(
HANDLE hCan,
LPCanCardMessageBuflpMsg)
{
if(!hCan||INVALID_HANDLE_VALUE= =hCan||
!lpMsg||lpMsg->dwMessageLen>8)return FALSE;
return CAN_SendMessage(LPCAN_HW_OPEN_INFO)
hCan,lpMsg);
该函数就是通过封装CAN卡的底层驱动函数SendMessage来实现的,这样将功能集中的五个函数更方便了用户使用。
结语
关键词:嵌入式操作系统;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 是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
关键词:MCP2515 嵌入式Linux 驱动 CAN
中图分类号:TP336 文献标识码:A 文章编号:1007-9416(2016)04-0000-00
1系统硬件结构介绍
本系统的硬件平台主要由OK2440开发板、基于MCP2515的CAN总线通信模块和以STC89C52为控制器的CAN节点模块组成。CAN通信模块用来完成OK2440开发板和STC89C52控制的节点模块之间的数据传输。
1.1 MCP2515功能简介
MCP2515是一款独立的CAN总线控制器,完全支持CAN V2.0B 技术规范。MCP2515 拥有六个验收滤波寄存器和两个验收屏蔽寄存器,通过它们可以过滤掉总线上不需要的报文,从而减少MCU关于处理CAN总线上无用数据的开销。MCP2515与MCU 的连接是通过业界标准串行外设接口来实现的。
1.2 TJA1050功能简介
TJA1050 是介于CAN控制器和物理总线之间的一种符合ISO 11898标准的高速CAN收发器。其最高速率可达1Mbit/s,而且它的电磁抗干扰EMI性极高,至少可以连接110个节点。在实际电路中,可为物理总线提供差动发送和为CAN控制器提供差动接收。
2 MCP2515相关驱动程序设计
2.1 Linux设备驱动简介
在Linux系统中,由于对硬件的操作必须处在特权模式下,在用户工作模式下,程序一般不能直接和硬件进行通信。因此,设备驱动程序则承担了用户模式下硬件和用户应用程序之间的通信工作,同时它还为应用程序和内核中其他的部分访问这些设备提供了程序接口。大多数设备驱动程序可以在系统工作时,以动态方式进行加载,在不需要的时候又可以将其卸载掉。
2.2 MCP2515驱动程序设计
2.2.1 MCP2515驱动初始化函数
在MCP2515的驱动初始化函数中首先通过s3c2440_spi_ioremap()函数将S3C2440上的SPI寄存器的物理地址映射到内核空间,这样才可以在驱动程序中访问和配置S3C2440的SPI寄存器。在正确的配置S3C2410的SPI寄存器后,通过s3c2440_spi_init()来完成对S3C2440相关寄存器的赋值。然后通过s3c2440_irq_init()函数来完成中断方面相关的设置。MCP2515_init()和MCP2515_dev_init()两个函数主要是针对于MCP2515控制器进行相关的配置和为MCP2515设备驱动程序申请和初始化内存空间。最后通过MCP2515 _cdev_register(Device0)函数完成MCP2515在内核中的注册。
2.2.2 MCP2515相关中断函数的注册
在CAN总线驱动程序中,CAN通信模块接收和发送数据必须以中断的方式与系统内核之间进行数据的交换,所以在MCP2515的驱动程序中必须用到内核中的相关中断函数。对于MCP2515的中断注册函数request_irq(),如果此中断注册函数返回值为0则表示中断注册成功,返回负数则表示注册失败。
2.2.3 MCP2515的文件操作函数
MCP2515_fops中定义了很多与设备有关的操作函数,内核可以通来它来访问与MCP2515操作有关的函数。在MCP2515的文件操作函数中,read()和write()两个函数是用来完成读写CAN总线上数据的功能的,通过传递不同的参数给驱动程序中的read()和write(),我们可以读取和写入相应的数据。驱动中的CAN总线读函数read()是整个驱动程序设计的难点,其中在函数的设计中采用了Linux内核阻塞机制。read()读取完CAN总线上的数据后,通过验收滤波寄存器和屏蔽滤波寄存器来决定总线上的数据帧是否存入到总线控制器相应的接收缓冲寄存器里。
2.2.4 MCP2515的卸载函数
当我们不需要继续使用某个设备时,我们可以将这个设备从内核中卸载掉。在设备的卸载过程中,必须将其内核中所对应的设备号释放掉。在模块的卸载函数中,我们通过调用int unregister_chrdev_region(unsigned int major,const char *name)函数来完成设备驱动的卸载。此函数的两个参数分别对应设备文件的主设备号和设备名。在卸载模块时,Linux内核会把设备名与内核中已注册的设备名称进行对比,如果两者相等,则完成设备的卸载,反之则卸载失败。MCP2515的驱动卸载函数主要是完成MCP2515驱动在内核中所占用的中断的释放和MCP2515在内核中的注销。
3 结语
本文重点讨论了S3C2440中MCP2515的驱动程序设计方法,并详细介绍了Linux系统下如何开发MCP2515的驱动程序的方法。实验结果表明,本文所设计的Linux下MCP2515驱动程序可以在OK2440开发板上正常运行,基本可以完成CAN总线上数据的正常发送与接收,测试结果符合论文的要求。本文提到的基于Linux下MCP2515驱动程序的开发,对其他Linux驱动程序的开发具有一定的启示作用。
参考文献
[1]宋宝华.Linux设备驱动开发详解[M].北京:人民邮电出版社,2008.
[2]杨庆华,张景元.单片机和MCP2515的CAN总线通信模块设计[J].单片机与嵌入式系统应用,2007.
[3]刘淼.嵌入式系统接口设计与Linux驱动程序开发[M].北京:北京航空航天大学出版社,2006.
关键词:CAN_NODE实验板;ATmega128;CAN总线驱动程序
中图分类号:TP305文献标识码:B 文章编号:1009-3044(2011)16-3952-03
CAN_NODE Bus Drivers Design Based on Atmega128
LIU Bin, LIU Jun-liang, MA Jin-bo, WANG Jun-qing
(2332 Laboratory, College of Engineering, Ocean University of China, Qingdao 266100, China)
Abstract: CAN_NODE is a powerful 8-bit AVR microcontroller experiment board, it is based on AVR RISC structure 8-bit low-power CMOS microprocessor ATmega128. This paper briefly expounds the profile of the fieldbus technology, hardware structure of CAN_NODE experimental board and characteristic of ATmega128, then the CAN bus drivers based on the experimental board is focused on.
Key words: CAN_NODE experiment board; ATmega128; CAN bus drivers
1 概述
现场总线(Fieldbus)技术是当前自动化技术的热点之一。现场总线技术集先进的嵌入式系统、现代通信、自控理论、网络技术于一身,充分体现出先进技术的进步能够为人类带来的便利。
CAN:全称为“Controller Area Network”,即控制器局域网,是国际上应用最广泛的现场总线之一。最初,CAN被设计作为汽车环境中的微控制器通讯,在车载各电子控制装置ECU之间交换信息,形成汽车电子控制网络,比如,发动机管理系统、变速箱控制器、仪表装备、电子主干系统中,均嵌入CAN控制装置。
AVR单片机是1997年由ATMEL公司研发出的增强型内置Flash的RISC(Reduced Instruction Set CPU) 精简指令集高速8位单片机。AVR的单片机可以广泛应用于计算机外部设备、工业实时控制、仪器仪表、通讯设备、家用电器等各个领域。
2 CAN_NODE实验板硬件结构
CAN_NODE实验板上提供了CAN总线通讯所需要的硬件,和一些按键,LED,USB接口等常用的功能部件,还提供了为系统扩展而预留的扩展功能接口,也提供了SPI接口和JTAG接口以方便下载和调试。
2.1 CAN_NODE实验板功能框图
图1为系统结构框图。
2.2 ATmega128的特点
其先进的指令集以及单周期指令执行时间, 使得ATmega128 的数据吞吐率高达1 MIPS/MHz。同时ATmega128具有:128K 节的系统内可编程Flash(具有在写的过程中还可以读的能力,即RWW)、4K 字节的EEPROM、4K 字节的SRAM、53 个通用I/O 口线、32个通用工作寄存器、实时时钟RTC、4 个灵活的具有比较模式和PWM 功能的定时器/ 计数器(T/C)、两个USART、面向字节的两线接口TWI、8 通道10 位ADC(具有可选的可编程增益)、具有片内振荡器的可编程看门狗定时器、SPI 串行端口、与IEEE 1149.1 规范兼容的JTAG 测试接口(此接口同时还可以用于片上调试)。
3CAN总线驱动程序设计
软件开发采用的是ImageCraft公司开发的ICCAVR,软件的下载采用双龙ATMEL_ISP下载软件。ICCAVR是一种使用符合ANSI 标准的 C 语言来开发ATMEL公司生产的微控制器(MCU)程序的一个工具,它有以下几个主要特点:
1)ICCAVR 是一个综合了编辑器和工程管理器的集成工作环境(IDE),其可在Windows9X/NT下工作,源文件可被组织到工程中,文件的编译和工程的构筑也是在这个环境中完成。
2)编译错误显示在状态窗口中,并且当你用鼠标单击编译错误时,光标会自动跳转到编辑窗口中引起错误的那一行。这个工程管理器还能直接产生您希望得到的可以直接使用的INTELHEX 格式文件,INTEL HEX 格式文件可被大多数的编程器所支持,用于下载程序到芯片中去。
集成开发环境如图2所示。
CAN总线驱动程序主要包括四个部分:CAN控制器初始化、接收数据、发送数据和总线异常处理。
图3为主程序流程图。
主要程序设计如下所示:
3.1 初始化
Can控制器初始化的操作包括:中断控制,硬件使能,软件复位,工作模式等。
初始化程序如下
unsigned char can_state;
IOWR(CAN_IP_0_BASE,CAN_IER,0x00);//禁止中断
IOWR(CAN_IP_0_BASE,CAN_MOD,0x09);//进入复位模式,单验收滤波器
can_state=(unsigned char)IORD(CAN_IP_0_BASE,CAN_MOD);
while((can_state&0x01)==0x00)//检测是否进入复位模式
{
IOWR(CAN_IP_0_BASE,CAN_MOD,0x09);//进入复位模式,单验收滤波器
can_state=(unsigned char)IORD(CAN_IP_0_BASE,CAN_MOD);
}
IOWR(CAN_IP_0_BASE,CAN_CDR,0xC1);//peliCAN,禁止时钟输出,禁止TX1,RX1c8
IOWR(CAN_IP_0_BASE,CAN_ACR0,local_code1);//验收码1
IOWR(CAN_IP_0_BASE,CAN_ACR1,local_code2);//验收码2
IOWR(CAN_IP_0_BASE,CAN_ACR2,local_code3);//验收码3
IOWR(CAN_IP_0_BASE,CAN_ACR3,local_code4);//验收码4
IOWR(CAN_IP_0_BASE,CAN_AMR0,0xff);//屏蔽码1
IOWR(CAN_IP_0_BASE,CAN_AMR1,0xff);//屏蔽码2
IOWR(CAN_IP_0_BASE,CAN_AMR2,0xff);//屏蔽码3
IOWR(CAN_IP_0_BASE,CAN_AMR3,0xff);//屏蔽码4
IOWR(CAN_IP_0_BASE,CAN_BTR0,0x01);//同步跳转3个周期,系统时钟4倍周期
IOWR(CAN_IP_0_BASE,CAN_BTR1,0x1C);//采样点3,段一6,段二3
IOWR(CAN_IP_0_BASE,CAN_OCR,0x1A);//控制寄存器
IOWR(CAN_IP_0_BASE,CAN_MOD,0x08);//进入工作模式,单验收滤波器
can_state=(unsigned char)IORD(CAN_IP_0_BASE,CAN_MOD);
while((can_state&0x01)==0x01)//检测是否进入复位模式
{
IOWR(CAN_IP_0_BASE,CAN_MOD,0x08);//进入工作模式,单验收滤波器
can_state=(unsigned char)IORD(CAN_IP_0_BASE,CAN_MOD);
}
IOWR(CAN_IP_0_BASE,CAN_IER,0x01);//开接收中断
}
CAN是一种基于广播的通讯机制,广播通讯依靠报文(Message)的传送机制来实现,因此CAN并未定义站及站地址,而仅仅定义了报文,这些报文依靠报文确认区(Identifier)来进行识别,一个消息报文确认区在一个网络中必须是唯一的,它不但描述了某一报文的意义,而且还定义了报文的优先级,当很多站都在访问总线时,优先级是很重要的,因此,CAN是通过报文的确认区来决定报文的优先级的。
CAN节点之间的数据传输采用的协议是报文格式,其29位的帧标识符和报文数据部分的规定如图4所示。
3.2 数据接收
接收数据可以采用查询方式或中断方式。在某一段时间内CAN总线并不是总在活动,为了提高效率,可采用中断方式。
程序如下:
alt_u8 can_irq_reg;
//can_irq_reg=IORD(CAN_IP_0_BASE,CAN_IR);
//if ((can_irq_reg & 0x01)==1)
{
can_rx_reg[0]=IORD(CAN_IP_0_BASE,CAN_TX_SFF_EFF_H);//发送帧
can_rx_reg[1]=IORD(CAN_IP_0_BASE,CAN_TX_SFF_EFF_C1);//验收码1
can_rx_reg[2]=IORD(CAN_IP_0_BASE,CAN_TX_SFF_EFF_C2);//验收码2
can_rx_reg[3]=IORD(CAN_IP_0_BASE,CAN_TX_EFF_C3);//验收码3
can_rx_reg[4]=IORD(CAN_IP_0_BASE,CAN_TX_EFF_C4);//验收码4
can_rx_reg[5]=IORD(CAN_IP_0_BASE,21);
can_rx_reg[6]=IORD(CAN_IP_0_BASE,22);
can_rx_reg[7]=IORD(CAN_IP_0_BASE,23);
can_rx_reg[8]=IORD(CAN_IP_0_BASE,24);
can_rx_reg[9]=IORD(CAN_IP_0_BASE,25);
can_rx_reg[10]=IORD(CAN_IP_0_BASE,26);
can_rx_reg[11]=IORD(CAN_IP_0_BASE,27);
can_rx_reg[12]=IORD(CAN_IP_0_BASE,28);
}
can_rx_flag=1;
IOWR(CAN_IP_0_BASE,CAN_CMR,0X04);//释放接收缓冲区
can_irq_reg=IORD(CAN_IP_0_BASE,CAN_IR);
while ((can_irq_reg & 0x01 )==0x01)
{
IOWR(CAN_IP_0_BASE,CAN_CMR,0X04);
can_irq_reg=IORD(CAN_IP_0_BASE,CAN_IR);
}
3.3 数据发送
将待发送的数据打包成符合CAN协议的帧格式后,写入发送缓冲区,然后发送。
程序如下所示:
if(can_rx_flag==1)
{
can_tx_count=0;
can_rx_flag=0;
//IOWR(CAN_IP_0_BASE,21,0x55);
//IOWR(CAN_IP_0_BASE,21,0xaa);
//data_reg=IORD(CAN_IP_0_BASE,21);
IOWR(CAN_IP_0_BASE,CAN_TX_SFF_EFF_H,0x88);//发送帧
IOWR(CAN_IP_0_BASE,CAN_TX_SFF_EFF_C1,local_code1);//验收码1
IOWR(CAN_IP_0_BASE,CAN_TX_SFF_EFF_C2,local_code2);//验收码2
IOWR(CAN_IP_0_BASE,CAN_TX_EFF_C3,local_code3);//验收码3
IOWR(CAN_IP_0_BASE,CAN_TX_EFF_C4,local_code4);//验收码4
IOWR(CAN_IP_0_BASE,21,can_rx_reg[5]);//数据
IOWR(CAN_IP_0_BASE,22,can_rx_reg[6]);//数据
IOWR(CAN_IP_0_BASE,23,can_rx_reg[7]);//数据
IOWR(CAN_IP_0_BASE,24,can_rx_reg[8]);//数据
IOWR(CAN_IP_0_BASE,25,can_rx_reg[9]);//数据
IOWR(CAN_IP_0_BASE,26,can_rx_reg[10]);//数据
IOWR(CAN_IP_0_BASE,27,can_rx_reg[11]);//数据
IOWR(CAN_IP_0_BASE,28,can_rx_reg[12]);//数据
IOWR(CAN_IP_0_BASE,CAN_CMR,0x01);//发送
}
3.4 异常情况处理
总线发生故障时,下行的CAN节点可能脱离总线。可通过读取错误计数器对计数器递减计数的情况进行监测并作相应处理。若前面传输到CAN控制器的数据未被读出,而接收缓冲区又没有及时释放,就有可能引起后面信息的丢失。这时必须通过写命令寄存器来清除CANSR的数据溢出位。这两种异常可通过异常中断来处理,只要在中断子程序中加入处理代码即可。其他的总线异常处理可根据使用情况决定是否在软件中处理。
4 结束语
本设计对CAN模块软硬件结构及ATmega128的特点进行简要的描述,主要对基于ATmega128单片机的CAN_NODE总线驱动程序的进行设计。现场总线技术以其独有的技术优势和特点,在现代分布式测量与控制技术领域中应用已愈来愈广泛。各种现场总线的主控制器一般都内嵌有相当完善的、开放式的互联通信协议,它具有通信速度快、误码率低、开发设计简单及网络使用维护方便等诸多特点,是实现网络化现场测量与控制技术的一个发展方向。
参考文献:
[1] 周立功.iCAN现场总线原理与应用[M].北京:北京航空航天大学,2007.
[2] 范伟成.基于ATmegal28单片机的CAN总线接口设计及应用[M].上海:上海齐耀动力技术有限公司,2008.
[3] 刘滨.基于单片机的CAN_NODE的设计与实现[M].青岛:中国海洋大学,2011.
关键词:VxWorks操作系统;串口驱动程序;共享中断
中图分类号:TP316文献标识码:A文章编号:1009-3044(2009)33-9544-03
The Design of Driver for Multi Serial Sharing IRQ Based on VxWorks System
LIU Wei,TAO Ying
(Department of Information Engineering, Jiangxi Vocational College of Finance and Economics, Jiujiang 332000, China)
Abstract: This paper introduces the structure of serial port driver on the VxWorks system, then the achievement of the driver of serial driver is analyzed. The driver for multi serial sharing IRQ based on VxWorks system is designed, and loading VxWorks system with the module of the driver is achieved.
Key words: VxWorks system; serial port driver; sharing IRQ
VxWorks操作系统是美国Wind River公司开发的一种嵌入式实时操作系统,由于其高可靠性、强实时性以及可裁减性,广泛应用于航空航天、军事、民用通信和工业控制等领域。
在某大型控制系统中,我们需要开发一个具有4路串口通讯、1路CAN通讯以及2路以太网通讯的多种通讯方式并存的通讯设备。考虑到通讯能力以及通讯的实时性要求,CPU选用盛博公司PC104+总线的Pentium III处理器,串口选用具有PC104总线接口的4路串口扩展板,采用VxWorks操作系统来实现以上需求。由于每种通讯方式都采用中断方式触发,而系统硬件提供的中断源是有限的,针对这种情况,为了节省系统的中断资源,本文设计了一个基于VxWorks的多串口共享中断的驱动程序,并对该驱动程序的功能进行了长时间测试验证。
1 串行设备驱动的结构
在VxWorks操作系统中,串行设备作为一种特殊的字符型设备,操作系统为其提供一个简单、统一、独立于设备的接口,在应用层对于串行设备的任何操作都可以视为对一个文件的操作,而具体的实现是通过串行设备的驱动程序来完成。
在VxWorks中串行设备驱动采用3层抽象的软件结构,即I/O系统、虚拟设备ttyLib或tyLib以及硬件驱动,其结构示意图如图1所示。在VxWorks中,I/O系统并不直接与具体的硬件驱动进行交互,而是将驱动程序中与硬件无关的部分放在虚拟设备ttyLib中实现,再利用虚拟设备ttyLib与I/O系统进行通讯,使得I/O系统独立于具体的硬件驱动,而驱动程序的开发者只需要实现系统所提供的接口并且将其挂载到虚拟设备ttyLib就能完成具体串行设备驱动的设计,从而保证驱动代码的可复用性和接口的统一性。
2 串行设备驱动的实现
VxWorks在启动过程中对串行设备驱动的实现主要包括两部分:串口的初始化和串行设备的创建。串口的初始化主要包括初始化串口设备,分配串口所需的资源以及完成串口中断程序的系统挂接;串行设备的创建包括tty驱动的初始化和对tty设备的创建,即建立起I/O系统与硬件驱动层的联系。
2.1 串口的初始化
sysInit()作为VxWorks操作系统启动的入口程序会调用第一个C程序函数usrInit(),完成用户定义系统的初始化工作,而串口的硬件初始化是在usrInit()函数的子函数sysHwInit()中完成。对于VxWorks现有的Intel8250驱动(Tornado目录/target/src/drv/sio/i8250Sio.c),sysHwInit()还会调用sysSerial.c文件下的sysSerialHwInit(),sysSerialHwInit()函数主要对串行设备的设备描述符进行初始化,在初始化过程中还会调用底层的i8250HrdInit()对串行设备的端口进行初始化。在完成系统硬件和VxWorks内核的初始化以后,系统会启动一个函数名为usrRoot()的任务,usrRoot()作为VxWorks操作系统的根任务调用sysClkConnect()对系统时钟中断进行配置,而具体的工作是由sysClkConnect()的子函数sysHwInit2()完成,其中sysHwInit2()会调用sysSerialHwInit2()来完成串行设备的中断挂接。
2.2 串行设备的创建
在usrRoot()中通过调用ttyDrv()完成tty驱动的初始化,而ttyDrv()则调用iosDrvInstall()将tty驱动添加到系统的驱动程序列表中,并且完成与I/O系统层的各系统操作函数的连接。tty虚拟设备层与底层硬件驱动的连接则是通过ttyDevCreate()来完成,并实现各个串行设备的创建。
3 多串口共享中断的驱动程序开发
串口扩展板选用的是盛博的A3-CSD板卡,采用PC104总线接口,集成了4路16C554兼容的光电隔离异步串行口,每个串行口能独立控制发送与接受,且具有16字节FIFO以减少中断请求次数,此外该扩展板还具有一个串口中断状态指示寄存器,可以指示产生中断的串口。根据上述硬件配置,可以在现有Intel8250驱动的基础上进行改进来完成多串口共享中断的驱动程序设计。
3.1 串口设备的初始化
每个串口设备都需要有一个的描述自身属性的结构体I8250_CHAN_EX,即设备描述符,且结构体的第一个成员必须为指向SIO_DRV_FUNCS结构的指针,该结构体还包含描述16C554芯片各个端口的信息以及提供给高层协议的回调函数。在系统启动过程中通过调用sysSerialHwInitEx()完成对该结构体的初始化并且将自定义的全局指针数组pi8250ChanEx[4]中各元素分别指向4个串口的I8250_CHAN_EX结构体,初始化过程中会调用i8250HrdInitEx()将串口驱动程序的设备操作入口函数安装到SIO_DRV_FUNCS结构中,然后调用sysSerialHwInitEx2()完成串口中断的系统连接。其中sysSerialHwInitEx2()的实现代码为:
void sysSerialHwInitEx2 (void)
{
int i;
for (i = 0; i < N_UART_CHANNELS_EX; i++)
if (i8250ChanEx[i].int_vec)
{/*将四个串口设备的中断服务程序i8250ShareIntEx ()连接到同一中断*/
(void) intConnect (INUM_TO_IVEC (i8250ChanEx[i].int_vec),
i8250ShareIntEx, (int)&i8250ChanEx[i] );
if (sysBp)
sysIntEnablePIC (devParasEx[i].intLevel);/*中断使能*/
}}
其中,宏N_UART_CHANNELS_EX表示串口设备的个数,i8250ChanEx结构的成员变量int_vec表示该串口的系统中断号,这里每个i8250ChanEx结构的int_vec项值都是相同的。
3.2 串口驱动程序的入口点函数编写
编写串口设备驱动程序需要完成串口设备的入口点函数,这些函数包括控制命令函数i8250IoctlEx(),启动发送循环函数i8250StartupEx(),轮询方式输入函数i8250PRxCharEx(),轮询方式输出函数i8250PTxCharEx(),回调安装函数i8250CallbackInstallEx(),单串口中断服务函数i8250IntEx(),多串口共享中断服务函数i8250ShareIntEx()等函数。这里只列出多串口共享中断服务函数i8250ShareIntEx(),其余函数可以参考i8250Sio.c文件的各相应函数。
void i8250ShareIntEx (I8250_CHAN_EX*pChan)
{
FASTintoldlevel;
oldlevel = intLock(); /*关闭系统中断*/
IntStatus = sysInByte(UART_INT_STATUS); /*读串口中断状态指示寄存器* /
while(( IntStatus & 0x0F) != 0x00 )/*判断是否有串口中断产生*/
{
if (IntStatus & COM0_ INT _FLAG)
i8250IntEx(pi8250ChanEx[0]);/*串口1产生了中断*/
……………
if (IntStatus & COM3_ INT _FLAG)
i8250IntEx(pi8250ChanEx[3]);/*串口4产生了中断*/
}
intUnlock(oldlevel); /*开启系统中断*/
}
其中,全局变量pi8250ChanEx为I8250_CHAN_EX结构的指针数组,分别指向4个串口设备所对应的I8250_CHAN_EX结构,宏UART_INT_STATUS表示串口中断状态指示寄存器地址。
在进入i8250ShareIntEx()后首先关闭系统中断,通过查询串口中断状态指示寄存器来判断产生中断的串口设备,然后将产生此中断的串口描述符结构体,即pi8250ChanEx[4]中对应的元素,作为参数传递给单串口中断服务函数i8250IntEx(),最后重新开启系统中断。
3.3 以模块加载串口驱动程序
在config.h中加入#undef INCLUDE_TTY_DEV,执行下面的代码后生成一个o格式的串口驱动的库文件8250SioEx.o,然后在应用程序中利用loadModule()将8250SioEx.o动态加载到内存中运行。
sysSerialHwInitEx();/*初始化串口设备*/
sysSerialHwInitEx2(); /*串口中断的系统挂接*/
if (N_UART_CHANNELS_EX > 0)
{
ttyDrv();
for (int i = 0;i < N_UART_CHANNELS_EX;i++)
{
sprintf (tyName, "%s%d", "/tyCo/", i);
(void) ttyDevCreate (tyName, sysSerialChanExGet (i), 512, 512); /*创建tty设备*/
}
}
其中sysSerialChanExGet()返回一个描述串口设备的I8250_CHAN_EX结构体。
4 结束语
本文详细分析了串行设备驱动程序的结构以及在VxWorks启动过程中串行设备驱动程序的加载过程,设计了一个多串口共享中断的驱动程序,利用该驱动程序对4个串口同时进行了连续10小时的数据收发测试,4个串口都能稳定地发送和接收数据。此外,在测试过程中发现在进入多串口共享中断服务函数后需要将系统中断关闭,待执行完中断处理后再开启系统中断,否则会引起串口工作的不稳定。
参考文献:
[1] 周启平.VxWorks下设备驱动程序及BSP开发指南[M].北京:中国电力出版社,2004.
[2] 陈智育,温彦军,陈琪.VxWorks程序开发实践[M].北京:人民邮电出版社,2004.
[3] VxWorks programmer’s guide version 2.0[Z].Wind River System Inc,1999.
[4] TL16C550 asynchronous communications element[Z].1998.
关键词:DSP;TMS320C6416;PCI Linux2.6;驱动程序;DMA
中图分类号:TP368.11 文献标识码:A文章编号:1007-9599(2012)04-0000-02
一、引言
数字信号处理器(DSP)在通讯、语音图像处理、数据加密等各方面得到越来越广泛的应用。TI C6000系列DSP芯片内嵌PCI接口,支持主/从模式的读写,以33MHz的工作频率和32位地址/数据总线进行数据传输,理论上最高可以支持132MByte/s的数据传输,在速度上远远超过DSP常用的HPI、McBSP总线,完全可以满足传输实时性的要求。
本文在Linux2.6内核下,以TMS320C6416 DSP数据加密卡为平台,研究了PCI设备驱动程序的开发方法。首先介绍了常规的以IO内存方式对DSP进行读写操作的方法,接着结合DSP芯片特点,提出了一种基于DMA传输方式的DSP加密卡控制方法,与常规方法比,显著地提高了传输速度,具有较高的应用价值。
二、TMS320C6416的PCI接口
TMS320C6416是一款TI公司生产的DSP芯片,属于C6000系列。C6000系列DSP片内集成了一个主/从模式的PCI接口,可以通过PCI总线实现主机与DSP的互连。TMS320C6416的PCI接口由EDMA的地址产生硬件与DSP相连,支持PCI接口规范2.2版本[1]。
(一)PCI数据访问
DSP内嵌PCI主要包含三类寄存器:PCI配置寄存器、PCI I/O寄存器以及存储器映射寄存器。
PCI主机通过3个基地址空间(Base0-2)能够访问DSP全部的存储器映射空间。如图1所示,Base0空间定义了一段可预取4Mbytes的DSP存储器空间。Base1定义了8Mbytes不可预取的存储器空间。Base2定义了16Byte的I/O空间。当主机上电启动后,主机操作系统执行配置事务,将DSP的内存和I/O区域映射到主机处理器的地址空间,此段空间的物理地址,可以通过读取BASE0-2寄存器获得[2]。
三、Linux驱动程序开发
Linux下对TMS320C6416加密卡进行驱动程序开发,要完成的工作主要包括:对PCI设备的查找、初始化、卸载,对字符设备的数据读写和控制,中断处理等[3]。
(一)PCI设备初始化
在Linux2.6内核中,使用pci_driver结构体来定义PCI驱动。设备查找时通过id_table结构体中的的VENDER_ID、DEVICE_ID来区别不同的设备,对于TMS320C6416芯片,VENDER_ID和DEVICE_ID分别为0x104c、0xa106。
pci_driver结构体中的probe()函数向内核提供了对硬件进行探测并初始化的接口。probe()函数完成的功能有:
1.读取DSP加密卡Base0-2空间基地址和中断号,通过pci_read_config_dword()函数实现;
2.将IO内存空间映射到Linux内核虚拟地址空间。通过ioremap()函数实现;
3.申请DSP加密卡中断服务程序。通过request_irq()函数实现;
4.申请DSP加密卡的主设备号,注册DSP加密卡字符设备驱动程序。通过cdev_init()、cdev_add()函数实现。
初始化完成后,可以通过设置DSPP寄存器,访问BASE0空间读取DSP内存资源,基于I/O内存方式进行PCI数据读写关键代码如下:
static ssize_t dsp_read(struct file *fp, char *buf, size_t size, loff_t *f_pos)
{
outl(*f_pos, dsp_dev.iospace+IO_DSPP_OFFSET); //设置DSPP寄存器
copy_to_user(buf,dsp_dev.bar0, size); //拷贝DSP内存至主机
}
在实际使用中, TMS320C6416 PCI接口可以采用DMA方式进行数据操作,通过DMA控制器直接传输I/O数据,可大大提高与主机通信的吞吐量。
(二)基于DMA传输的加密卡控制
在Linux2.6内核中,file_operations结构体中的ioctl()函数向应用程序提供了对硬件进行命令控制的接口。以DSP加密卡加解密控制命令为例,加密卡加密命令要完成的操作是:通过DMA读操作将主机数据发送给DSP加密卡,等待DSP加密卡将数据加密完毕后,通过DMA写操作将加密数据回传给主机。详细步骤如下:
1.主机调用内核函数get_free_page()申请DMA空间,调用virt_to_bus()函数将内核空间虚拟地址转换成PCI总线地址,将此地址写入到DSP端PCIMA寄存器中;
2.主机访问Base1空间,调用writel()函数修改DSP端PCIMA、DSPMA寄存器配置DMA传输源地址、目的地址,修改DSP端PCIMC寄存器设置DMA传输方向并启动DMA传输[4];
3.DMA传输完成后,DSP端响应MASTER OK中断,在中断中释放信号量,开始数据加密操作。加密操作完成后,使用DMA方式将产生的密文数据回送给主机,并给主机发送中断;
4.PC机响应 中断,将密文数据拷贝至用户空间。
(三)用户态设备访问
Linux系统下可通过使用命令insmod将驱动程序编译生成的.ko文件插入到内核中,从而实现驱动程序的模块化动态加载。使用mknod命令创建由主、次设备号确定的加密卡设备文件,然后就可以像操作普通文件一样来操作DSP加密卡设备。打开设备文件后,就可以实现对设备进行诸如数据读写、设备控制等操作。
四、测试结果
在主机上编写测试程序,设置DSP的EMIF工作在100 MHz/133 MHz时钟,数据线为32位。PCI总线工作在33MHz时钟,使用DMA方式进行连续的数据读写,传输1GB的数据,测得DSP主模式下DMA方式数据写操作速度为90Mbytes/s,读操作速度为70MBytes/s,实验证明,所开发的驱动程序使用良好稳定,传输高效,满足高速数据传输和高速数据处理的需要。
参考文献:
[1]Texas Instruments.TMS320C6000 DSP Peripheral Component Interconnect(PCI)Reference Guide[Z].2007:20221
[2][美]Jonathan C,Alessandro R.LINUX设备驱动程序(第2版)[M].北京:中国电力出版社,2006
[3]宋宝华,华清远见.LINUX设备驱动开发详解[M].北京:人民邮电出版社,2010
[4]李静,赵保军.基于TMS320C6416内嵌PCI设备驱动程序开发[J].微机发展,2005(10):135-137
计算机专业的学生在初开始接触专业课时就要学习程序设计,程序设计的学习比较困难,就算对一些理论知识有所理解,但是在实践阶段也很难有效的掌握其技巧与技术。特别是对程序语言设计的学习,很多学生感到不知所措,无从下手。
1.1学生感到程序设计较难理解
计算机程序设计的学习困境主要表现在概念难懂,技术难以掌握,理论与实践的脱节等方面,尤其是在程序语言学习中面向对象程序设计语言时,绝大多数的学生不理解面向对象程序设计思想,不会使用类的思想进行程序设计。往往感到困难重重而方式深入学习,导致学习成绩节节下滑,不利于后来其他计算机专业课的学习。
1.2主动学习能力差
学生长期在传统应试教育环境影响下,形成了被动学习的习惯,缺乏学习的积极性与主动性,另外还有一些学生养成的不良学习习惯,在课堂学习中情绪比较懒散,精神比较散漫,对教师所讲的内容没有兴趣,这样很难提高学生学习成绩,影响教学效果的提高。
1.3实践能力不高
计算机是一门实践性比较强的学科,不仅需要学生掌握基本的理论知识,更重要的是理论应用于实际的能力,因为学习计算机的目的就是解决实际中遇到的问题。但是在实际教学中,很多教师设计的教学目标脱离学生的应用宗旨,教学过程中理论课比较多,实践课程比较少,这样较难培养学生的实际动手操作能力,很难真正提高教学效果。
1.4教学方法单一
过去教师一般采用传统的教学方法,从程序设计的概念出发,围绕理论知识点加以讲解,过多注重理论知识的讲解,而教材中的实力一般与学生实际生活相差较远,学生在学习的过程中感到生涩难懂,只会比葫芦画瓢,不会举一反三,缺乏独立思考问题和解决问题的能力。教师在教学过程中忽略了学生的主体地位,较难提高学生学习兴趣,同时也达不到较好的学习效果。
2项目驱动教学模式特点
2.1项目实践环境突出
项目驱动教学过程中,导师带领学生在学习专业理论知识的同时进行实际应用项目的开发。学生与老师在学习的过程中始终处于一种相互配合、沟通的环境下,强调学生的自主学习、积极沟通、勇于实践。学生在项目驱动下,带着问题进行有效的学习,这样能够培养学生思维扩散能力、动手操作能力与团结合作精神。
2.2强调教师的引导作用
项目驱动教学模式注重把理论知识转化为实际技术,在教学过程中教师仅仅起引导学习的作用,课堂的主体是学生。学生按照项目需求被划分为若干个小组,导师在课堂中主要监督、指导学生行为,在项目学习过程中导师要随时解答学生的疑问,为学生补充技能知识,实时启发学生在项目学习中解决问题的正确思路,开发学生思维创造能力,帮助学生掌握项目技能。
2.3培养学生计算机专业能力
项目驱动模式的实施目的是提高学生软件开发与应用能力,事件性知识一般比较隐蔽,而项目驱动教学能够通过教学过程中各种功能的实施,使一些隐藏在软件开发过程中的核心要素显现出来,通过这种方式的学习,学生将很快的具备软件应用开的基本能力,提高学生实践能力与应用能力。
3项目驱动教学实施过程
3.1项目设计
项目驱动模式教学过程中,首先导师要根据程序设计教学内容,设定教学目标,将教学计划、目标融入到教学项目中,然后将整个教学项目按照学习小组分成若干个独立的小项目,再把这些小项目按组分配给学生,最后导师围绕项目内容设计具体教学内容,项目来源一般源自于教师纵横向教学项目。
3.2实施形式
利用项目驱动模式进行教学的过程中,学生需要进入专门的工作室进行软件程序的学习与开发。在工作室中,主要的学习方式是自学,教师在这种模式下主要起引导作用,课程知识除了很少部分较深的理论课由导师专门讲授以外,其他的课程都是学生围绕项目进行自主学习、合作学习,主要学习方式包括:小组研讨、导师解疑、技术交流、调查研究等形式;课程的具体的实施要根据教学内容以及学生的实际认知情况进行合理的分配。这种教学模式的目的在于各种信息技术及认知提高计算机教学质量和效率,培养学生自主学习能力、创新能力和勇于探索精神以及实践能力。其中自主学习是由学生自己积极主动的去学习,在学习过程中导师的角色是解答疑问,并不是直接帮学生解决问题,导师可以向学生传授解决问题的方法和思路,引导学生向正确的解答思路上靠,提供给学生解决问题的资料,引导学生围绕疑问积极探索。如果学生在学习过程中遇到难以解决的问题,导师首先要积极引导学生找到解决问题的方法,同时教会学生利用移动通信、互联网、QQ以及电子邮件等先进技术手段进行搜索或者在线讨论与交流,尤其要教会学生怎样使用互联网查询资料,丰富程序设计知识,提高深深学习能力。在个人自主学习的基础上进行小组讨论与交流,在交流中不仅扩展知识与视野,而且能培养团队协作精神,增进同学之间的感情。导师还要积极引导学生发现规律,找到自己的不足,积极改正,不断超越自我。
3.3项目驱动教学模式中的成绩评定
成绩评定是项目驱动模式教学的重要组成部分,成绩评定一般具有激励、引导和反馈的作用,能够全面反映学生的近况。成绩评定比较重视学生在学习过程中能否解决实际问题,旨在培养学生动手操作的能力和创新能力以及计算机素养,树立科学精神和坚韧不拔的性格以及积极向上的人生观。如果学生成绩提高,教师要给予鼓励和表扬,激励学生再接再厉。成绩评定的方式采用项目答辩的形式进行,每个小组派出一个代表作主辩手,其他学生补充,导师可以随时提问,最后结合项目答辩情况给出学生最终考核成绩。
4结语