USB总线程序设计Word文档下载推荐.docx
《USB总线程序设计Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《USB总线程序设计Word文档下载推荐.docx(78页珍藏版)》请在冰点文库上搜索。
AnchorChips公司(Chips公司的USB芯片集是以一个改进的8051微处理器以及一个核心逻辑为基础来实现USB规范中的一些低级协议。
开发板上还含有附加的外部存储器、一个UART、一组按钮、一组LED读出器,用于开发和调试基于AnchorChips软件框架的8051固件(firmware)。
AnchorChips芯片集的一个关键特征是可以通过USB下载固件。
对于一个像我这样恐惧硬件,特别是EEPROM编程的程序员来说,这个特征简直太好了!
随书光盘中的USB例子驱动程序演示了最简单的USB设备以及它所能执行的一些任务。
如果你碰巧有一个AnchorChips的开发包,就可以用真正的固件实验这些例子程序。
每个例子都包含一个WDM驱动程序(在SYS子目录)、一个Win32测试程序(在TEST子目录)、和一个固件程序(在EZUSB子目录)。
你可以按照每个例子中的HTM文件的指导编译这些部件或者直接安装光盘中的已编译好的版本。
有一点需要指出,AnchorChips提供的是简化版本的8051开发工具,版权由KeilElektronikGmbH保留,如果你需要开发真正的固件,必须从Keil得到工具软件全部功能的使用许可。
Keil现在提供改进的32位8051开发工具uVision2。
编程架构
USB可以使程序员在不了解总线电气特性的情况下写出主机和设备的驱动软件。
USB规范的第五章“USB数据流模型”和第九章“USB设备框架”描述了许多对于驱动程序作者有用的特征。
在这节中,我将概述这些章。
设备层次
图11-1演示了一个简单的USB配置拓扑。
USB主控制器与其它I/O设备一样直接连接到系统总线上。
操作系统与主控制器通信使用I/O口或内存寄存器,通过普通的中断信号,系统可以接受主控制器的事件通知。
主控制器连接一棵USB设备树。
一种称为hub的设备作为其它设备的连接点。
多个hub能以菊链方式连接,可以连接到USB规范中定义的最大深度。
其它设备,如照相机、麦克风、键盘等等,直接连到hub上。
为了精确地表达概念,USB使用术语function来描述非hub设备。
图11-1.USB设备层次结构
高速和低速设备
USB规范中定义了两种设备,高速设备和低速设备。
低速设备以1.5Mb/sec速率通信,高速设备以12Mb/sec速率通信。
hub能用电子方式区分这两种设备。
发生在总线上的通讯通常都是高速的,hub一般不向低速设备发送数据。
操作系统把任何发往低速设备的消息前加上一个前导包,这将使hub临时降为低速,并完成低速设备的数据发送。
电源
USB电缆中含有两条电源线。
hub可以为连接在其上的设备提供电力,USB规范限定了总线供电设备所消耗的电流。
这个限定会因为设备插入可供电hub或与最近可供电hub的远近而改变。
另外,USB允许设备有睡眠状态,处于睡眠状态下的设备仅消耗非常低的电力并足够支持唤醒和配置信号。
另外,设备还可以不用总线电力而直接使用外接电源。
USB设备可以唤醒睡眠中的系统。
当系统进入节能状态后,操作系统也把USB总线置入节能状态。
一个有远程唤醒特征的设备能发出唤醒信号,信号首先被送到hub,然后又被hub送到主控制器,最后由主控制器送往系统。
USB设备设计者应该知道唤醒特征的一些限制。
首先,远程唤醒功能仅能工作在有高级电源配置接口(ACPI)BIOS的计算机上,而不能工作在早期的系统上,这些早期系统或者支持APM或者根本就没有电源管理特征。
另一个限定在驱动程序的通知上。
WDM提供了一种方法——IRP_MN_WAIT_WAKE电源管理IRP,当设备唤醒系统时该IRP被发往驱动程序。
然而,当USB设备从节能状态恢复到正常状态时,而此时系统又处于正常工作状态,该IRP将不出现。
设备中有什么?
一般,每个USB设备有一个或多个配置(configuration)来控制其行为,如图11-2。
使用多配置的一个原因是对操作系统的支持,例如,系统BIOS可以使用一个简单的配置而操作系统中的驱动程序则使用另一个更复杂的配置。
图11-2.USB设备的配置、接口、端点。
设备的每个配置中都含有一个或更多的接口(interface),接口指出软件应该怎样访问硬件。
接口的概念与第二章(“WDM驱动程序的基本结构”)中讨论的连接命名设备中的概念类似,即支持相同接口的设备本质上可以互换,因为它们以相同的方式响应相同的命令。
另外,接口一般都有替换设置(alternatesetting)以适应不同的带宽需求。
设备的接口露出一个或多个端点(endpoint),端点作为通信管道的一个终点。
图11-3显示了一个多层次结构的通信模型,它表明了端点和管道所扮演的角色。
在最低一级,USB电缆把主控制器与设备的总线接口连接起来。
在第二级,一个控制管道把系统软件与逻辑设备连接起来。
在第三级,一捆数据管道把客户软件与一组接口连接起来,这些接口组成设备的function。
信息实际上是在图中两侧垂直流动,但把它理解为在这些分层的管道中水平流动更清晰。
图11-3.USB的多层次通信模型
一组由Microsoft提供的驱动程序占据了图中系统软件方块中的底部。
这些驱动程序包括主控制器驱动程序(OPENHCI.SYS或者UHCD.SYS),hub驱动程序(USBHUB.SYS),和一个类驱动程序(USBD.SYS),由控制器驱动程序使用。
为了方便,我把USBD下面的所有驱动程序看成一个整体,我们的驱动程序主要就是与这个整体进行交互,它们管理着硬件连接和管道通信。
WDM驱动程序,就是你和我将要写的,占据系统软件方块中的顶部。
广义地说,WDM驱动程序的工作就是把客户软件的请求翻译成USBD能执行的事务(transaction)。
客户软件处理实际的设备功能。
例如,一个图象生成程序占据的客户软件槽可能与一个静态图象function(如数码相机)对应。
信息流动
USB定义了四种数据传输方式,如表11-1所示。
它们的不同之处有:
单个事务能携带的数据量(下一段将解释术语“事务”transaction)、能否保证特定的周期或延迟,能否自动校正错误。
每种传输方式对应特定类型的端点。
实际上,给
定类型的端点(控制、批量、中断、等时)总是使用对应类型的传输。
类型
描述
纠错
包容量(字节)
延迟保证?
控制
用于发送和接收USB定义的结构化信息
是
≤8,16,32,64
尽最大能力保证不延迟
批量
用于发送或接收小块无结构数据
≤8,16,32,64
无
中断
与批量管道相似,但包括一个最大延迟
≤64
以保证的最小速率轮询
等时
用于发送或接收有周期保证的大块无结构数据
否
≤1023
每1毫秒帧中的固定部分
表11-1.数据传输类型
端点除了传输类型外还有其它几个属性。
其中一个属性是单一事务中端点能够提供或消耗的最大数据量。
控制和批量端点必须指定某个离散值,而中断和等时端点能指定少于或等于最大值的任何值。
端点的另一个属性是传输方向,输入(数据从设备到主控制器)或输出(数据从主控制器到设备)。
最后,每个端点都有一个端点号,其中包含输入输出方向,作为端点的地址使用。
当主控制器要求设备执行某些多少有些规则的功能时,USB使用一个轮检(polling)协议。
当一个设备需要向主控制器发送数据时,主控制器必须注意到并且向要发送数据的设备发出一个请求使其发送数据。
即USB设备不用传统方式中断主计算机,而是提供中断端点,主机周期轮检中断端点。
信息打包
当客户程序通过USB管道发送或接收数据时,它首先调用Win32API,调用最终将使function的驱动程序收到一个IRP。
而驱动程序的工作就是把客户的请求引导到有正确端点的管道上。
它把请求提交到总线驱动程序,总线驱动程序再把请求分解成多个事务(transaction),然后这些事务被送往总线。
总线上的信息流以每毫秒一帧数据的形式流动。
总线驱动程序必须安排好多个事务以使它们能被装入同一帧中,图11-4显示了这个过程。
图11-4.信息流中的事务和帧模型
在USB中,事务由一个或多个阶段(phase)组成。
阶段有令牌(token)、数据(data)、握手(ack)三种类型。
根据不同的类型,事务有一个令牌阶段、一个可选的数据阶段、和一个可选的握手阶段组成,如图11-5所示。
在令牌阶段,主控制器向所有已配置的设备广播该令牌包。
令牌包中含有设备地址,通常还有端点号,仅有被寻址的设备才会处理事务;
当事务寻址设备时,任何设备都不读写总线。
在数据阶段,数据被放到总线上。
对于输出事务,主机把数据放到总线上,而被寻址的设备消耗这些数据。
对于输入事务,情况相反,设备把数据放到总线上由主机消耗。
在握手阶段,由设备或主机把握手包放到总线上,包中含有状态信息。
当设备发出握手包时,ACK包指出成功地接收了信息,NAK包指出忙并且不试图接收信息,STALL包指出事务被正确接收但在逻辑上无效。
当主机发送握手包时,它仅能发送ACK包。
图11-5.总线事务的阶段
你也许会注意到,没有发出握手包的事务就代表“在这个事务中出现了一个传输错误”。
正在等待握手包的一方应认为缺少握手包可能是发生了错误并重试刚才的事务。
USB的设计者确信这种错误很少发生,由于重试而造成的偶然延迟对于总线吞吐量不会有大的影响。
关于设备寻址的更多内容
上文提到所有被配置的设备都接收每个事务中的电子信号。
这几乎是正确的,但一个真正的程序员应该了解更详细的内容。
当一个USB设备第一次接入时,它使用默认地址(碰巧是0,你不必知道)响应。
然后,某个电子信号通知总线驱动程序有一个新设备插入总线,于是总线驱动程序找出一个未用的设备地址并发送一个控制事务告诉“0号设备”什么才是它的真实地址。
这之后,设备就放弃使用默认地址0,而用真实地址来应答。
另一些细节涉及到低速设备。
低速设备的电气特征使它在面对传输率是其八倍的总线时会发生信号混乱。
另外,低速设备的电缆没有电磁屏蔽,遇到高速信号会产生电子干扰。
结果,低速设备在大部分时间并不连接到总线上。
当总线进行高速传输时,hub就隔离低速设备。
当主机需要与低速设备通信时,它就发送一个特殊的前导包把总线临时切换到低速操作,所以,低速设备只能看到低速事务,而高速设备能看到所有事务。
端点的状态
一般,端点可以进入图11-6中所示的任何一种状态。
在空闲状态中,端点准备处理主机发起的新事务。
在忙碌状态中,端点忙于处理手中的事务而不能接受新事务。
如果主机试图向一个忙端点发起新事务(不是控制端点,下段描述),设备将用NAK握手包响应,主机将在以后重发刚才的包。
如果设备发现自己内部出现错误(不包括传输错误),设备将在当前事务中发送一个STALL握手包然后进入停止状态。
控制端点在接到新事务时会自动从停止状态恢复,但其它三种端点必须由主机明确发送一个清除特征(feature)控制请求后才能从停止状态中恢复。
图11-6.端点的三种状态
控制传输
控制传输在主机和控制端点之间传送控制信息。
例如,在操作系统配置USB设备过程中,有一步就是用控制传输从物理设备中读出各种描述符(descriptor),配置过程的另一步是利用控制传输设置一种可能的配置并使能一个或多个接口。
控制传输是一种纠错传输,在遇到传输错误时重试三遍,如果错误仍存在就放弃传输并向上层软件报告错误。
如表11-1中所指出的,控制端点所能指定的最大数据传输长度为8、16、32、64字节。
一个单独的事务可以包含少于最大数据传输长度的数据但不能多于。
控制事务在USB中具有最高优先级。
设备必须处理控制事务。
此外,总线驱动程序为控制事务保留了10%的带宽。
对于轻量级的负载,主机能确保在1毫秒内完成一个控制事务。
对于重量级的负载,未完成的控制传输将被强制到下一帧中传输,因此会产生一些延迟。
每个USB设备至少应有一个编号为0的控制端点以响应控制事务的输入输出。
严格地讲,端点应属于配置,但端点0是一个例外,因为它是设备默认控制管道的终点。
端点0甚至在设备被配置前就被激活而不管其它端点是否有效。
除了端点0,一个设备没有必要拥有另外的控制端点(尽管USB规范中允许有这种可能),因为端点0对于大部分控制请求都可以很好地完成。
如果你定义了一个厂商专用的请求并且该请求不能在一帧中完成,你应该创建额外的控制端点以防止设备接收器被新事务抢先。
每个控制事务包括一个SETUP令牌,之后可以带一个可选的数据阶段和一个握手阶段,在握手阶段设备会发出ACK包或者STALL包,或者根本就不响应,如图11-7。
设备必须在任何时间都能接受控制传输,并且不能用NAK响应控制端点忙。
向控制端点发送一个无效请求将导致STALL响应,但当设备再次接收到一个SETUP包时会自动清除停止状态。
这个特殊的STALL在USB规范(8.5.2.4段)中被称为协议停止(protocolstall)。
图11-7.控制传输中的三个阶段
开始控制传输的SETUP令牌由8个字节组成,如图11-8所示。
在下面这个和后面的数据结构图中,我按照数据在USB导线上的传输顺序列出其中的数据字节,但是每个字节中的位是以高位开始。
在传输线上的字节传输是从低位开始的,但主机软件和设备固件通常以相反的方向使用字节。
Intel计算机和USB总线协议使用小结尾的数据表达,即低位字节占用低地址。
许多USB芯片集包括AnchorChips芯片集使用8051微处理器,这个处理器使用大结尾的数据表达。
固件程序设计者必须注意这一点。
图11-8.SETUP令牌的内容
SETUP令牌的第一字节指出信息流的方向、请求的类型、和接收控制传输的实体类型。
请求类型有标准类型(由USB规范定义)、类类型(由USB工作组定义的一类设备),和厂商类型(由设备制造者定义)。
控制请求可以发到整个设备、一个指定接口、一个指定的端点,或者到设备上的厂商专有实体。
SETUP令牌中的第二字节指出具体的请求,其类型由第一字节指出。
表11-2列出了当前定义的标准请求。
对于类专用请求,应参考对应设备类的说明(http:
//www.usb.org/developers/)。
设备制造者可以自由定义自己专用的请求代码。
例如,AnchorChips使用请求代码A0h表示从主机下载固件程序。
注意
改变端点状态的控制请求将发往控制端点而不是发往被改变状态的端点。
表11-2标准设备请求
请求代码
符号名
可能的接受者
GET_STATUS
获得状态信息
任何
1
CLEAR_FEATURE
清除一个双态特征
2
(保留)
3
SET_FEATURE
设置一个双态特征
4
5
SET_ADDRESS
设置设备地址
设备
6
GET_DESCRIPTOR
取设备、配置,或串描述符
7
SET_DESCRIPTOR
设置一个描述符(可选)
8
GET_CONFIGURATION
取当前配置索引
9
SET_CONFIGURATION
设置一个新的当前配置
10
GET_INTERFACE
取当前的alt接口索引
接口
11
SET_INTERFACE
使能alt接口设置
12
SYNCH_FRAME
报告同步帧号
(等时)端点
SETUP包中其余的内容包括一个value代码(其含义与具体的请求相关)、一个index值(当控制请求寻址端点或接口时,index值指出具体地址)、一个length域(指出控制事务的数据阶段要传输的数据量。
为0表示该事务没有数据阶段)。
我并不想详细描述各种控制请求的细节;
你可以参考USB规范的第9.4段。
但我确实想简要地讨论一下设备特征(feature)这个概念,USB认为,属于设备的任何可寻址实体都可以有1个特征位。
已有两个特征实现了标准化。
DEVICE_REMOTE_WAKEUP特征——属于设备整体的特征,它指出当外部事件发生时设备能否用这个能力(如果有)唤醒计算机。
主机软件(尤其是总线驱动程序)通过SET_FEATURE或CLEAR_FEATURE命令可以允许或禁止这个特征,用value代码为1来指出允许唤醒特征。
DDK中用符号名USB_FEATURE_REMOTE_WAKEUP代表这个特征码。
ENDPOINT_HALT特征——属于单个端点的特征,指出端点是否处于停止状态。
主机软件可以向端点发送SET_FEATURE命令并且value为0(指定ENDPOINT_HALT)来强制端点进入停止状态。
当然,管理端点的设备固件也能使端点进入停止状态。
如果端点被固件设为停止状态,主机软件(总线驱动程序)也可以发送一个value为0的CLEAR_FEATURE命令清除该端点的停止状态。
DDK使用符号名USB_FEATURE_ENDPOINT_STALL代表这个特征码。
USB规范中并没有为厂商使用的设备或端点的特征代码规定范围。
为了避免后来的标准化问题,你应该避免定义设备级或端点级的特征,而仅应该定义自己的厂商类型控制事务。
在本章后面我将演示一个例子驱动程序(FEATURE),它能控制AnchorChips开发板上的7段LED显示。
我在这个例子中定义了一个编号为42的接口级特征。
(USB现在为电源管理定义了一些接口级特征,所以你不应效仿我的例子,除非你想知道特征是怎样工作的)
尽管AnchorChips(现在是CypressSemiconductor)的EZ-USB可以容易地从驱动程序下载新固件,但你不应在产品级设备上使用这个特征。
你需要开发一个“Loader”驱动程序和一个function驱动程序,前者用于下载固件到USB设备,后者用于管理设备。
不幸的是,如果计算机进入节能状态,操作系统也把USB总线置入节能状态,设备的固件内容将丢失。
当回到正常电源状态时,系统卸载function驱动程序并重新装载“Loader”驱动程序,Loader再次下载固件并重新装载function驱动程序。
而节能前的function驱动程序的状态信息将全部丢失,所以当你使用这个芯片时应考虑把固件放到EEPROM上。
批量传输
批量(bulk)传输能在主机和批量端点间一次传输最多64字节的数据。
就象控制传输一样,批量传输是纠错传输,不同的是批量传输没有任何延迟保证。
如果主机发现帧中除了预定带宽外还有剩余,它就把等待的批量传输送往总线。
图11-9显示了组成批量传输的各个阶段。
传输开始于表明传输方向的IN或OUT令牌,这些令牌同时还指定目标设备和端点。
对于输出事务,后面是一个数据阶段,把数据从主机送到设备,最后在握手阶段设备向主机提供状态反馈。
如果端点正忙不能接收新数据,它就在握手阶段发出一个NAK包,主机以后会重试该事务。
如果端点处于停止(STALL)状态,它就在握手阶段发出一个STALL包,主机在重试前必须清除端点的停止状态。
如果端点正确地接收并处理了数据,将在握手阶段返回一个ACK包。
最后一种情况是端点因为某种原因没有正确地接收数据并且在握手阶段也没有发出应答包,主机将检查端点是否应答,并且自动重试三次原事务。
IN令牌后面是一个批量输入传输。
如果端点将数据准备好,设备将把数据发往主机,主机或者回应一个ACK包指出数据无误地接收,或者保持沉默以指出发生了某种错误。
如果主机查出一个错误,ACK的缺发将使设备数据保持有效,之后主机将重试输入操作;
如果端点忙或停止,设备将会在数据阶段发出NAK或STALL握手包而不是数据。
NAK指出主机应在以后重试该输入操作,STALL需要主机先清除端点的停止特征再重试输入操作。
图11-9.批量传输和中断传输中的阶段
中断传输
中断(interrupt)传输在总线操作和涉及设备方面上几乎与批量传输完全相同。
它能把最大64字节的数据无误地在主机和中断端点间传输。
中断传输和批量传输仅有的不同是它必须考虑延迟。
中断端点需指定一个范围在1-255毫秒内的询查周期。
主机保留足够的带宽以确保在指定频率上直接向中断端点发出IN或OUT事务。
注意USB设备不生成异步中断,它们总是响应循检,Microsoft的主控制器驱动程序把中断端点描述符中指定的循检周期简化为不大于32的2的幂。
例如,一个指定循检周期为31毫秒的端点实际上是以16毫秒进行循检。
指定周期在32-255毫秒之间的循检实际上是以32毫秒为循检周期。
等时传输
等时(isochronous)传输可以在一个总线帧内最多传输1023字节数据。
因为等时传输有周期保证,因此特别适用于时间敏感的数据传输,如音频信号,但这种周期保证是有代价的,等时传输在数据出错时不会自动重试。
USB设计者假定等时数据流的接收者允许偶尔的数据丢失。
等时传输由IN或OUT令牌阶段后跟一个数据阶段组成。
因为不进行数据纠错,所以等时传输没有握手阶段。
如图11-10。
图11-10.等时传输中的阶段
主机为等时传输和中断传