USB作为目前计算机的最广泛使用的外设接口,让我们变得越来越便利。
USB的设计理念与传统的外设接口设计有很大区别,一般的外设接口设计仅仅规定通信过程的实现,很少涉及到通信内容本身。而USB协议则对通信内容的解析有很多规定,因此其协议内容比一般的协议都复杂,即使你理解TCP/IP协议,但是当面对USB协议时,也会感觉一头雾水。
正因为USB实现目标是多种不同类型和速度设备的连接,因此其灵活性也导致了其复杂性,当我刚开始接触USB的时候,也感觉很多技术文档不知所云。根本就不知道USB是个什么概念。经过大量的资料阅读和测试,才大概了解了其基本原理,走了很多弯路,有过很多错误观念。
1) 一般计算机的外设接口可以描述如下
主机系统<---->主机控制芯片 <------------------电缆--------------> 设备通信芯片 <------>设备处理器
程序负责写入数据到芯片缓冲区,然后发送控制命令给芯片,由芯片负责发送一个数据,当芯片接收到一个数据会产生中断信号通知程序处理收到的数据。
在主机端,实现与芯片交互的程序就是设备驱动或总线驱动程序,在设备端,一般用单片机程序控制通信芯片实现数据通信。
2)在USB的外设通信原理中,依然没有什么新的技术,一样采用上述的硬件结构。
3)但是,USB实现的是外设通用接口,无论外设的类型和速度怎样(当然速度是有限制的),都可以通过这个接口接入系统。在以前的接口中,如键盘、鼠标、硬盘均有特定的接口,也有特定的驱动程序来实现数据的交互。一个驱动对应一个接口(外设)。而USB则是一个接口对应的设备个数是不确定的,类型也是不确定的,因此其对应的驱动程序个数不定,驱动程序也不定,这就要求操作系统能动态的检测设备的类型,动态地加载驱动程序。
主机系统
|
主机USB通信控制器
USB 根集线器HUB
/ | \
设备1 设备2 集线器HUB1
很多设备可以连接到同一个集线器上,这就类似以太网的集线器。我们在电脑上看到很多USB接口,它们可能连接到同一个USB主控制芯片。
因为多个设备连接到同一个接口, 设备通信就可能发生冲突,因此必须有一套机制保证数据传输的协调。
4)与以太网的对等通信机制不同,USB是用来连接计算机的外部设备的,因此其通信过程存在主从关系。
设备永远只能是准备数据,不能主动发送数据到主机。
主机驱动程序会轮流读取各个设备的状态,从状态中判断各个设备是否有数据要传给主机。
5)一个外部设备在主机系统中均有一个对应的驱动程序。而设备驱动程序是调用更加底层的USB总线驱动程序与外设通信的。
用户程序向设备写入一个数据的过程(如一个1024字节的数据包):
<1> 数据首先被转发给设备驱动程序,其实就是通过很多次的调用,最终会调用到设备驱动程序中的发送数据的函数。
<2> 设备驱动程序是负责与一个具体的设备(如鼠标、U盘)通信的业务逻辑处理的。
设备驱动程序要发送一个数据给设备,首先把一个大的数据按照USB容许的最大数据包长度进行分解,然后每次发送一个数据包给设备。
例如设备的端点一次最大容许接收512字节,那么就被分解成两个数据包。
设备驱动程序每次调用USB主控制器驱动程序发送一个数据包。
<3> USB主控制器驱动是负责管理连接到本控制器的所有设备,并协调其通信过程的。USB主控驱动程序把数据包发送给实际的设备,数据包中包含了设备编号。
主控制器驱动程序发送一个数据包给设备的时候,是占用一个事务周期的,就是发送数据的过程中是不能去做其他事情的。
发送一个数据包占用一个总线时间片,在这个时间片里,总线全力处理这个事务(发送数据包)。
<4> 主控制器驱动程序发送一个512字节数据包给设备的过程,又被分解成三个阶段:
首先是主机发送一个命令(令牌包)给设备,告诉设备主机准备发送数据了。
紧接着主机发送512字节数据包给设备。
设备如果正常接收到,就返回一个信号(握手包)告诉主机。主机收到这个信号后就可以做其他事情了。
上面的三个阶段是连续的,中间不能穿插其他的总线通信操作。
驱动程序从设备读一个数据的过程:
<1> 首先向设备发送一个命令包,命令包格式必须遵从USB协议规定。
<2> 设备收到命令数据包后,从中解析出主机的命令意图,发现是要求本设备上传数据。设备向芯片写入数据,并写入发送命令,数据从设备传输到主机。
<3> 主机收到数据后,向设备输出一个应答包,告诉设备数据是否成功接收。
主机要从设备获得某些特定的数据,获得U盘的一个扇区数据:
<1>主机首先要告诉设备准备好哪个扇区的数据到设备的USB芯片中,USB设备从U盘的存储区找到扇区并把数据拷贝到USB芯片中是需要时间的。
第一个事务过程,向设备输出读扇区数据的命令。
a. 向设备输出一个令牌包,告诉设备准备接收数据。
b. 向设备输出一个数据包,数据内容为扇区号和读扇区命令。
c. 设备收到数据后,回答一个握手包(ACK)给主机。
<2>主机在完成第一个事务后,就可以做其他事情了。在做其他事情时,偶尔检查下设备是否准备好数据(向设备发一个IN包,设备如果回答NAK表示没准备好)。
<3> 设备准备好数据后,就可以进入第二个事务。
a. 向设备输出一个IN令牌包,告诉设备准备传输数据。
b. 设备输一个数据包,数据内容为扇区数据。
c. 主机收到数据后,回答一个握手包(ACK)给设备。