蒋康康,郑思远
(重庆邮电大学自动化学院 重庆 400065)
USB接口作为一种高速的新型总线接口,支持即插即用设备,并能为外设提供电源且易于扩展,已成为了计算机和嵌入式系统应用的主流接口。人机接口设备(HID)一直是Windows系统支持较完善的设备类,不仅提供了完整的USB系统软件,而且直接提供HID的设备驱动程序,只要按照HID类的规范编写设备固件程序,就能够让Windows系统自动识别设备,省去了复杂的驱动程序编写过程,这样大大降低了开发的难度[1]。本文给出了一种利用S3C2440内置USB控制器实现HID类接口的设计方案,以及如何在应用程序中对HID类设备进行访问。
S3C2440是基于ARM920T内核的一款MCU,主频高达400MHz。其内部集成的全速USB设备控制器兼容USB1.1,支持全速和低速两种运行速度,提供了5个可灵活配置的端点,64字节FIFO存储器,集成的USB收发器,支持挂起和远程唤醒功能,可方便实现与计算机通信[2]。由于S3C2440内部集成了USB控制器,所以接口电路比较简单,如图1所示。
图1 S3C2440的USB接口电路
HID是用于管理和控制大多数计算机的人工输入设备,如键盘、鼠标、游戏杆等;但HID设备不一定非要是这些人机交互设备,只要符合HID设备级定义规范要求的都可以认为是HID设备,其具有以下功能特点[3]:①交换数据驻留在报告结构里;②适用于传输少量或中量的数据;③传输的数据具有突发性;④传输的最大速率有限制;⑤无固定的传输率。
USB设备有4种传输方式与主机进行通信:控制方式、中断方式、批量方式和同步方式。HID类仅支持其中的2种,即控制传输和中断传输。HID设备和主机上的HID类驱动程序之间是通过缺省的控制管道和中断管道来传输数据的,其中控制管道和中断输入管道是必须的,中断输出管道是可选的[4],如图2所示。
图2 HID的数据传输方式
HID设备类是在USB的接口描述符中定义的,其除了支持标准USB描述符外,还自行定义了3种描述符,分别为HID描述符(主要用于识别HID设备所包含的其他类描述符)、报告描述符(提供HID设备和主机问交换数据的格式)和物理描述符。一个HID设备只能支持一个HID描述符;可以支持一个或多个报告描述符;物理描述符是可选的,大多数HID设备不需要使用它。图3显示了HID各种描述符之间的关系[5]。
图3 HID各种描述符之间的关系
USB协议定义了11种标准请求命令,Get Status,Clear Feature,Set Feature,Set Address,Get Description,Set Description,Get Configuration,Set Configuration,Get Interface,Set Interface和Synch Frame。主机通过这些请求来获取设备的信息及对设备进行设置。HID类设备除了支持这些标准请求外,还要实现以下6种特定请求:Get Report、Set Report、Get Idle、Set Idle、Get Protocol、Set Protocol。Get Report和Set Report的作用是通过控制管道接收和发送数据报告[6]。
初始化部分是固化程序能畅通运行的基础,是USB系统能正常工作的基本工作。主要包括USB设备控制器中的特殊寄存器初始化、中断初始化以及描述符的初始化[7]。
USB设备固件程序的核心就是对主机请求进行响应,实现USB设备枚举。枚举是USB设备插上之后,主机与设备最初的数据交换过程。在编写这部分代码时,首先应该清楚USB设备连接到主机时,主机需向USB设备所发的所有请求,然后编写相应的代码来响应具体的请求。图4为USB连接时总线枚举的主要过程。
图4 USB设备枚举过程
HID类设备接收主机的一系列请求时都是通过中断的方式来激活。当设备收到来自USB接口的中断时,会立即根据USB中断寄存器中的变化来判断PC的请求,并对其作出相应的响应。当主机通过缺省的控制通道对USB设备发出请求时,设备的端点0产生中断,设备首先从端点0的FIFO中读出Setup包,然后根据Setup包中的数据来确定具体的响应。Setup包内的每个域(或称字段)值是由主机负责设置。每个Setup包由8个字节构成,可用C语言的结构体数据类型描述如下:
USB设备接收该包的语句为(其中RdPktEp0()为从端点0缓冲区FIFO中读取8字节数据的函数,DescSetup为保存Setup包的结构):
RdPktEp0((unsigned char *)&DescSetup,8);
然后根据Setup包中域bRequest中的值来判断具体的请求,使用分支语句来实现不同请求的跳转,以完成对主机标准请求和HID类特定请求的响应。形式为:
具体情况如下:
1)当 bmRequestType=0x80且 bRequest=0x06, 主机请求类型为GET_DESCRIPTOR,此时若bValueH为0x01表明主机向设备请求设备描述符;为0x02表明主机向设备请求配置描述符;为0x03表明主机向设备请求字符串描述符。
2)当bmRequestType=0x00且bRequest=0x05,主机请求类型为SET_ADDRESS,bValueL为设置的地址值。
3)当bmRequestType=0x00且bRequest=0x09,主机请求类型为SET_CONFIGURATION,bValueL指示了一个设置配置。
4)当bmRequestType=0x21且bRequest=0x0A,主机请求类型为Set_Idle,该请求的作用是限制中断输入端点的报告频率来节省总线带宽,bValueH设置了报告之间的最大时间间隔,bValueL设置了设备所支持的报告类型。
5)当 bmRequestType=0x81,bRequest=0x06且bValueH=0x22,表明主机向设备请求报告描述符。
Windows为应用程序访问HID设备提供了强大的支持,提供了完整的HID类驱动程序以及相应的API函数。API函数名中包含Hid字样的函数属于hid.lib,包含Setup字样的函数属于setupapi.lib,使用VC编写应用程序时需要在工程设置选项的Link下的Library Modules下加入hid.lib和setupapi.lib,否则会出现链接错误[8]。
应用程序要访问设备首先必须利用Windows提供的API函数枚举到设备,图5为应用程序枚举HID设备流程。
图5 应用程序枚举HID设备流程
枚举成功后返回设备句柄,然后就可以调用ReadFile()和WriteFile()函数对设备进行读/写数据了。
图6 USB HID应用程序运行界面
根据上述思路编写的USB HID主机应用程序的人机界面如图6所示。测试时,ARM9控制器S3C2440模块每隔5ms向PC机端循环发送0~7共八字节数据,点击图6所示的“接收”,可以看到界面上能准确无误显示收到的数据。
该设计融合了S3C2440功耗小、代码执行效率高和USB传输效率高、结构简单的优点, 容易可靠地实现USB HID设备的开发,所设计程序已经在硬件平台上成功运行。这样的设备无需驱动,在插入PC后就能立刻开始工作,省去了安装驱动程序的过程,方便使用。
[1] 马伟.计算机USB系统原理及其主/从机设计[M].北京:北京航空航天大学出版社,2004.
[2] S3C2440A处理器用户手册,Revision 1.
[3] USB Implementer's Forum.Universal Serial Bus Device Class Definition for Human Interface Device 1.11.2001.6.27
[4] 詹克团,侯国志.USB HID类设备的开发[J].电测与仪表,2004,41(5):48-50.
[5] 杨晶晶,江春华.USB HID设备驱动程序设计[J].微计算机信息,2006(22):140-143.
[6 刘立,谢剑斌.基于HID类的USB接口技术研究[J].计算机工程与科学,2003,25(5):82-85
[7] 倪陈强,陈 赘.基于C8051f340单片机的USB HID类设备设计[J].现代电子技术,2007,18(257):64-66.
[8] 扶文树,何 军,陆信如.USB HID数据通信接口的设计与实现[J].工业控制计算机,2009,22(2):8-9.