因为杰出的功用、低价的价格和灵敏便利的特性,USB 摄像头正被广泛的集成到嵌入式体系中。例如,经过USB 摄像头WinCE体系能够很便利地得到实时图画,这对某些要求实时图象监控的嵌入式体系是一个很不错的挑选。可是因为嵌入式硬件渠道的多样性,以及WinCE对USB设备驱动开发只供给了底层支撑,再加上许多摄像头厂商没有供给WinCE下的USB摄像头驱动,这对初级开发人员在开发WinCE USB摄像头程序时是一个难点。
前段时刻,公司派遣我担任一个嵌入式项目,项目要求是在WinCE渠道上集成USB摄像头驱动和视频收集程序。这个项目的关键是要集成USB摄像头驱动,并高效的把摄像头设备进行初始化以获得一幅完好的图画。幸亏我曾经开发过WinCE USB的主从设备的驱动程序。但尽管如此,我仍是花了一些时刻来调整体系的稳定性和可靠性。在这儿我共享在这次项目实践中得到的经历和经历,期望大家能少走弯路。
一. 什么是USB设备驱动程序开发?
跟着USB设备的遍及,USB设备驱动开发在嵌入式体系变得越来越重要了。为了支撑不同类型的硬件能够衔接到WinCE渠道上,微软供给了具有定制接口的流接口驱动程序模型。WinCE的USB外围设备一般是运用流接口驱动程序。流接口驱动程序是指经过体系供给的文件体系API与应用程序交互;WinCE内核体系会经过设备办理器来完结对流接口驱动程序的加载、卸载等办理作业;而流接口驱动程序则会经过调用USBD模块供给的接口函数完结与底层USB设备通讯。因而,在进行USB设备驱动程序开发之前,咱们有必要先了解USB设备驱动的结构和分类。
(1)主机与USB摄像头的通讯结构
USB摄像头驱动程序首要是运用体系供给的底层接口装备设备和摄像头设备进行通讯。因而,WinCE的USB摄像头驱动分为两层:USB Client设备驱动程序和底层的WinCE函数完结层。而底层的函数层自身又由两部分组成,即通用串行总线驱动程序(USBD)模块和较低层的主操控器驱动程序(HCD)模块。HCD担任最底层的处理,USBD模块完结较高的USBD函数接口。因而,USB摄像头驱动首要是运用USBD接口函数和外围USB摄像头打交道。
一般来说,主机和USB外设之间的通讯是由在主机端经过USBD模块和HCD模块运用的PIPE拜访一个通用的逻辑设备来完结。也便是说,USBD和HCD是一组笼统出来用于拜访USB设备的逻辑接口,它们首要是担任办理USB外设的衔接、加载、移除、数据传输和通用的装备。其间HCD是由主机操控和驱动的,是为USBD供给底层的功用拜访服务。而USBD则是由USB总线驱动的,坐落HCD的上层,是运用HCD的服务供给较高层次笼统的功用。
因为HCD和USBD都是面向共同的逻辑设备接口,因而假如嵌入式体系中具有多种USB物理外设的话,那么就需求有仅有对应的外设驱动程序,也便是要有最上层的PIPE所衔接的物理设备和USB设备驱动程序。有了对这个结构的知道,那么咱们在进行USB设备驱动程序开发时首要要写的便是最上端的USB摄像头客户端驱动程序,在WinCE的样例程序中它也被称为USB Client Driver。它是作业于USBD之上,所以实际上咱们的作业就变成了运用USBD供给的接口针对特定的物理设备来完结USB设备驱动程序。(见图)
(2)流驱动程序的分类和函数结构
WinCE驱动程序是介于内核体系和物理设备之间的一个代码层,它的首要作用是为内核体系供给一个接口用来操作不同的外围设备,包含物理设备和虚拟设备。驱动程序供给给内核体系的接口一般能够分为:本地驱动(Native Drivers)和流驱动(Stream Drivers)。我从这次项目实践中得到的经历是,WinCE下的一切驱动都能够归类到这两个里边,二者必居其一。
流驱动是指经过为内核体系供给流接口函数来完结驱动外围设备,如XXX_Init()、XXX_Open()、XXX_Read()、XXX_Write()、XXX_Close()等。这一类的驱动由Device Manager来办理,它是经过调用ActivateDeviceEx()函数来完结加载流驱动的。ActivateDeviceEx()的参数是注册表中相应的键,用来设定加载流驱动的特点,如Index、Order、Prefix等等。流驱动加载成功后,应用程序就能够经过调用CreateFile()、ReadFile()、WirteFile()等函数来拜访流驱动设备了。而与流驱动相反,本地驱动供给给内核体系的不是规范的流接口,而是事前约定好的特定接口。因而不同的本地驱动设备,接口也是不一样的。在WinCE中,常见的本地驱动有LCD显现驱动、触摸屏驱动、鼠标和键盘驱动及打印机驱动等。从这儿能够看出,本地驱动首要是触及与人机界面相关的驱动。它们是由GWES来办理的,因为他们在注册表中有各自相应的装备信息,因而它们会在体系启动时主动加载。简略的说,便是本地驱动是由内核体系操作和调用的,一般的应用程序是不能拜访和调用的。
在上一段描绘中咱们说到主动加载的概念,这是从驱动加载时刻来区别的。首要分为两种:一是体系启动时主动加载;二是需求时才加载。一般来说,本地驱动都是在启动时主动加载的。而需求时才加载的方法,望文生义便是想加载时才加载、想卸载时就可卸载。USB设备的驱动加载都是归于需求时才加载的驱动,例如USB摄像头的驱动程序。而从驱动的接口来看,USB摄像头驱动又归于流驱动接口。但相对于一般的流驱动接口,它增加了几个特有的接口函数:如USBDeviceAttach()、USBInstallDriver()、USBUnInstallDriver()等。在这次项目的调试中,咱们发现需求时才加载的驱动程序有一个十分有用的优点,便是能在不修正嵌入式内核体系的情况下,应用程序能够动态加载该驱动以完结对硬件的操作,而操作完结后又可卸载其驱动程序以节约有限的内存。
(3)USB设备驱动程序进口点函数剖析
大部分USB外围设备因为功用性的原因会更适合运用流接口驱动结构,所以一般都会选用加载式流接口驱动程序模型来开发USB设备驱动程序。流驱动是指经过流接口函数来完结驱动外围设备的。因而,编写流驱动程序实际上便是对各种流函数进行调用。
又因为USB摄像头驱动程序首要是和USBD打交道,所以咱们有必要具体的了解USBD供给的函数。让人感到走运的是在WinCE下微软现已供给了通用串行总线驱动程序(USBD)模块、USBD接口函数全集、样本主机操控器驱动程序(HCD)模块。所以,咱们只需求根据USB摄像头的硬件特性,运用USBD供给的不同函数就能完结流接口函数与外围摄像头设备的交互。就能大大的节约开发时刻,从而能更快速地进行嵌入式开发。