1,USB的简单介绍
1.1概念
看到USB也许第一个会联想到U盘,认为USB就是U盘。U盘是USB中的其中一种外设。USB(universal serial bus)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在PC领域的接口技术。
1.2常见的USB设备
常见的USB设备:U盘、鼠标、MP3、移动硬盘、数码相机、键盘、游戏杆、USB摄像头、USB打印机、USB扫描仪、USB话筒、USB网卡、USB显示器等。
1.3 USB优缺点
优点:容易使用、方便携带、即插即用、支持热插拔、传输速度快和具有很强的可扩展性等。
缺点:传输距离短,开发调试难度大。
1.4 USB拓扑结构
常见概念的区分
USB主控制器(host controller)、根集线器(root hub)和集线器(USB hub)
Host controller:主要负责数据处理。
Root Hub:提供主控制器和设备连接的接口与通路。
USB Hub:扩展USB口的数量,获得更多的USB口。但不能扩展出更多的带宽,带宽是共享一个USB主控制器的。所以当在USB Hub上接入多个U盘去拷贝东西时,速度是比较慢的。
每个主控制器下有一个根集线器,根集线器通常具有一个或者几个USB口。主控制器有几个,根集线器就有几个。
下图为USB的拓扑结构(图片来自USB2.0协议):
USB协议对集线器的层数有限制,USB1.1最多4层,USB2.0最多6层。理论上一个USB主控制器最多连接127个设备,因为USB协议规定每个USB设备有7bit的地址(地址0是保留给未初始化的设备使用的)。
2,USB协议的版本:
USB的协议版本有:USB1.0、USB1.1 、USB2.0和USB3.0等
USB版本 | 理论最大传输速率 | 速率称号 | 最大输出电流 | 推出时间 |
USB1.0 | 1.5Mbps(192KB/s) | 低速(Low-Speed) | 5V/500mA | 1996年1月 |
USB1.1 | 12Mbps(1.5MB/s) | 全速(Full-Speed) | 5V/500mA | 1998年9月 |
USB2.0 | 480Mbps(60MB/s) | 高速(High-Speed) | 5V/500mA | 2000年4月 |
USB3.0 (USB 3.1Gen1 / USB 3.2 Gen 1×1) | 5Gbps(500MB/s) | 超高速(Super-Speed) | 5V/900mA | 2008年11月 / 2013年12月 / 2017年7月25日 |
USB 3.1Gen 2(USB 3.2 Gen 2×1) | 10Gbps(1280MB/s) [2] | 超高速+(Super-speed+) | 20V/5A | 2013年12月/ 2017年7月25日 |
USB 3.2 Gen 2×2 | 20 Gbps (2.5 GB/s) [3] |
|
| 2017年7月25日 |
注意:USB2.0并不是高速设备的代名词,因为USB2.0协议对设备的高速模式并不是强制的,而是可选的。如PDIUSBD12(USB芯片型号),是符合USB2.0协议的,但是不支持高速模式,只支持12Mb/s的全速模式。和USB芯片也有关系的,不要认为支持USB2.0协议就一定具有高速模式。
注意:USB只遵从主从模式,即设备与设备、主机与主机不能互连。
为了解决这个问题,就有了 USB OTG(on the go),做法是:同一个设备在不同的场合下可以在主机与从机之间切换。USB OTG比USB多了一个ID引脚,ID接地,充当USB Host;ID悬空,充当USB Device。例如:手机通过USB OTG接入电脑,此时手机就是USB Device,电脑是USB Host;U盘接入手机,此时手机就是USB Host,U盘是USB Device。
至于USB OTG如何在主机和从机间切换,这里就不做介绍,这个涉及到主机谈判协议HNP(Host Negotiation Protocol),是通过HNP去实现的。
3,USB主机如何检测到设备的插入?
根据D+、D- 的高低电平来检测设备的插入。
在USB集线器的下游端口D+和D-上,分别接了一个15kΩ下拉电阻;在设备端,D+或D-上接了一个上拉电阻1.5kΩ,低速设备的上拉电阻接在D-上,高速和全速设备的上拉电阻接在D+上。在当没有设备插入时,输入端的电平就被这两个下拉电阻拉到了低电平。当有设备插入时,接了上拉电阻的数据线,电平被拉高,根据被拉高的是D+还是D- 来判断是低速设备还是全速设备。
USB高速设备显示被识别成全速设备,然后通过集线器和设备两者的确认,再切换到高速模式。高速模式下,是电流传输,这时要将D+上的上拉电阻断开。
4,USB描述符介绍
USB主机如何知道插入的USB是个什么样的设备,这个设备有什么功能呢?
答:USB描述符
4.1 USB描述符的类型
USB1.1协议中定义的标准描述符有:设备描述符(Device Descriptor)、配置描述符(Configuration Descriptor)、接口描述符(Interface Descriptor)、端点描述符(Endpoint Descriptor)、字符串描述符(String Descriptor)
USB2.0又新增了两个新的标准描述符:Device Qualifier Descriptor、Other Speed Configuration Descriptor
还有一些特殊的描述符,如类特殊描述符(HID描述符、音频接口描述符)、厂商自定义的描述符等。
USB描述符类型及编号:
Descriptor Types | Value |
DEVICE | 1 |
CONFIGURATION | 2 |
STRING | 3 |
INTERFACE | 4 |
ENDPOINT | 5 |
DEVICE_QUALIFIER | 6 |
OTHER_SPEED_CONFIGURATION | 7 |
INTERFACE_POWER | 8 |
The INTERFACE_POWER descriptor is defined in the current revision of the USB Interface Power Management Specification(参考USB2.0协议9.3)
这个电源接口描述符是在USB接口电源管理规范的2.0版本中定义的。
项目中usb.h(这里是指本人在公司做的项目)中有USB描述符的定义:
UB代表1个字节,UH代表2个字节;
4.1.1 设备描述符
/* USB device descriptor */
typedef struct
{
UB bLength; /* descriptor length 描述符长度(18字节) */
UB bDescriptorType; /* device descriptor 描述符类型(0X01) */
UH bcdUSB; /* USB specification release number USB协议版本*/
UB bDeviceClass; /* device class 设备类代码 */
UB bDeviceSubClass; /* device sub class 设备子类代码 */
UB bDeviceProtocol; /* device protocol 设备协议 */
UB bMaxPacketSize0; /* max packet size 端点0支持的最大数据包*/
UH idVendor; /* vendor id 厂商ID */
UH idProduct; /* product id 产品ID */
UH bcdDevice; /* device release number 设备版本号*/
UB iManufacturer; /* manufacturer index 厂商字符串索引*/
UB iProduct; /* product index 产品字符串索引*/
UB iSerialNumber; /* serial number index 设备序列号索引*/
UB bNumConfigurations; /* number of configuration 可配置数量*/
} usbDeviceDescriptor;
bcdUSB:该设备使用的USB协议版本,长度为2个字节。是用BCD码表示的,例如USB2.0协议就是0x0200,因为USB协议中是采用小端模式,地址由小到大,低字节放在低地址。即USB2.0协议拆成BCD码两个字节就是0x00和0x02
bDeviceClass:设备使用的类代码,由USB协会规定。对于大多数标准的USB设备类,通常设置为0,在接口描述符中的bInterfaceClass中指定接口所实现的功能。当bDeviceClass为0时,下面的bDeviceSubClass也必须为0。如果bDeviceSubClass为0XFF,表示是厂商自定义的设备类。
Class code (assigned by the USB-IF).
If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently.
If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate
interfaces.
If this field is set to FFH, the device class is vendor-specific(USB2.0 chapter 9.6)
(如果此域的值为0则一个设置下每个接口指出它自己的类,各个接口各自独立工作。如果此域的值是1~FEH之间,则设备在不同的接口上支持不同的类。并且这些接口可能不能独立工作。此值指出了这些接口集体的类定义。如果此值设为FFH,则此设备的类由厂商定义。)
bDeviceSubClass:子类代码,子类代码的值有bDeviceClass字段决定。如果bDeviceClass字段为0,bDeviceSubClass也必须为0;如果bDeviceClass不是0xFF时,bDeviceSubClass全部保留给USB-IF分配。
Subclass code (assigned by the USB-IF).
These codes are qualified by the value of the bDeviceClass field.
If the bDeviceClass field is reset to zero, this field must also be reset to zero.
If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
bDeviceProtocol:设备使用的协议,协议代码由USB协会规定。协议码的值视bDeviceClass 和 bDeviceSubClass 的值而定。如果bDeviceClass为0,则bDeviceProtocol也为0。
如果设备支持设备类相关的协议,此码标志了设备类的值。如果此域的值为零,则此设备不支持设备类相关的协议,然而,可能它的接口支持设备类相关的协议。如果此域的值为FFH,此设备使用厂商定义的协议。
bMaxPacketSize0:端点0最大数据包的长度,取值可以为:8、16、32、64。
idVendor:厂商ID,由USB协会分配,不能随意使用,要版权费的。主机通常靠厂商ID、产品ID和设备序列号来安装和加载驱动
idProduct:产品ID,由生产厂商根据产品来编号的,比较自由。
bcdDevice:设备版本号。当同一个产品升级后(如修改了固件增加了某些功能),可以通过修改设备的版本号来区别。
iManufacturer:厂商字符串索引。该值为0时,表示没有厂商字符串。主机获取设备描述符时,会将索引值放在wValue的第一个字节中,用来选择不同的字符串。
iProduct:产品字符串索引。该值为0时,表示没有产品字符串。当第一次插入一个USB设备,电脑右下角显示一个对话框,显示发现新硬件,并且会显示该设备的名称。这些信息就是从产品字符串中获得的。
iSerialNumber:设备序列号字符串索引值。该值为0时,表示没有序列号字符串。一般主机会结合VID、PID和设备序列号来区分不同的设备。同时连接有相同VID、PID和设备序列号的设备,会导致设备无法正确识别。设备序列号最后是唯一的。
bNumConfigurations:可配置数。表示该设备有多少中配置,每种配置有一个配置描述符,主机通过发送配置来选择某一种配置。
bDeviceClass类可查下表:
值(十进制) | 值(十六进制) | 说明 |
---|---|---|
0 | 0X00 | 接口描述符中提供类的值 |
2 | 0X02 | 通信类 |
9 | 0X09 | 集线器类 |
220 | 0XDC | 用于诊断用途的设备类 |
224 | 0XE0 | 无线通信设备类 |
255 | 0XFF | 厂商定义的设备类 |
4.1.2 配置描述符
/* USB configuration descriptor */
typedef struct
{
UB bLength; /* descriptor length该描述符的长度(9字节)*/
UB bDescriptorType; /* configuration descriptor描述符类型(0x02)*/
UH wTotalLength; /* descriptor total length配置描述符集合总长度*/
UB bNumInterfaces; /* number of interface该配置支持的接口数*/
UB bConfigurationValue; /* configuration value该配置的值*/
UB iConfiguration; /* configuration index该配置的字符串索引*/
UB bmAttributes; /* configuration characteristics 设备的属性*/
UB MaxPower; /* maximum power consumption 设备需要的电流(单位:2mA)*/
} usbConfigurationDescriptor;
wTotalLength:表示整个配置描述符集合的总长度,包括配置描述符、接口描述符、类特殊描述符(如果有的话)和端点描述符。
bNumInterfaces:该配置所支持的接口数量。一般功能单一的设备只有一个接口(如鼠标),复合设备则有多个接口(音频设备)。
bConfigurationValue:该配置的值。当主机发起设置配置请求时,会发送一个配置值,如果某个配置的bConfigurationValue与它相等时,就表示该配置被激活。通常一个USB设备可以支持多个配置,bConfigurationValue就是每个配置的标识。
iConfiguration:该配置的字符串索引值。这个值为0时,表示该配置没有字符串。
bmAttributes:描述设备的特性。D7是保留位,必须设为1;D6表示供电方式,当D6为1时,表示设备是自供电的;当D6为0时,表示设备是总线供电的。D5表示是否支持远程唤醒,当D5为1时,支持远程唤醒。D4~D0保留位,设置为0
MaxPower:表示当设备完全运行时,USB设备在此特定配置中从总线获取的最大电流量,单位为2mA。如需要100mA,则此值为50。
4.1.3 接口描述符
/* USB interface descriptor */
typedef struct
{
UB bLength; /* descriptor length 描述符长度(9字节)*/
UB bDescriptorType; /* interface descriptor 描述符类型(0x04)*/
UB bInterfaceNumber; /* number of this interface 接口的编号*/
UB bAlternateSetting; /* value for alternate setting 可选的设置*/
UB bNumEndpoints; /* number of endpoints 端点数量*/
UB bInterfaceClass; /* interface class code 接口类*/
UB bInterfaceSubClass; /* interface sub class code 接口子类*/
UB bInterfaceProtocol; /* interface protocol code 接口协议*/
UB iInterface; /* interface index 接口的字符串索引*/
} usbInterfaceDescriptor;
bInterfaceNumber:该接口的编号。当一个配置有多个接口时,每个接口的编号都相同。从0开始依次递增对一个配置的接口进行编号。
bAlternateSetting:可选设置的编号。从0开始依次递增,这个字段很少使用,设为0
bNumEndpoints:该接口使用的端点数量(不包括0端点)。如果为0,则表示没有非0端点,只能使用默认的控制端点。
bInterfaceClass、bInterfaceSubClass、bInterfaceProtocol:和设备描述符中的意义类似,通常在接口中定义设备的功能,在设备描述符中将类、子类和协议字段的值设为0。
iInterface:描述该接口的字符串索引值。该值为0,表示没有字符串。
对于bInterfaceClass字段,表示接口所属的类别,USB协议根据功能将不同的接口划分成不同的类,其具体含义如下表所示:
值(十六进制) | 类别 |
0X01 | 音频类 |
0X02 | CDC控制类 |
0X03 | 人机接口类(HID) |
0X05 | 物理类 |
0X06 | 图像类 |
0X07 | 打印机类 |
0X08 | 大数据存储类 |
0X09 | 集线器类 |
0X0A | CDC数据类 |
0X0B | 智能卡类 |
0X0D | 安全类 |
0XDC | 诊断设备类 |
0XE0 | 无线控制器类 |
0XFE | 特定应用类(包括红外的桥接器等) |
0XFF | 厂商定义的设备 |
4.1.4 端点描述符
/* USB endpoint descriptor */
typedef struct
{
UB bLength; /* descriptor length描述符长度(7字节)*/
UB bDescriptorType; /* endpoint descriptor描述符类型(0x05)*/
UB bEndpointAddress; /* endpoint address 该端点的地址*/
UB bmAttributes; /* endpoint attributes该端点的属性*/
UH wMaxPacketSize; /* max packet size该端点支持的最大包长度*/
UB bInterval; /* interval for polling endpoint端点的查询时间*/
} usbEndpointDescriptor;
bEndpointAddress:表示端点地址。最高位D7为该端点的传输方向,1为输入(设备到主机),0为输出(主机到设备)。D3~D0是端点号,D6~D4保留,设为0。
bmAttributes:该端点的属性。D1~D0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输。如果该端点是非等时传输的,那么D7~D2为保留值,设为0。如果该端点是等时传输的,则D3~D2表示同步类型,0为无同步,1为异步,2为适配,3为同步;D5~D4表示用途,0为数据端点,1为反馈端点,2为暗含反馈的数据端点,3是保留值,D7~D6保留。
wMaxPacketSize:该端点所支持的最大包长度。对于全速模式和低速模式,D10~D0表示端点的最大包长,其他位保留为0。对于高速模式,D12~D11为每个帧附加的传输次数,0为不附加(即每微帧传输一个),1为附加1个,2为附加两个,3为保留。其他位保留设为0。
bInterval:表示该端点的查询时间。对于中断端点,表示查询的帧间隔数。详细请参考USB2.0
4.1.5字符串描述符
/* USB string descriptor */
typedef struct
{
UB bLength; /* descriptor length */
UB bDescriptorType; /* string descriptor */
UH bString[1]; /* UNICODE encoded string */
} usbStringDescriptor;
如下两个描述符项目中暂时没有用到
/* USB device quarifier descriptor */
typedef struct
{
UB bLength; /* descriptor length */
UB bDescriptorType; /* device quarifier descriptor */
UH bcdUSB; /* USB specification release number */
UB bDeviceClass; /* device class */
UB bDeviceSubClass; /* device sub class */
UB bDeviceProtocol; /* device protocol */
UB bMaxPacketSize0; /* max packet size */
UB bNumConfigurations; /* number of configuration */
UB bReserved; /* reserved for future use */
} usbDeviceQualifierDescriptor;
/* USB other speed configuration descriptor */
typedef struct
{
UB bLength; /* descriptor length */
UB bDescriptorType; /* other speed configuration descriptor */
UH wTotalLength; /* descriptor total length */
UB bNumInterfaces; /* number of interface */
UB bConfigurationValue; /* configuration value */
UB iConfiguration; /* configuration index */
UB bmAttributes; /* configuration characteristics */
UB MaxPower; /* maximum power consumption */
} usbOtherSpeedConfigurationDescriptor;
根据项目,插入相关USB设备,log输出如下:
大容量存储设备的接口描述符中的类和子类:
[HMI]hmi_fsa_usb_getInterfaceDescriptorFromDeviceAddress(732): bInterfaceClass = 8
[HMI]hmi_fsa_usb_getInterfaceDescriptorFromDeviceAddress(733): bInterfaceSubClass = 6
鼠标接口描述符中的类和子类:
[HMI]hmi_fsa_usb_getInterfaceDescriptorFromDeviceAddress(732): bInterfaceClass = 3
[HMI]hmi_fsa_usb_getInterfaceDescriptorFromDeviceAddress(733): bInterfaceSubClass = 1
[HMI]hmi_fsa_usb_getInterfaceDescriptorFromDeviceAddress(732): bInterfaceClass = 3
[HMI]hmi_fsa_usb_getInterfaceDescriptorFromDeviceAddress(733): bInterfaceSubClass = 55
详细的描述符介绍可参考USB 协议2.0第9章第6节。
4.2 USB描述符之间的关系
USB描述符之间的关系:一个USB设备只有一个设备描述符。设备描述符决定了该设备有多少种配置,每种配置都有一个配置描述符;配置描述符中又定义了该配置有多少个接口,每个接口都有一个接口描述符;接口描述符中又定义了该接口有多少个端点,每个端点都有一个端点描述符;端点描述符定义了端点的类型、大小等。如果有HID描述符或音频接口描述符,则在接口描述符的后面。一个设备至少要包含设备描述符、配置描述符和接口描述符,如果USB设备没有端点描述符,则它仅仅用默认管道与主机进行数据传输。
USB描述符之间的关系是一层一层的,设备描述符、配置描述符、接口描述符、端点描述符
如下图所示:
主机在获取描述符时,首先获取设备描述符,再获取配置描述符,然后根据配置描述符中的配置集合总长度,一次将配置描述符、接口描述符、类特殊描述符(如果有)、端点描述符一次读回。注意:接口描述符、类特殊描述符、端点描述符不能单独获取,必须跟配置描述符以一个集合的方式一并返回。可以通过beagle抓USB数据看到,没有Get Interface Descriptor和Get Endpoint Descriptor的请求。
对于字符串描述符,是单独获取的。主机通过发送获取字符串描述符的请求和描述符的索引号、语言ID来获取对应的字符串描述符。
下图是插入U盘后用beagle抓的数据包:
4.3 USB枚举过程
5,USB的传输类型
a. 控制传输:可靠,时间有保证,比如:USB设备的识别过程
b. 批量传输: 可靠, 时间没有保证, 比如:U盘
c. 中断传输:可靠,实时,比如:USB鼠标
d. 实时传输:不可靠,实时,比如:USB摄像头
U盘的传输对象是端点,我们说的读U盘、写U盘,可以细化到从端点1读数据,把数据写到u盘的端点2。
除了端点0外,其他端点都是单向传输数据的。
补充:
USB 时候采用NRZI(非归零反向编码)编码方式:数据为0时,电平翻转;数据为1时,电平不翻转。