USB是主从模式的传输总线,只有当主机提出请求时,设备才可以进行数据传输。这种数据传输模式和通信中的蜂窝数据传输有点类似,只有当基站(BS)向终端(CS)发送读写请求时,终端才会发送或者接收数据。主从式的数据传输可以很好的控制传输带宽。USB分为四种传输模式:控制传输、中断传输、同步传输和批量传输。这四种传输模式对总线带宽需求是不一样的,因此,USB总线必须实现一种机制,可以对总线带宽进行调度控制,而主从模式就是最佳选择。

USB总线的调度机制是如何实现的呢?我们在开发USB设备驱动、主控制器驱动、设备节点的时候需要如何考虑调度机制呢?前年的时候,我参与开发wimax芯片。芯片流片之后,发现我们的性能就是不如竞争对手,并且在持续数据传输的过程中,性能不稳定。后来发现这个问题与数据丢包相关,BS在调度CS的时候,由于CS响应存在问题,导致一些数据报文丢失 ,从而导致传输性能不稳定并且总体性能不高。主从模式的数据传输,如果调度机制实现不佳,将会影响性能。由此,我们在研究USB的时候,很有必要对USB调度机制进行详细分析,机制或者实现不佳,都会严重影响到数据传输性能。
 
USB调度机制是在USB主机控制器芯片内部实现的,主机驱动程序通过OHCI/EHCI/UHCI之类的标准实现与控制器之间的数据交互。因此,在开发主机控制器或者驱动程序的时候需要详细了解OHCI之类的协议规范。这里简要分析一下OHCI规范。
 
OHCI定义了端点描述(ED)和传输描述(TD)两大结构,ED描述了一个端点的数据传输,TD描述了一次传输操作。主机控制器会为每个端点分配端点描述符。端点描述符会为主控制器包含足够的信息进行数据传输。端点描述符包含的信息如下:
1,最大报文大小
2,端点地址
3,端点速度
4,数据流方向
 
每次数据传输都会被抽象成传输描述符,每个传输描述符都会连接到指定的端点描述符上。传输描述符包含了共享缓存区(数据缓冲区)的地址。
 
ED和TD之间的关系可以描述如下:

在主机控制器中,会遵循OHCI的规范定义一系列寄存器,通过这些寄存器,驱动程序可以告诉主机控制器ED和TD所在的内存位置。这样,一旦驱动程序提交了TD之后,主机控制器可以通过这个地址对这次传输进行调度。驱动程序和主机控制器之间的接口关系如下图所示:

 

USB数据传输可以划分为实时传输和非实时传输两大类。中断传输和同步传输属于实时传输;批量传输和控制传输属于非实时传输。实时传输的特点是对占用带宽的实时性要求比较高,这些任务需要及时地得到调度,为此,主机控制器对实时类传输进行了特殊处理。其定义了HCCA寄存器指向实时传输的请求,并且对中断传输请求的调度进行了树状划分。

 

对调度时间要求不同的ED位于调度树的不同层次,位于树顶层的节点每1ms调度一次,下一层节点2ms调度一次,依次类推。因此,对于不同调度需求的传输请求,驱动程序可以将请求挂载到不同的ED上。
 
通过上述描述,我们可以得出结论,主机控制器驱动程序只需要将设备驱动提交的请求转换成TD,并且挂载到对应的ED上,然后触发主机控制器实现对TD的调度处理。在这里,我们可以看出,主机控制器和驱动程序是共享内存的,因此,需要一定的锁机制进行保护。其实,这种机制和我以前参与研发的wimax基带处理器的思路是一样的,基带处理器需要处理PHY和ARM处理器之间的数据交互问题,我们同样采用了共享内存的方法,PHY接收解析数据报文之后放入共享内存,ARM处理器通过访问共享内存获取数据报,然后进行上层协议的解析处理。
 
这里,可以得出USB主机控制器一个很重要的功能是实现TD调度,那么其内部是如何实现的呢?
 
一个比较简单的方法是在主机控制器内部嵌入处理器,通过软件的方法实现TD调度,在opencores开源项目中,有一个OHCI-USB控制器的项目,该实现方案就是采用AVR单片机实现USB主机控制器,可以实现12Mbps/1.5Mbps的数据传输,该芯片的内部架构如下所示。

 

USB调度机制是主从USB总线的基础,以后会对其细节技术进行详细阐述。