绪论:写作既是个人情感的抒发,也是对学术真理的探索,欢迎阅读由发表云整理的11篇驱动程序设计范文,希望它们能为您的写作提供参考和启发。
中图分类号:TP316文献标识码:A文章编号:1009-3044(2011)22-5418-02
Design of USB Device Drver Program on linux
SUN Yong-gang, JIAO Li-fei
(College of Science, GuiZhou University, Guiyang 550025, China)
Abstract:USB interface, with its efficient, reliable and widely is used in various embedded products. However, existing data on linux operating system, more studies USB Host, USB Device driver rarely is done. Therefore this paperthrough a simpleintroduction of USB protocol, as well as analysis of USB driver architecture about linux, is about an design of USB Device driver of linux systemfor embedded microprocessor S3C2440 .
Key words: USB agreement; linux driver;USB device driver
嵌入式产品通过的USB接口品可以很方便与PC的USB进行通信以完成数据的传输与交互。ARM嵌入式处理器性以其性能高、功耗低而被广泛地应用于消费电子、工业控制等众多领域。以ARM内核为核心集成了USB功能的处理器使得产品更简洁、更灵活、更方便。S3C2440集成了ARM920T内核,带MMU功能,可运行linux操作系统,同时带有两个USB Host一个USB Device控制器,因此在此基础上完成Linux 下的USB Device驱动程序有着重要的意义。本文是以此处理器为核心的嵌入式智能终端的Linux下的USB Device驱动程序设计。
1 USB体系结构及协议
1.1 USB硬件系统结构
USB接口是由+5V电源线、电源地线、信号线D+、信号线D-四根电缆线组成接口。其中+5V电源是向设备提供电源,信号线作用是传输数据, 为了提高信号传输的抗干扰能力这两根数据线采用差分传输。主机可以通过D+和D-线的电平高低来确设备是高速设备还是全速设备。
1.2 USB数据传输通道
USB主机与USB设备由很多端点构成,它们之间通过端点进行通讯。通过设置与些端点相对应的寄存器,可以为这些端点分配唯一的地址(由端点号和传输方向组成)。USB总线支持四种传输类型,他们分别是控制传输、同步传输、中断传输、批量传输。端点O只支持控制传输。
1.3 USB总线枚举
USB总线枚举就是当USB设备连接到USB主机时,主机通过缺省管道以控制传输方式来获取USB设备发来的设备描述符、配置描述符、接口描述符、端点描述符信息,并根据这些描述相关内容对USB设备进行相应的配置。
2 Linux USB 驱动程序
在Linux系统中,USB驱动程序可以分为USB Host驱动程序和USB Device驱动程序。Linux USB Host驱动程序和USB Device驱动程序总体架构如图1所示。
从图1可以知,在Linux USB Host中,USB控制器驱动是运行在USB 控制器硬件上面的的驱动动程序。该驱动实现了对USB 控制器硬件进行控制,一般称为USB固件驱动程序。USB设备驱动处于USB驱动的最顶层,它主要实现USB设备如何与主机进行通信。处在USB主机控制器驱动与USB设备驱动之间的是USB核心层,起到驱动程序桥梁的作用,该核心层为USB主机USB主机控制器驱动提供编程接口。
Linux系统中, USB Device驱动分为UDC驱动、Gadget API、Gadget驱动三个层次结构。UDC驱动处USB Device控制器硬件之上,该驱动程序控制USB控制器硬件工作,同时向上层提供操作USB控制器硬件的回调函数。处在中间层的是Gadget API层,该API向下层和上层提供统一的编程接函数的封装。Gadget驱动程序完成设备功能的实现。通过编写不同Gadget驱动程序可以使设备具有不同的功能。
3 S3C2440 USB Device驱动
3.1 S3C2440 USB接口特性
S3C2440嵌入式微处理器集成了一个设备控制器。该设备控制器具有以下特征:
1) 完全兼容USB1.1的协议。设备全速运行时可达到了12Mb/s。
2) 支持控制、中断和批量传输,批量传输支持DMA接口。
3) 自带5个的端点。端点EP0带有16byte的FIFO,该端点为双向的控制端点,其余4个端点都带有128字节输入/输出的FIFO(异步双端口RAM)的,支持中断或DMA批量传输。
3.2 S3C2440 USB Device驱动程序设计
一个完整的S3C2440 USB Device驱动程序由S3C2440_UDA驱动和gadget驱动两部分构成。S3C2440_UDA驱动是用来控制S3C2440的USB Device硬件控制器器,并把对硬件控制操作抽象为函数接口供上层调用。USB gedget驱动程序运行在S3C2440_UDA驱动程序之上的,不同的gedget驱动程序使该设备具有不同的功能。
Linux gadget驱动程序主要涉及到2个重要的结构体usb_gadget_driver和struct file_operations结构。其中usb_gadget_driver结构体包括bind、setup、disconnect等一些函数。Linux Gadget提供usb_gadget_register_driver函数对Gaget驱动进行注册。当Gadget驱动被注册后,Linux内核就会调用结构体usb_gadget_driver中的bind函数把Gadget驱动与UDA驱动进行绑定,这样就可以在Gadget驱动中使用UDA提供的统一接口函数。
bind函数中需要完成以下工作:
1) 使用usb_ep_autoconfig函数申请以后用到的传输端点。
2) 通过usb_ep_alloc_request函数为Gadget驱动分配一个请求。
3) 通过调用register_chrdev_region注册设备驱动程序。
Bind函数完成这后当有USB Host 向USB设备发出请求时,Linux系统将调用setup函数来响应请求。Setup函数把设备的设备描述符、配置描述符、接口描述符以及以后需要使用的几个端点描述符发送给USB Host,这些配置信息的发送都是通过usb_ep_queue函数来完的。
struct file_operations结构包含有open、read、write等函数。通过该结构体定义的变量被register_chrdev_region函数注册后该设备就可以像字符设备那样使有了。该结构中的一些函数完成的功能如下:
1) open函数通过init_waitqueue_head完成等待队列初始化。
2) read函数通过alloc_ep_req函数分配一个读请求变量,并为该变量中的complete设置一个请求完成函数,调用usb_ep_queue函数向端点提交I/O读请求。当内核从USB Device读到数据时就会调有刚才的完成函数。在完成读数据之前可以通过add_wait_queue和schedule()函数让进程挂起,在完成函数中唤醒挂起的进程。
3) write函数通过alloc_ep_req函数分配一个写请求变量,并为该变量中的complete设置一个请求,调用usb_ep_queue函数向端点提交I/O写请求。当内核向USB Device写完数据时就会调有刚才的完成函数。在完成写数据之前可以通过add_wait_queue和chedule()函数让进程挂起,在完成函数中唤醒挂起的进程。
至此整个驱动程序就设计完成了,图2为USB Host 与 USB Device 通信测试效果。
4 结束语
USB Device 为众多电子产品提供了一个与PC信息交互的更好的方案。本文通过对USB协议介绍,以及对Linux下USB驱动程序进行分析,在此基础上实现了USB Device驱动程序进行设计。实践表明该设计是可行的。
参考文献:
[1] 冯国进.嵌入式Linux驱动程序设计从入门到精通[M]北京:清华大学出版社,2008.
[2] 薛园园.USB应用开发技术大全[M].北京:人民邮电出版社,2007.
[3] 刘少峰,韦克平.USB软件系统的开发[J].计算机应用研究,2002,19(30).
中图分类号: TN964?34 文献标识码: A 文章编号: 1004?373X(2013)18?0051?04
0 引 言
设备互联(PCI)总线是一种先进的高性能局部总线,可同时支持多组设备[1]。CPCI总线应用于工业和嵌入式领域,其规范改进自PCI规范,CPCI规范在电气方面兼容PCI规范,只是在封装结构上进行了加强,CPCI板的封装结构基于IEC 60297?3,IEC 60297?4以及IEEE 1101.10定义的欧式板卡外形[2]。既然电气特性上兼容PCI规范,因此CPCI驱动程序的设计本质就是PCI驱动程序设计。
当前Windows环境下用于PCI设备驱动开发的工具主要是DDK,DriverStudio以及WinDriver。前两者功能强大,但是开发者需要熟知操作系统的体系结构、汇编语言和设备驱动程序结构体系方法,还需要具备丰富的驱动程序开发经验,否则可能造成软件不稳定甚至系统崩溃,另外前两者开发周期长。而Jungo公司开发的WinDriver改变了传统的驱动程序开发方法,其整个驱动程序中的所有函数都是工作在用户态下,使开发者不需要掌握前两者所需的预备知识就可以开发出与之相媲美的程序[3]。
为了实现在主控计算机和信号处理板之间快速通信,采用了CPCI并行总线技术,信号处理板采用内嵌PCI模块的DSP6416芯片。软件开发基于Windows平台和VC++6.0编程环境,为了便于应用程序调用驱动程序,按照模块化的软件设计思想,驱动程序以DLL动态链接库的形式封装。为提高工作效率、缩短开发周期,开发工具选用WinDriver。
1 WinDriver简介
WinDriver是一套设备驱动程序开发组件,它的目的就是方便程序员快速开发出PCI,ISA,CPCI,PCIE等设备的Windows驱动程序[4]。
1.1 WinDriver原理
WinDriver的体系架构分为两种模式:用户模式和内核模式。对硬件进行操作时,开发者应用程序调用WinDriver用户模式的库函数,用户模式的库函数再调用WinDriver内核,WinDriver内核再调用操作系统底层函数实现对硬件的最终访问。其与硬件模板、用户驱动程序、用户应用程序之间的关系即体系架构见图1[5?6]。对于某些在用户模式下不能实现的高性能硬件驱动程序,可通过WinDriver的内核插件功能实现:在用户模式下完成编程和调试,不做任何修改,直接将该高性能要求的程序模块植入内核插件,WinDriver即从内核模式下调用该程序模块。
1.2 WinDriver特点
作为一款实用的驱动程序开发工具包,WinDriver的主要优点和特征如下:
(1)通过内核插件功能(Kernel PlugIn)能够实现用户模式的易用和内核模式的高性能;
(2)友好的驱动向导允许不写一行代码即可实现硬件诊断;
(3)支持所有PCI/PCMCIA/CardBus/ISA/EISA/CompactPCI/PCIExpress设备,与制造商无关;
(4)可以利用常见的软件开发平台包括MSDEV/VisualC/C++,Borland Delphi,Visual Basic6.0等;
(5)开发者不需要知道DDK,ETK,DDI及任何其他系统层面的编程知识;
(6)支持I/O、DMA中断处理和直接访问板卡映射的存储器;
(7)支持多CPU及多PCI总线平台。
1.3 用WinDriver开发驱动程序
利用WinDriver开发驱动程序有2种方式:通过驱动程序向导生成驱动程序框架,再对框架程序进行修改和调试;直接编写驱动程序。
通过驱动程序向导开发步骤:板卡检测、诊断;生成驱动程序框架;调试、编译驱动程序。
直接编写代码方式步骤:
(1)包含WinDriver相关的头文件;
(2)WinDriver库函数调用,WinDriver库函数典型调用流程见图2[7]。
2 CPCI信号处理板卡驱动程序设计
2.1 硬件环境
实现PCI总线协议一般有2种方法:一是用FPGA设计实现,由于PCI协议比较复杂,实现较困难;二是采用专业PCI总线控制芯片,如AMCC公司的S5933、PLX公司的PCI 9080等通用PCI接口芯片[8]。本信号处理板采用第二种方法,选用自带PCI接口模块的DSP6416,主控计算机上的应用程序通过驱动程序将控制命令字主动写入DSP内存,实现主控计算机对信号处理板的控制;信号处理板结果数据处理完毕后,向主控计算机发中断,驱动程序响应该中断,并主动读取指定DSP内存获取结果数据。
结果数据和模块状态信息存入L2缓存单元,主控计算机下发的命令字也写入L2缓存单元。结果数据缓存划分为大小各为28 KB的Block1和Block2两块区域;模块状态信息缓存大小为24字节;控制命令缓存大小为1 B。DSP中与PCI操作有关的缓存定义见表1。
表1 DSP中与PCI操作有关的缓存定义
当Block1缓存填满后,新的结果数据存入Block2缓存,同时DSP给主控计算机发PCI中断,主控计算机通过PCI接口读取Block1;同理当Block2填满后,新的结果数据存入Block1缓存,主控计算机通过PCI读取Block2。Block1和Block2缓存交替接收结果数据。
2.2 CPCI驱动程序DLL接口设计
为了便于应用程序访问驱动程序,按照模块化的软件设计思想,驱动程序以DLL动态链接库的形式进行封装,应用程序通过与驱动程序DLL之间的接口来访问信号处理模块的板上资源,下发控制命令、获取结果数据。主要接口及其功能描述如下:
(1)DSP6416DLL_Init(CWnd* pMainWnd):打开并注册WDC库、打开设备,初始化中断;
(2)DSP6416DLL_SendCmd(BYTE BCommand):主控计算机中的控制命令数据写入DSP中命令存储区;
(3)DSP6416DLL_ReadState(BYTE *StateData):从DSP的状态存储区读取信号处理板的状态数据;
(4)DSP6416DLL_ReadResult(BYTE *ResultData):从DSP的Block1或Block2数据缓存区读取结果数据;
(5)DSP6416DLL_Exit():关闭中断,关闭设备,关闭WDC库。
2.3 CPCI驱动程序实现
在硬件环境和接口、驱动程序封装形式及其软件接口确定后,剩下的工作就是CPCI驱动程序的实现。该工作主要内容为驱动程序DLL各接口函数的编码实现和WinDriver库函数调用。
2.3.1 文件包含
包含与WinDriver相关的头文件:windrvr.h,windrvr_int_thread.h,wdc_lib.h。
2.3.2 驱动程序初始化
驱动程序初始化主要工作和步骤包括:打开WinDriver,WinDriver授权、版本号检查、板卡检测、板卡信息获取、模块配置、板卡注册和PCI中断使能,驱动程序初始化流程见图3。
2.3.3 驱动程序向DSP内存写数据
DSP6416的PCI接口支持四种类型的数据交换[9?10]:从模式写,外部PCI主设备通过PCI接口写数据到DSP;从模式读,外部PCI主设备通过PCI接口读取DSP中的数据;主模式写,DSP主设备通过PCI接口向外部设备写数据;主模式读,DSP主设备通过PCI接口向外部设备读数据。
4 结 语
通过实际应用,发现用WinDriver开发的本驱动程序运行稳定可靠,达到了主控计算机对信号处理板实时控制,特别是信号处理板中大容量数据实时上传的目的。由于系统方案确定了CPCI并行总线作为通信手段,硬件设计时采用了自带主从式PCI接口模块的DSP6416芯片,驱动开发工具选择了快速高效的WinDriver工具包,以及对驱动程序形态进行DLL封装,本驱动程序从需求设计到完成编码和调试不到一个月的时间,在保证软件质量的同时,缩短了研制周期,提高了开发效率。
参考文献
[1] 李贵山,戚德虎.PCI局部总线开发者指南[M].西安:西安电子科技大学出版社,1997.
[2] PICMG. Compact PCI core specification PICMG 2.0 R3.0 [R]. [S.l.]: PICMG, 1999.
[3] 王磊,鲁新平,李吉成.WinDriver在开发基于PLX9056芯片的PCI设备驱动程序中的应用[J].现代电子技术,2006,29(18):77?79.
[4] 李静,赵保军.基于TMS320C6416内嵌PCI设备驱动程序开发[J].微机发展,2005,15(10):135?137.
[5] Jungo Ltd. WinDriver PCI/ISA/CardBus v8.02 user’s guide [R]. US: Jungo Ltd, 2005.
[6] 简育华.基于WinDriver的 PCI驱动程序开发[J].火控雷达技术,2011,40(1):68?70.
[7] Jungo Ltd. WinDriver PCI/PCMCIA/ISA v8.02 Low?Level API Reference[R]. US: Jungo Ltd, 2005.
近年来电力行业为了快速部署变电站,采用了建造整体变电所的方法:在生产基地将变电站的内部设备安装、调试完成,只留下与外界的接口,整体运到变电站所在地后进行安装和简单调试即可投入运行。其内部设备通过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来实现的,这样将功能集中的五个函数更方便了用户使用。
中图分类号:TP311.52
文献标识码:B
文章编号:1004―373X(2008)04―063―03
开发驱动程序的软件主要有:MicroSoft公司的DDK,Jungo公司的Windriver和Compuware NuMega公司的Driver Studio三种。DDK是最基本的驱动程序开发工具,比较复杂,适于专业的驱动程序开发人员,不适于硬件开发人员开发驱动程序。Windriver开发驱动程序不需要熟悉操作系统内核知识,针对硬件PCI/ISA/PCM―CIA/USB开发驱动程序比较方便,但驱动程序的效率不高、缺乏灵活性。Driver Studio把DDK用类的形式进行封装,简化设备驱动程序的开发,方便又不失灵活性。所以这里选择Driver Studio作为驱动程序的开发工具。
在结合PCM高速遥测数据发送卡的基础上,本文介绍WDM驱动程序的结构特点和PCM高速遥测数据发送卡的硬件结构,并阐述针对数据发送卡的特点,详细地讨论驱动程序关键部分的设计。
1 PCM遥测数据发送卡的硬件结构
图1为遥测数据发送卡的原理框图。码型变换器的功能是根据原始PCM数据产生3种输出码型:NRZ―L,NRZ―M及NRZ―S之一,以适应更加广泛的测试目的。多电平驱动器将来自FPGA的LV TTL电平的PCM数据和时钟信号转换为3种电平接口输出,分别是TTL,EIA422及MLVDS。同步FIFO作为硬件数据帧缓存存储由PCI总线写入的数据帧,然后由序列生成器读出。序列生成器根据PCM时钟速率产生串行移出的PCM原始数据将来自FIFO的32位并行数据转换为串行输出,同时根据移位寄存器的状态产生发向FIFO的读数请求:
2 WDM驱动程序的结构及特点
WDM(Windows Driver Model)是在原有的NT内核模式驱动程序的基础上发展来的,他增加了PnP(Plugand Play)、电源管理、WMI(Windows Management Instru―mentation)等功能。WDM模型的层次结构如图2所示。
层次结构可以使I/O请求过程更加清晰。影响设备的每一个操作都使用I/O请求包(IRP),通常IRP被送到设备堆栈的最上层,然后逐渐过滤到下层驱动程序。每处理1个IRP,I/O管理器就调用1次StartIO例程,从而着手IRP处理工作;如何处理完全取决于具体的设备,调用驱动程序中相应的例程。驱动程序处理完IRP后,会将结果返回给I/O管理器,再由I/O管理器返回给用户应用程序。
3 PCM遥测数据发送卡WDM驱动程序的设计
在设备的驱动程序设计中,需要处理PCI设备的硬件读写、中断处理、DMA等功能。可以把驱动程序视为一个框架和若干例程的结合体,各个例程处理不同的IRP,而框架负责在IRP到来时调用相应的例程。利用Driver―Works的驱动程序向导(Driver Wizard)新建一个PCI设备驱动程序框架,然后在这个框架基础上添加必要的实现功能的处理代码,就可以完成整个驱动程序的设计。下面以PCM遥测数据发送卡为例讨论其主要的功能驱动程序例程的实现。
3.1硬件初始化例程
OnStartDevice(KIrp I)参数例程中包含2种系统分配的资源配置信息:原始的资源配置信息(AllocatedRe―sources);转换后的资源配置信息(AllocatedResourcesTranslated)。因为I/O总线和CPU在寻址物理硬件的方式不同,所以存在2种资源列表。从注册表、PCI配置空间和其他地方获取原始的资源值和转换这些值的操作全部由PnP管理器完成,WDM驱动程序需要做的仅是从设备启动IRP中获取这些资源。
3.2 中断服务例程
中断服务例程运行在DIRQL级别上,需要尽可能快地运行。本设计在中断服务例程中,首先判断中断是否自己设备产生的,如果是,则调用一个在DISPATCH_LEV―EL级别上运行的延迟过程调用(DPC)。当中断服务例程完成后,一旦处理器获得DISPATH_LEVEI。运行权,就会运行DPC。中断服务例程流程图如3所示。
3.3 中断延迟调用例程
在延迟调用例程中,判断中断原因如果是DMA中断就启动DMA继续发送。如果是发送通道中断,则判断通道号,并把相应软件FIFO里面的待发送数据传送到硬件FIFO里。在此过程中需要检查在将软件FIFO中的数据写入硬件FIFO中后,如果软件FIFO已被读空,则应禁止通道中断,否则通道中断因为优先级高,会一直于有效状态,导致系统死锁。而在用户程序写软件FIFO的处理函数中,检查通道中断,如果被禁止,则应将新写入软件FIFO的数据读取一部分写入硬件FIFO中,然后开启通道中断。
3.4应用程序与驱动程序的通信例程
DeviceControl(KIrp I)主要用于应用程序与驱动程序之间的通信,如向硬件读写数据以及软件FIFO的操作等。DevcieControl响应用户应用程序DeviceloControl()发送的IRP,根据IOCTL代码来判断调用子处理函数PCI_9054_IOCTL_READ_Handler(I),PCI_9054_IOCTL_WRITE_Handler(I).DEV_IOCTL_TXI_FIFO_WRITE_Handler(I)分别完成对硬件的读写和软件FIFO的写操作。
3.5 DMA传输操作
硬件FIFO半满时产生通道中断,在DPC里,判断是通道中断,则初始化KDmaTransfer,然后调用OnD-maReady();在OnDmaReady()中启动首次DMA传输,传输时发生中断,在DPC中判断是否DMA中断,如果是,则调用Continue()再次启动下次传输,至此全总数据传输完成。其流程图如图4所示。
4 驱动程序编译、调试和安装
当驱动程序编写完成后,必须在DDK环境下进行编译,执行Rebuild aIl命令,编译完成后生成*.sys文件和*.inf文件。调试工具使用Softlce,基本过程如下:
(1)使用Symbol Loader加载驱动程序*.nms文件,然后激活Softlee,设置断点跟踪调试;
(2)用Genint命令产生虚拟中断测试,中断服务例程;
1 WDM模式驱动程序
1.1 WDM模式(Windows Driver Model)
Windows2000对驱动程序的编写不再基于以往的Win3.x和Win9x下的VxD(虚拟设备驱动程序)结构,而是基于一种新的驱动模型——WDM(Windows Driver Model)。
WDM为Windows98/2000/XP操作系统的设备驱动程序的设计提供了统一的框架。WDM来源于Windows NT的分层32位设备驱动程序模型(layered 32-bit device driver model)。它支持更多的特性,如即插即用(PnP)、电源管理、WMI和NT事件。
1.2 设备驱动程序
设备驱动程序是操作系统的一个组成部分,它由I/O管理器(I/O Manager)管理和调动。Windows2000操作系统下的I/O管理器功能描述如图1所示。
I/O管理器每收到一个来自用户应用程序的请求就创建一个I/O请求包(IRP)的数据结构,并将其作为参数传递给驱动程序。驱动程序通过识别IRP中的物理设备对象(PDO)来区别是发送给哪一个设备。IRP结构中存放请求的类型、用户缓冲区的首地址、用户请求数据的长度等信息。驱动程序处理完这个请求后,在该结构中填入处理结果的有关信息,调用IoCompleteRequest将其返回给 I/O管理器,用户应用程序的请求随即返回。访问硬件时,驱动程序通过调用硬件抽象层的函数实现。
1.3 DriverStudio工具简介
NuMega Lab公司开发的DriverStudio是一整套开发、调试和检测Windows平台下设备驱动程序的工具软件包。它把DDK(Device Development Kit)封装成完整的C++函数库,根据具体硬件通过向导生成框架代码,并且提供了一套完整的调试和性能测试工具SoftICE、DriverMonitor等。
2 应用实例
本文利用PCI专用接口芯片PCI9052设计了一个数据传输控制卡。卡上主要的芯片有PCI9052、FIFO(CY7C4221)、CPLD(MAX7064S)和A/D转换器(MAX1197)。传输卡硬件框图如图2所示。面阵CCD得到的视频信号经过调理电路,生成的视频调理信号通过A/D转换器进行数字化处理,送入FIFO中。在CPLD的控制下,数据经过PCI9052送入PCI总线,再传送到计算机内存中,并显示在监视器上。驱动程序必须实现如下几个基本功能:(1)硬件中断;(2)能支持应用程序获取数据;(3)能根据外部FIFO(CY7C4221)的状态启动或停止突发传输。
在数据输入过程中,最重要的是对数据进行实时控制,因此需要硬件中断。在中断程序中,根据外部FIFO状态完成数据的读入。
2.1 用DriverWizard生成驱动程序框架
DriverStudio中的DriverWorks软件为开发WDM程序提供了一个完整的框架。它包含一个可快速生成WDM驱动程序框架的代码生成向导工具DriverWizard,而且还带有许多类库。在用DriverWizard生成的程序框架中写入相对于设备的特定代码,编译后即可得到所需的驱动程序。
在利用DriverWorks V2.7的向导Driver Wizard完成驱动程序的框架时共有11个步骤,其中关键步骤有:
(1)在第四步中选中PCI,并在VendorID和DeviceID中分别输入厂商号和设备号,还需填入PCI Subsystem ID和PCI Revision ID。这四项可以用网上的免费软件PCITree或PCIView浏览PCI设备,用这两个软件也可以得到BAR0~BAR5的资源分配情况和中断号。
(2)第七步IRP队列排队方法,它决定了驱动程序检查设备的方式。本设计选SystemManaged,则所有的IRP排队都由系统(即I/O管理器)完成。
(3)第九步是最关键的一步。首先在Resources中添加资源,在name中输入变量名,在PCI Base Address中输入0~5的序列号。0~5和BAR0~BAR5一一对应。在设置中断对话框中,在name栏写入中断服务程序的名称,选中创建中断服务程序ISR?穴Create ISR?雪,不选创建延迟程序调用DPC(Create DPC),选中Make ISR/DPC class functions,使ISR/DPC成为设备类的成员函数。
其次选中Buffer以选取读写方式,用于描述与I/O操作相关的数据缓冲区。本设计需要快速传送大量数据,因此采用Direct I/O方式。
(4)在第十步中,需要加入与应用程序或者其他驱动程序通信的I/O控制代码参量。
2.2 驱动程序模块框图和代码分布
PCI设备驱动程序模块包括配置空间的访问模块、IO端口模块、内存读写模块和终端模块等。各模块之间是对等的。驱动程序模块框图如图3所示。
驱动程序初始化模块代码段放在#pragma code_seg(″INT″)和#pragma code_seg()之间。在系统初始化完成后,这部分代码从内存中释放,防止占用系统宝贵的内存资源。#pragma code_seg()之后是驱动程序和系统的许多模块的实现部分。这部分在驱动程序运行后不会从内存中释放。
2.3 驱动程序主要模块的实现
(1)配置空间的访问模块
DriverWorks的KPciConfiguration类封装了访问PCI设备配置空间的所有操作。首先初始化这个类的实例:
KpciConfiguration PciConfig()m_Lower.TopOfStack());
/?觹m_Lower是 KpnpLowerDevice类的对象。m_LowerTopOfStack()返回当前设备堆栈顶部的设备对象。*/
初始化完后可以直接利用成员函数 ReadHeader/ WriteHeader函数访问所有的配置寄存器。
为了确定映射空间的类型和大小,先向目标基地址寄存器写入0Xffffffffh,然后回读该寄存器的值。如果最低位为1,表示映射于I/O空间,反之为存储空间;如果映射于存储空间,从第四位开始计算0的个数可以确定内存空间的大小;如果是I/O方式,从第二位开始计算0的个数可确定I/O空间的大小,最大为256字节。如果设备的存储空间超过256字节,要实现设备的整个存储部分的访问,就必须采用内存映射。
(2)I/O操作模块
Driverworks的KIoRange类封装了I/O端口访问的操作。部分代码如下:
{……
KIORange DevIoPort () ;//创建实例
NTSTATUS status= DevIoPort ().Initialize ( pResListTranslated,pResListRaW,PciConfig.BaseAddressIndexToOrdinal(0));
/* 第一个参数为转换后的资源列表指针;第二个参数为原始资源列表指针;第三个参数中的0为 I/O口对应的基地址,用来转换成特定端口资源的序数?*/
If(NT _SUCCESS(status))
{……
DevIoPort.inb(0,LineBuf1,10);
/*成功初始化后可分别用KIoRange类的成员函数inb(/outb)从端口中读/写字节 */
}
else{Invalidate();return status;
/*未能初始化成功,错误信息在status中*/
{
……}
(3)内存读写模块
DriverWorks的 KMemoryRange类封装了端口访问的操作。
status=m_MemoryRange().Initialize(pResListTranslated,pResListRaw, PciConfig.BaseAddressIndexToOrdinal(0));
此函数的参数、意义及具体用法与I/O端口的操作基本相同。
内存对象也用来发送控制字,以控制CPLD的开始和停止等。实际上控制字是通过PCI9052发送的。该控制字地址已被映射成PCI的内存空间。所以定义一个指向内存空间的内存对象,通过该对象即可发送控制字。
(4)中断模块
在中断模块,首先要激活PCI9052中断使能位,然后判断硬件中断响应是否产生,如果有,则进行突发传输,读入FIFO中的数据。
BOOLEAN TranCard::Isr_MyIrq(void)
{ if (// 中断未产生)
{……
return FALSE;}
else
{/* 如果产生硬件中断,设置命令寄存器,进行突发数据传输 */
return TRUE;}
}
为了将硬件中断与编写的中断服务程序连接在一起,采用InitializeAndConnect方法,部分代码如下:
NTSTATUS TranCardDevice?押?押OnStartDevice(KIrp I )
{……
status=m_MyIrq. InitializeAndConnect(
pResListTranlated,
LinkTo(Isr_MyIrq),
This;)
……}
2.4 驱动程序的调用
编写驱动程序本身不是最终目的,最终目的是调用驱动程序管理资源,并为用户应用程序使用。驱动程序加载以后,它的许多进程处于Idle状态,实际上需要用户应用程序去调用激活。应用程序利用Win32 API直接调用驱动程序,实现驱动程序和应用程序的信息交互。
首先用CreateFile()打开设备,获得一个指向设备对象的句柄。使用CreateFile函数时应注意:由于驱动程序是*.sys,所以第一个参数应该是这个设备对象的标志连接(symbolic link)。该标志连接名有一个设置数据文件搜索路径的数字号,而这个数字号通常是零。如果这个连接名是″TranCard″,则传递给CreateFile的宇符串就是:″\\\\.\\ TranCard0″。例如:
HANDLE hDevice=CreateFile(″\\\\.\\TranCard0″)GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ, NULL?, OPEN_EXISTING,0,NULL);
然后用 DeviceIoControl()进行数据的传送。最后用CloseHandle( )关闭设备句柄。
下面是应用DeviceIoControl()程序片段。
{……
m_b=DeviceIoControl(hDevice,TRANCARD_IOCTL_
RECEIVE(buffer, sizeof,buffer, NULL,0,&buffersize,NULL);
……}
2.5 驱动程序的调试
中图分类号: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.
1 PC/104-CAN适配卡的硬件结构
PC/104-CAN适配卡主要由CAN控制器(SJA1000)、光电隔离(6N137),收发驱动器(82C250)及译码电路组成。编程主要了解的是控制器SJA1000。CAN适配卡原理如图1所示。
2 CAN地址译码和中断选择
系统104主板的CPU为486DX,其对接口板访问有两种方式:内存映射和I/O访问。I/O寻址采用专门的指令,每次只能传送单个字节。内存映射方式可以访问较大的地址空间并且指令丰富,便于实现快速交换数据。本文讨论的CAN卡采用存映射模式工作,与486DX接口是104总线,它与ISA总线兼容。对于Intel X86体系的CPU,ISA可以映射的空间为0xC8000~0xEFFFF。使用比较器和地址选择开关组成可选端口地址译码电路,通过开关选通内存映射基地址(C8000H、C9000H、CA000H、…、EF000H),以避免与其它器件冲突。CAN偏移地址分配如下:
00~FFH SJA1000的寄存器;
100H~1FFH 对该范围内的任意地址进行写操作,均可导致CAN硬件复位。
SJA1000的INT引脚通过跳线选择IRQ3~7、IRQ9~12或IRQ15中的一个,避免与其它的适配卡冲突。
3 PC/104-CAN适配卡驱动实现
3.1 VxWorks驱动概述
VxWorks操作系统有两种方式实现驱动。第一种方式是,把设备驱动程序作为独立任务实现,直接在顶层任务中实现硬件操作,完成特有专用的驱动程序。第二种方式是,VxWorks的I/O系统将设备程序作为内核过程实现。这种方式便于实现I/O子系统的层次模型,便于文件系统一起把设备作为特殊文件处理,提供统一的管理、统一的界面和统一的使用方法,并把设备、文件及网络通信组织成为一致的更高层次的抽象,为用户提供统一的系统服务和用户接口。我们和这种驱动方式。
作为I/O系统和硬件设备之间的连接层,VxWorks驱动就是屏蔽硬件操作,为I/O系统提供服务。实现一个完整的驱动,必须了解VxWorks下I/O的三个基本元素:File、Driver和Dervice。File是为用户提供访问设备的统一接口;Driver是实现具体的基本控制函数,也就是实现I/O系统所需要的接口;而Device则是一个抽象的硬件设备,是一系列的结构体、变量和宏定义对实际物理设备的定义。一般而言,实现一个驱动应该有三个基本的步骤:①用编程语言完成对实际物理设备的抽象;②完成系统所需要的各类接口及自身的特殊接口;③将驱动集成到操作系统中。之后还有一些调试工作。
3.2 VxWorks I/O系统驱动程序框架
VxWorks为各种设备(包括字符设备、块设备、虚拟设备及网络设备)提供统一的访问接口,包括七种基本的I/O函数:open(filename、flags、mode),create(filename、flags),read(fd、&buf、nBytes),write(fd、&buf、nBytes),ioctl(fd、command、arg),close(fd)及remove(filename)。I/O系统所起的作用就是,把用户请求分配到与设备对应的驱动例程中去。VxWorks系统中有一个驱动程序列表,其形式如表1所列。
表1 设备驱动列表(调试时可利用iosDrvShow()查看)
驱动号码createremoveopenclosereadwriteioctl1
2ca OpenNULLca Openca Closeca Readca Writeca IoctlI/O系统的可动态调用iosDrvInstall()函数将设备的驱动例程(即XXOpen()、XXClose()、XXRead()等)加入到设备驱动列表中,如图2所示。
同样,系统中有一个设备列表,每个设备对应于设备列表中的一项,每一项包括设备名称和设备驱动号,同时包括一个设备描述的结构。该结构第一个变量是DEV_HDR类型的变量DEV_HDR。
DEV_HDR的定义如下:
Typedef struct
{
DL_NODE node; /*设备列表节点*/
short drvNum; /*驱动号码*/
char *name; /*设备名*/
}DEV_HDR;
系统调用iosDevAdd(),可以将设备加入到设备列表中。系统中将驱动和设备联系起来的就是文件描述符列表,每个文件描述符列表除了包括驱动号、设备ID外,还包括文件名、可用标志和指向DEV_HDR的指针。系统每次成功执行open(),返回一个文件描述符,这样对于设备的read()、write()及ioctl()就可以通过文件描述符进行。
文件描述符表(调试时调用iosFdShow()查看)如下:
I/O系统的整体结构如图3所示。系统启动时(一般挂接在usrroot()),XXDrv()和XXDevCreade()便将设备及其驱动加入相应的列表中。
3.3 设备驱动程序的访问过程
下面以CAN驱动程序为例,说明驱动程序的访问过程。(假定设备名“/can/1”并且以CAN设备驱动程序为例,上述中的XX在这里用Can代替。)
①fd=open(“/can/1”,O_RDWR,0644)
②I/O系统在设备列表中寻找设备名为/can/1的设备项,找到相应的设备驱动号。
③I/O系统在文件描述符中保留一个文件描述符空间。
④I/O系统在设备驱动列表中找到对应的CanOpen(CAN_DEV*PCAN_DEV,UBYTE*remainder,int flags),该驱动例程返回设备描述符的指针。
⑤I/O系统将设备描述符的指针存储在文件描述符列表的Device ID,同时将对应的设备驱动号存储在文件描述符的Driver num项。最后I/O系统返回该描述符项的索引(即为fd)。
⑥这样应用程序中的read()和write()等函数调用就可以根据fd找到相应的设备驱动号,进而找到相应的驱动例程。
4 CAN驱动程序的实现
CAN驱动程序的实现即是完成下面七个函数的编写。下面简要介绍其完成的功能,并用伪指令进行说明。
int drv_num; ;/*驱动号码*/
typedef struct {
DEV_HDR pCANHDR; /*这个数据结构必须放在设备描述符的最初部分*/
/*其余与驱动有关数据*/
}CAN_DEV; /*CAN设备描述符*/
CAN_DEV can_chan_dev;
STATUS CanDrv(void){
完成驱动的一些初始化;
intconnect(); /*连接所选的IRQ与中断处理函数*/
sysIntEnablePIC(); /*486DX允许中断*/
drv_num=iosDrvInstall(CanOpen,NULL,CanOpen,CanClose,CanRead,CanWrite,CanIoctl);/*将设备驱动例程装入设备列表中*/
}
/*iosDrvInstall()将设备的CAN驱动例程加入设备驱动列表中,7个参数为7个驱动例程的进入点(entry point),如果没有某个例程,则传递NULL。*/
STATUS CanDevCreate(){
完成一些设备初始化
iosDevAdd (&Can_chan_dev.pCANHDR,“can0”,drv_num);/*将设备放入设备驱动列表中*/
}
int CanOpen(CAN_DEV *pCan_Dev,UBYTE *remainder,int flags){
CAN卡硬件复位
CAN卡关中断
CAN卡进入软件复位模式
设置CAN卡工作寄存器,如接收码寄存器和屏蔽码寄存器等
CAN卡开中断和进入操作模式
Return((int)pCan_Dev); /*注意必须返回设备描述结构指针*/
}
int CanRead(int CAN_DEV_ID,UBYTE * buf,int nBytes){
等待信号量(该信号量由中断处理例程释放)
从接收缓冲区读取数据
释放接收缓冲
返回接收数据数量
}
int CanWrite(int CAN_DEV_ID,UBYTE* buf,int nbyte){
查询发送缓冲是否可用
向发送缓冲区写数据
命令发送
查询发送完成标志
返回发送数据数量
}
void interrupt_handle_routin(int arg){
处理中断事件
发送(释放)信号量
}
限于篇幅,其它函数略。
图3 I/O系统整体结构
5 CAN驱动调试
硬件驱动的调试是件十分麻烦的事,经验十分重要。这里简要介绍几个帮助调试的函数。
①可以调用iosDrvShow()、iosDevShow()及iosFdShow()查看相关内容,判断并将驱动及设备中入相应列表。
②使用logMsg()现实相关内容,以定位错误。
初期调试,示波器和信号灯是非常有用的,可以确定硬件的工作状况,从而有助于发现程序中的错误。
PCI总线规范是为提高微机总线的数据传输速度而制定的一种局部总线标准。在设计自行开发的基于PCI总线的数据传输设备时,需要开发相应的设备驱动程序。通常开发PCI设备驱动程序有多种模式,在Windows2000环境下,主要采用WDM模式。本文针对自行开发的基于PCI总线的CCD视频信号传输控制卡,编写了符合WDM模式的驱动程序。
1WDM模式驱动程序
1.1WDM模式(WindowsDriverModel)
Windows2000对驱动程序的编写不再基于以往的Win3.x和Win9x下的VxD(虚拟设备驱动程序)结构,而是基于一种新的驱动模型——WDM(WindowsDriverModel)。
WDM为Windows98/2000/XP操作系统的设备驱动程序的设计提供了统一的框架。WDM来源于WindowsNT的分层32位设备驱动程序模型(layered32-bitdevicedrivermodel)。它支持更多的特性,如即插即用(PnP)、电源管理、WMI和NT事件。
1.2设备驱动程序
设备驱动程序是操作系统的一个组成部分,它由I/O管理器(I/OManager)管理和调动。Windows2000操作系统下的I/O管理器功能描述如图1所示。
I/O管理器每收到一个来自用户应用程序的请求就创建一个I/O请求包(IRP)的数据结构,并将其作为参数传递给驱动程序。驱动程序通过识别IRP中的物理设备对象(PDO)来区别是发送给哪一个设备。IRP结构中存放请求的类型、用户缓冲区的首地址、用户请求数据的长度等信息。驱动程序处理完这个请求后,在该结构中填入处理结果的有关信息,调用IoCompleteRequest将其返回给I/O管理器,用户应用程序的请求随即返回。访问硬件时,驱动程序通过调用硬件抽象层的函数实现。
1.3DriverStudio工具简介
NuMegaLab公司开发的DriverStudio是一整套开发、调试和检测Windows平台下设备驱动程序的工具软件包。它把DDK(DeviceDevelopmentKit)封装成完整的C++函数库,根据具体硬件通过向导生成框架代码,并且提供了一套完整的调试和性能测试工具SoftICE、DriverMonitor等。
2应用实例
本文利用PCI专用接口芯片PCI9052设计了一个数据传输控制卡。卡上主要的芯片有PCI9052、FIFO(CY7C4221)、CPLD(MAX7064S)和A/D转换器(MAX1197)。传输卡硬件框图如图2所示。面阵CCD得到的视频信号经过调理电路,生成的视频调理信号通过A/D转换器进行数字化处理,送入FIFO中。在CPLD的控制下,数据经过PCI9052送入PCI总线,再传送到计算机内存中,并显示在监视器上。驱动程序必须实现如下几个基本功能:(1)硬件中断;(2)能支持应用程序获取数据;(3)能根据外部FIFO(CY7C4221)的状态启动或停止突发传输。
在数据输入过程中,最重要的是对数据进行实时控制,因此需要硬件中断。在中断程序中,根据外部FIFO状态完成数据的读入。
2.1用DriverWizard生成驱动程序框架
DriverStudio中的DriverWorks软件为开发WDM程序提供了一个完整的框架。它包含一个可快速生成WDM驱动程序框架的代码生成向导工具DriverWizard,而且还带有许多类库。在用DriverWizard生成的程序框架中写入相对于设备的特定代码,编译后即可得到所需的驱动程序。
在利用DriverWorksV2.7的向导DriverWizard完成驱动程序的框架时共有11个步骤,其中关键步骤有:
(1)在第四步中选中PCI,并在VendorID和DeviceID中分别输入厂商号和设备号,还需填入PCISubsystemID和PCIRevisionID。这四项可以用网上的免费软件PCITree或PCIView浏览PCI设备,用这两个软件也可以得到BAR0~BAR5的资源分配情况和中断号。
(2)第七步IRP队列排队方法,它决定了驱动程序检查设备的方式。本设计选SystemManaged,则所有的IRP排队都由系统(即I/O管理器)完成。
(3)第九步是最关键的一步。首先在Resources中添加资源,在name中输入变量名,在PCIBaseAddress中输入0~5的序列号。0~5和BAR0~BAR5一一对应。在设置中断对话框中,在name栏写入中断服务程序的名称,选中创建中断服务程序ISR?穴CreateISR?雪,不选创建延迟程序调用DPC(CreateDPC),选中MakeISR/DPCclassfunctions,使ISR/DPC成为设备类的成员函数。
其次选中Buffer以选取读写方式,用于描述与I/O操作相关的数据缓冲区。本设计需要快速传送大量数据,因此采用DirectI/O方式。
(4)在第十步中,需要加入与应用程序或者其他驱动程序通信的I/O控制代码参量。
2.2驱动程序模块框图和代码分布
PCI设备驱动程序模块包括配置空间的访问模块、IO端口模块、内存读写模块和终端模块等。各模块之间是对等的。驱动程序模块框图如图3所示。
驱动程序初始化模块代码段放在#pragmacode_seg(″INT″)和#pragmacode_seg()之间。在系统初始化完成后,这部分代码从内存中释放,防止占用系统宝贵的内存资源。#pragmacode_seg()之后是驱动程序和系统的许多模块的实现部分。这部分在驱动程序运行后不会从内存中释放。
2.3驱动程序主要模块的实现
(1)配置空间的访问模块
DriverWorks的KPciConfiguration类封装了访问PCI设备配置空间的所有操作。首先初始化这个类的实例:
KpciConfigurationPciConfig()m_Lower.TopOfStack());
/?觹m_Lower是KpnpLowerDevice类的对象。m_LowerTopOfStack()返回当前设备堆栈顶部的设备对象。*/
初始化完后可以直接利用成员函数ReadHeader/WriteHeader函数访问所有的配置寄存器。
为了确定映射空间的类型和大小,先向目标基地址寄存器写入0Xffffffffh,然后回读该寄存器的值。如果最低位为1,表示映射于I/O空间,反之为存储空间;如果映射于存储空间,从第四位开始计算0的个数可以确定内存空间的大小;如果是I/O方式,从第二位开始计算0的个数可确定I/O空间的大小,最大为256字节。如果设备的存储空间超过256字节,要实现设备的整个存储部分的访问,就必须采用内存映射。
(2)I/O操作模块
Driverworks的KIoRange类封装了I/O端口访问的操作。部分代码如下:
{……
KIORangeDevIoPort();//创建实例
NTSTATUSstatus=DevIoPort().Initialize(pResListTranslated,pResListRaW,PciConfig.BaseAddressIndexToOrdinal(0));
/*第一个参数为转换后的资源列表指针;第二个参数为原始资源列表指针;第三个参数中的0为I/O口对应的基地址,用来转换成特定端口资源的序数?*/
If(NT_SUCCESS(status))
{……
DevIoPort.inb(0,LineBuf1,10);
/*成功初始化后可分别用KIoRange类的成员函数inb(/outb)从端口中读/写字节*/
}
else{Invalidate();returnstatus;
/*未能初始化成功,错误信息在status中*/
{
……}
(3)内存读写模块
DriverWorks的KMemoryRange类封装了端口访问的操作。
status=m_MemoryRange().Initialize(pResListTranslated,pResListRaw,PciConfig.BaseAddressIndexToOrdinal(0));
此函数的参数、意义及具体用法与I/O端口的操作基本相同。
内存对象也用来发送控制字,以控制CPLD的开始和停止等。实际上控制字是通过PCI9052发送的。该控制字地址已被映射成PCI的内存空间。所以定义一个指向内存空间的内存对象,通过该对象即可发送控制字。
(4)中断模块
在中断模块,首先要激活PCI9052中断使能位,然后判断硬件中断响应是否产生,如果有,则进行突发传输,读入FIFO中的数据。
BOOLEANTranCard::Isr_MyIrq(void)
{if(//中断未产生)
{……
returnFALSE;}
else
{/*如果产生硬件中断,设置命令寄存器,进行突发数据传输*/
returnTRUE;}
}
为了将硬件中断与编写的中断服务程序连接在一起,采用InitializeAndConnect方法,部分代码如下:
NTSTATUSTranCardDevice?押?押OnStartDevice(KIrpI)
{……
status=m_MyIrq.InitializeAndConnect(
pResListTranlated,
LinkTo(Isr_MyIrq),
This;)
……}
2.4驱动程序的调用
编写驱动程序本身不是最终目的,最终目的是调用驱动程序管理资源,并为用户应用程序使用。驱动程序加载以后,它的许多进程处于Idle状态,实际上需要用户应用程序去调用激活。应用程序利用Win32API直接调用驱动程序,实现驱动程序和应用程序的信息交互。
首先用CreateFile()打开设备,获得一个指向设备对象的句柄。使用CreateFile函数时应注意:由于驱动程序是*.sys,所以第一个参数应该是这个设备对象的标志连接(symboliclink)。该标志连接名有一个设置数据文件搜索路径的数字号,而这个数字号通常是零。如果这个连接名是″TranCard″,则传递给CreateFile的宇符串就是:″\\\\.\\TranCard0″。例如:
HANDLEhDevice=CreateFile(″\\\\.\\TranCard0″)GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL?,OPEN_EXISTING,0,NULL);
然后用DeviceIoControl()进行数据的传送。最后用CloseHandle()关闭设备句柄。
下面是应用DeviceIoControl()程序片段。
{……
m_b=DeviceIoControl(hDevice,TRANCARD_IOCTL_
RECEIVE(buffer,sizeof,buffer,NULL,0,&buffersize,NULL);
……}
2.5驱动程序的调试
1.1学生感到程序设计较难理解
计算机程序设计的学习困境主要表现在概念难懂,技术难以掌握,理论与实践的脱节等方面,尤其是在程序语言学习中面向对象程序设计语言时,绝大多数的学生不理解面向对象程序设计思想,不会使用类的思想进行程序设计。往往感到困难重重而方式深入学习,导致学习成绩节节下滑,不利于后来其他计算机专业课的学习。
1.2主动学习能力差
学生长期在传统应试教育环境影响下,形成了被动学习的习惯,缺乏学习的积极性与主动性,另外还有一些学生养成的不良学习习惯,在课堂学习中情绪比较懒散,精神比较散漫,对教师所讲的内容没有兴趣,这样很难提高学生学习成绩,影响教学效果的提高。
1.3实践能力不高
计算机是一门实践性比较强的学科,不仅需要学生掌握基本的理论知识,更重要的是理论应用于实际的能力,因为学习计算机的目的就是解决实际中遇到的问题。但是在实际教学中,很多教师设计的教学目标脱离学生的应用宗旨,教学过程中理论课比较多,实践课程比较少,这样较难培养学生的实际动手操作能力,很难真正提高教学效果。
1.4教学方法单一
过去教师一般采用传统的教学方法,从程序设计的概念出发,围绕理论知识点加以讲解,过多注重理论知识的讲解,而教材中的实力一般与学生实际生活相差较远,学生在学习的过程中感到生涩难懂,只会比葫芦画瓢,不会举一反三,缺乏独立思考问题和解决问题的能力。教师在教学过程中忽略了学生的主体地位,较难提高学生学习兴趣,同时也达不到较好的学习效果。
2项目驱动教学模式特点
2.1项目实践环境突出
项目驱动教学过程中,导师带领学生在学习专业理论知识的同时进行实际应用项目的开发。学生与老师在学习的过程中始终处于一种相互配合、沟通的环境下,强调学生的自主学习、积极沟通、勇于实践。学生在项目驱动下,带着问题进行有效的学习,这样能够培养学生思维扩散能力、动手操作能力与团结合作精神。
2.2强调教师的引导作用
项目驱动教学模式注重把理论知识转化为实际技术,在教学过程中教师仅仅起引导学习的作用,课堂的主体是学生。学生按照项目需求被划分为若干个小组,导师在课堂中主要监督、指导学生行为,在项目学习过程中导师要随时解答学生的疑问,为学生补充技能知识,实时启发学生在项目学习中解决问题的正确思路,开发学生思维创造能力,帮助学生掌握项目技能。
2.3培养学生计算机专业能力
项目驱动模式的实施目的是提高学生软件开发与应用能力,事件性知识一般比较隐蔽,而项目驱动教学能够通过教学过程中各种功能的实施,使一些隐藏在软件开发过程中的核心要素显现出来,通过这种方式的学习,学生将很快的具备软件应用开的基本能力,提高学生实践能力与应用能力。
3项目驱动教学实施过程
3.1项目设计
项目驱动模式教学过程中,首先导师要根据程序设计教学内容,设定教学目标,将教学计划、目标融入到教学项目中,然后将整个教学项目按照学习小组分成若干个独立的小项目,再把这些小项目按组分配给学生,最后导师围绕项目内容设计具体教学内容,项目来源一般源自于教师纵横向教学项目。
3.2实施形式
利用项目驱动模式进行教学的过程中,学生需要进入专门的工作室进行软件程序的学习与开发。在工作室中,主要的学习方式是自学,教师在这种模式下主要起引导作用,课程知识除了很少部分较深的理论课由导师专门讲授以外,其他的课程都是学生围绕项目进行自主学习、合作学习,主要学习方式包括:小组研讨、导师解疑、技术交流、调查研究等形式;课程的具体的实施要根据教学内容以及学生的实际认知情况进行合理的分配。这种教学模式的目的在于各种信息技术及认知提高计算机教学质量和效率,培养学生自主学习能力、创新能力和勇于探索精神以及实践能力。其中自主学习是由学生自己积极主动的去学习,在学习过程中导师的角色是解答疑问,并不是直接帮学生解决问题,导师可以向学生传授解决问题的方法和思路,引导学生向正确的解答思路上靠,提供给学生解决问题的资料,引导学生围绕疑问积极探索。如果学生在学习过程中遇到难以解决的问题,导师首先要积极引导学生找到解决问题的方法,同时教会学生利用移动通信、互联网、QQ以及电子邮件等先进技术手段进行搜索或者在线讨论与交流,尤其要教会学生怎样使用互联网查询资料,丰富程序设计知识,提高深深学习能力。在个人自主学习的基础上进行小组讨论与交流,在交流中不仅扩展知识与视野,而且能培养团队协作精神,增进同学之间的感情。导师还要积极引导学生发现规律,找到自己的不足,积极改正,不断超越自我。
3.3项目驱动教学模式中的成绩评定
成绩评定是项目驱动模式教学的重要组成部分,成绩评定一般具有激励、引导和反馈的作用,能够全面反映学生的近况。成绩评定比较重视学生在学习过程中能否解决实际问题,旨在培养学生动手操作的能力和创新能力以及计算机素养,树立科学精神和坚韧不拔的性格以及积极向上的人生观。如果学生成绩提高,教师要给予鼓励和表扬,激励学生再接再厉。成绩评定的方式采用项目答辩的形式进行,每个小组派出一个代表作主辩手,其他学生补充,导师可以随时提问,最后结合项目答辩情况给出学生最终考核成绩。
中图分类号:TP274.2 文献标识码:A 文章编号:1007-9416(2016)04-0000-00
在针对新一代多普勒气象雷达实现多功能、多模式的目标实现上同时获得更高质量的数据,对获取雷达数据的速率和容量的要求越来越高。而伴随软件无线电技术的突破,雷达作业系统将有可能要直接从射频采样中获得更丰富的数据。这些气象雷达领域技术的发展,都对雷达高速数据采集传输提出了新的需求,现有的气象雷达数据传输带宽已经不能满足需要了。对基于计算机平台的气象雷达作业系统,提出了关键部件商品断档和已有技术须适应计算机硬件环境的挑战。鉴于现阶段的各个类型的气象雷达中,雷达数据还主要基于PCI总线进行传输,数据带宽已经不能适应现代气象雷达的发展,为保障已有气象雷达设备能够得到后续升级技术的储备,研究气象雷达数据在PCI-Express总线上的技术[1],将能解决主流计算机淘汰的PCI接口对气象雷达数据处理后续发展的问题。
1 气象雷达信号处理器介绍
该信号处理器是气象雷达视频I/Q数据采集和系统参数控制的核心板卡,其主要完成了PC机对中频I/Q数据采集,接收机、发射机控制功能,其性能的好坏直接影响到了整个雷达系统的正常运行。通过接收串行格式的中频数据,并将数据按照预先设定进行储存,经由PCI-Express接口定时通知计算机获取数据。也能通过它发送大量参数到外部串行接口,对硬件进行指定的参数传递。该雷达信号处理器采用美国PERICOM公司的PI7C9X130作为本地总线和PCI-Express总线的接口。PI7C9X130是一款x4的PCI-Express to PCI-X/PCI桥接芯片,本地端总线频率最高可达133MHZ,数据位宽64bit。PI7C9X130拥有4KB的配置空间,其中前256字节是和PCI设备功能上是兼容的,其余是PCI-Express扩展配置空间[2]。
2 驱动程序设计
总线驱动程序由系统提供,本文只设计了PI7C9X130的功能驱动程序,它主要由驱动程序初始化、双缓冲数据传输模块两部分组成。基本思想是:驱动内设置DMA缓存和数据缓存(比DMA缓存大),采用中断方式获取板卡数据,当驱动收到一个外部数据中断时,启动DMA读取乒乓FIFO中的数据到DMA缓存,每次读完后,都复制DMA缓存到数据缓存区,以匹配DMA传输与上层应用程序Read数据的速度。
2.1 WDF驱动程序设计
DriverEntry是驱动程序的入口函数,负责初始化和构造驱动程序对象。系统启动时,如果检测到PI7C9X130的存在,I/O管理器会创建一个未初始化的驱动程序对象并将它作为一个参数传给DriverEntry。DriverEntry根据这个对象创建WDFDRIVER对象,并注册DeviceAdd例程并在此例程中进行设备驱动初始化,包括创建设备扩展对象并分配初始化各个子对象,包括WDFINTERRUPT、WDFQUEUE、WDFDPC、 WDFDMAENABLR等[3]。
2.2 双缓存数据传输
功能驱动正常装载后,应用程序就可以向驱动发起打开中断请求,数据卡在中断开启的情况下在获得数据后会产生外部中断,在驱动中断处理服务例程中,排队一个DMA传输DPC(Delayed Procedure Call)事件,进行数据传输。当DMA完成传输,产生DMA完成中断,通过中断服务例程排队一个数据复制事件,把DMA缓存的数据复制到数据缓存中。应用程序只要调用Read,就可以读取数据缓存中的雷达中频数据,而不用担心因为进程切换等系统因素导致的DMA数据传输和应用层Read速度不匹配问题。
2.3 内核驱动程序调试
本文采用微软随WDK一起的调试工具WinDbg调试驱动程序。WinDbg是一种内核模式和用户模式的调试器,可以用来分析故障存储文件和执行驱动程序代码。采用双机调试:目标机(气象雷达信号处理器)和主机(运行WinDbg的机器),用串口线连接,主机控制和监视目标机上的活动[4]。设置好主机和目标机后,通过WinDbg的命令窗口可以设置断点、观察调试输出信息或分析目标机蓝屏产生的故障存储文件。
3 结语
本文介绍了基于PCI-Express总线的气象雷达信号处理器的驱动程序开发。经实测,该数据处理器稳定传输速度达到530Mbyte/s,超越原基于PCI总线的数据处理器速度,适应气象雷达大幅度增长的探测原始信息量,为新一代多普勒气象雷达关键技术的发展提供了可行的方案。
参考文献
[1] 何建新.现代天气雷达[M].四川:电子科技大学出版社,2004-05.
[2] 孟会,刘雪峰.PCI Express总线技术分析[J].计算机工程,2006(32):252-258.
[3] 武安河.Windows设备驱动程序WDF开发[M].北京.电子工业出版社,2009
1 嵌入式Linux系统
1.1 Linux操作系统
Linux是一套可以免费使用和自由传播的类UNIX操作系统,其实际上只是一个操作系统的内核,主要用于Intel x86系列CPU的计算机上[ ]。
谈及Linux的起源,其灵感源自于UNIX。UNIX操作系统于1969年由Bell实验室设计开发,之后Linus Torvalds设计了Linux,该系统在发展初期就得到了广大程序员的帮助,逐步发展成为现今这样一个拥有自己版权的完整的系统。
Linux具有很多特点,如支持多种体系结构,支持大量的设备,具有完善的网络功能,开放源代码,软件资源丰富,内核稳定等,可总结为以下几点:
(1)强大的编程能力[ ]。由于Linux源自于世界各地成千上万的程序员和黑客,使得Linux就犹如加入到了一个高手如云的编程组织中,同时,由于GPL的存在,Linux开放源码,吸引更多专业人士的加入,在这种需求的刺激下,Linux提供的开发工具功能也越来越完善,越来越强大。
(2)完善的组网能力。Linux具有强大的组网能力,它对当前的TCP/IP协议[ ]提供了完全的支持,同时也支持下一代Internet协议IPv6。在安全性方面,Linux内核中包括了IP防火墙代码、IP防伪及IP服务质量控制等特性。现阶段,Linux广泛用于服务器,其可以作为Windows客户机的打印和文件服务器,也可用做NT的文件和打印服务器,甚至可作为Macintosh客户机的文件和打印服务器。另外,Linux还包括了一个Ftp服务器、一个电子邮件传输程序以及POP和IMAP邮件服务程序。
(3)Linux是自由开放的。Linux是自由软件,允许成千上万的人检查软件,修改软件,最终可以按照用户自己的意愿来定义自由软件,可以定制自己的Linux。
(4)系统稳定。Linux提供了完全的内存保护机制,每个进程都运行在各自的虚拟地址空间中,不会损坏进程或内核使用的地址空间。一台运行Linux的机器启动一次可以运行数个月。在安全性的较量上,Linux明显比Windows98和NT占上风。据统计分析,Linux是目前最安全的操作系统。
1.2 嵌入式系统
最早期的8位/16位系统,大多都是没有操作系统的,然而在进入32位时代之后,系统软件变得越来越复杂,出现了控制能力不够,维护成本过高,系统升级困难等问题,促使了操作系统的迅猛发展。而嵌入式操作系统,则被定义为“以应用为中心、以计算机技术为基础、软硬件可裁剪、适应应用系统,对功能、可靠性、成本、功耗等方面有严格要求的专用计算机系统”。
嵌入式操作系统的特点有:提供较好的内核管理、多任务管理、资源管理、稳定性好、可裁剪和配置、满足实时性需求、针对性强等。随着计算机信息技术的不断发展,嵌入式操作系统也在不断演化升级,常见的有uC/OSⅡ操作系统,eCOS操作系统,VxWorks嵌入式实时操作系统,WinCE操作系统以及Linux操作系统等。嵌入式Linux利用嵌入式系统实时性、稳定性的特性和Linux相辅相成,很好的弥补了Linux实时性差的缺点,使得Linux在嵌入式领域发展迅速。近年来,嵌入式Linux操作系统的应用相当热门,已经广泛应用于笔记本电脑、连网装置、网络电视等各式各样的通信基础产品中。
2 系统硬件环境
2.1 Intel的XScale系统结构
XScale系统结构是对StrongARM的系统结构的扩充和改进。Intel的第一个StrongARM处理器SA-110实现了ARM系统结构的第4版,即ARMv4内核。StrongARM是ARM公司的注册商标,最初由ARM公司与当时DEC公司联合开发,由DEC生产和销售,但是后来由Intel生产。SA-110是第一个采用哈佛结构的ARM内核,因此,它有两个独立的高速缓存和两个MMU。这样取指令与读/写就不需要在时间上互相错开,从而提高了访问高速缓存的速度。
2.2 PXA27x处理器
PXA27x处理器是Intel公司在2004年4月12日正式的当前最新的嵌入式处理器。它的时钟频率从312到624MHz,并内建64MB(megabytes)的堆栈型IntelStrataFlash内存。它内置了Intel公司的无线MMX技术,能够为3D游戏与影片应用提供更高的效能,显著提升多媒体性能。312MHz的CPU(PXA27x系列中最低时钟频率的产品)将达到520MHzARMCPU的多媒体处理效能,而钟频达到624MHz则可以具备775MHzARMCPU的表现。
3 系统软件环境的建立
3.1 嵌入式操作系统的选择
嵌入式操作系统的选择主要从以下几个方面加以考虑。
①操作系统的硬件支持:首先是否支持目标平台,其次可移植性。②开发工具的支持程度:选择嵌入式操作系统时必须考虑与之相关的开发工具。在线仿真器(ICE)、编译器、汇编器、链接器、调试器以及模拟器等不同程度的影响到嵌入式软件的开发。
③能否满足应用要求:应用对操作系统的要求包括实时性能、不同语言的支持、标准兼容性、技术支持、源代码还是目标代码等等。
若找不到一个合适的操作系统或者买不起昂贵的商用操作系统,可以考虑自己建立一个操作系统。
3.2 系统结构设计
Trident PNX8471芯片平台能够接收BTSC(Broadcast Television System Committee),该平台有两个硬盘接口、一个MII 接口(Media Independent Interface,介质无关接口或称为媒体独立接口,它是IEEE-802.3定义的以太网行业标准。它包括一个数据接口,以及一个MAC和PHY之间的管理接口)、2个USB2.0接口、1个USB1.1接口、5路TS输入接口、2路I2C,支持3D图形加速。在性能上支持:视频支持1080P60输出,支持H.264、MPEG2、VC-1、DiVX、AVS等格式,同时也支持RMVB格式480P的输出,3DTV支持H.264 MVC 1080P30输出;音频支持BTSC、CH3/4,输出支持YPbPr、RGB、Y/C、CVBS;TS处理方面最大支持5路基带输入和4路DMA输入,最大支持192个Filter。
Trident PNX8471芯片平台的编译使用GNU3.81,Perl版本5.8.8,支持Android2.3,Linux内核版本2.6.34。平台在基于Android的架构上增加了数字电视相关的功能模块。实现本项目的EPG功能,同时兼顾EPG功能的扩展性,我们需要在硬件抽象层增加Demux模块,用来接收PSI/SI数据,这个部分将是Program模块、Event模块、Time模块公用的模块;在Libraries层增加Program模块、Event模块、Time模块,用来实现节目、事件、时间的功能;在应用框架层(Application Framework)增加获取EPG功能的EPG JNI接口;在应用层增加EPG的呈现。
4 结语
嵌入式系统已成为以高速CPU和嵌入式操作系统为核心的软硬件综合系统。系统兼容性好,效率高,而且具备文件和目录管理、设备支持、多任务、网络支持、图形窗口及用户界面等功能。
参考文献:
[ ]彭晓明,王强.Linux核心源代码分析[M].北京:人民邮电大学出版社,2000.
[2]李善平,刘文峰.Linux与嵌入式系统[M].北京:清华大学出版社,2006.3.