USB 基本知识

USB的重要关键概念:

  • 端点:位于USB设备或主机上的一个数据缓冲区,用来存放和发送USB的各种数据,每一个端点都有惟一的确定地址,有不同的传输特性(如输入端点、输出端点、配置端点、批量传输端点) 设备支持端点的数量是有限制的,除默认端点外低速设备最多支持2组端点(2 个输入,2 个输出),高速和全速设备最多支持15组端点。
  • 帧:时间概念,在USB中,一帧就是1MS,它是一个独立的单元,包含了一系列总线动作,USB将1帧分为好几份,每一份中是一个USB的传输动作。
  • upstream、downstream(上行、下行):设备到主机为上行,主机到设备为下行

USB协议的数据格式

一个transfer(传输)由一个或多个transaction(事务)构成,一个transaction(事务)由一个或多个packet(包)构成,一个packet(包)由一个或多个sync(域)构成。

基本构成

1.传输数据通信
USB的数据通讯首先是基于传输(transfer)的,传输的类型有:中断传输、批量传输、同步传输、控制传输。
2.事务数据通讯
一次传输由一个或多个事务(transaction)构成,事务可以分为:in事务、out事务、setup事务。
3.包数据通讯
一个事务由一个或多个包(packet)构成,包可分为:令牌包(setup)、数据包(data)、握手包(ack)、特殊包。
4.域数据通讯
一个包由多个sync(域)构成,域可分为:同步域(sync)、标识域(pid)、地址域(addr)、端点域(endp)、帧号域(fram)、数据域(data)、校验域(crc)。

域数据格式

域是USB数据最小的单位,由若干位组成(至于是多少位由具体的域决定),域可分为七个类型:

  • 同步域(SYNC)八位 ,值固定为0000 0001,用于本地时钟与输入同步
  • 标识域(PID) :由四位标识符+四位标识符反码构成,表明包的类型和格式,这是一个很重要的部分,这里可以计算出,USB的标识码有16种
  • 地址域(ADDR)七位 地址,代表了设备在主机上的地址,地址000 0000被命名为零地址,是任何一个设备第一次连接到主机时,在被主机配置、枚举前的默认地址,由此可以知道为什么一个USB主机只能接127个设备的原因。
  • 端点域(ENDP)四位 ,由此可知一个USB设备有的端点数量最大为16个。
  • 帧号域(FRAM)11位 ,每一个帧都有一个特定的帧号,帧号域最大容量0x800,对于同步传输有重要意义(同步传输为四种传输类型之一,请看下面)。
  • 数据域(DATA) :长度为0~1023字节,在不同的传输类型中,数据域的长度各不相同,但必须为整数个字节的长度
  • 校验域(CRC) :对令牌包和数据包(对于包的分类请看下面)中非PID域进行校验的一种方法,CRC校验在通讯中应用很泛,是一种很好的校验方法,只须注意CRC码的除法是模2运算,不同于10进制中的除法。

包数据格式

由域构成的包有 种类型,分别是令牌包、数据包、握手包和特殊包,前面三种是重要的包,不同的包的域结构不同,介绍如下:

  1. 令牌包 :可分为输入包、输出包、设置包和帧起始包(注意这里的输入包是用于设置输入命令的,输出包是用来设置输出命令的,而不是放据数的)
    其中输入包、输出包和设置包的格式都是一样的: 帧起始包的格式:
  1. SYNC+PID+ADDR+ENDP+CRC5(五位的校验码)
SYNC+PID+11位FRAM+CRC5(五位的校验码)
  1. 数据包 :分为DATA0包和DATA1包,当USB发送数据的时候,当一次发送的数据长度大于相应端点的容量时,就需要把数据包分为好几个包,分批发送,DATA0包和DATA1包交替发送,即如果第一个数据包是 DATA0,那第二个数据包就是DATA1。但也有例外情况,在同步传输中(四类传输类型中之一),所有的数据包都是为DATA0,格式如下:
SYNC+PID+0~1023字节+CRC16
  1. 握手包 :结构最为简单的包,格式如下:
SYNC+PID

USB事务

事务的三个阶段

分别有IN、OUT和SETUP三大事务,每一种事务都由令牌包、数据包、握手包三个阶段构成,这里用阶段的意思是因为这些包的发送是有一定的时间先后顺序的,事务的三个阶段如下:

  1. 令牌包阶段 :启动一个输入、输出或设置的事务。
  2. 数据包阶段 :按输入、输出发送相应的数据。
  3. 握手包阶段 :返回数据接收情况,在同步传输的IN和OUT事务中没有这个阶段,这是比较特殊的。

事务的三种类型

IN事务

  • 令牌包阶段——主机发送一个PID为IN的输入包给设备,通知设备要往主机发送数据。
  • 数据包阶段——设备根据情况会作出三种反应(注意:数据包阶段也不总是传送数据的,根据传输情况还会提前进入握手包阶段)。
    • 设备端点正常:设备往主机里面发出数据包(DATA0与DATA1交替);
    • 设备正在忙:无法往主机发出数据包就发送NAK无效包,IN事务提前结束,下一个IN事务继续;
    • 相应设备端点被禁止:发送错误包STALL包,事务也就提前结束了,总线进入空闲状态;
  • 握手包阶段——主机正确接收到数据之后就会向设备发送ACK包。

OUT事务

  • 令牌包阶段——主机发送一个PID为OUT的输出包给设备,通知设备要接收数据
  • 数据包阶段——比较简单,就是主机会往设备送数据,DATA0与DATA1交替
  • 握手包阶段——设备根据情况会作出三种反应
    • 设备端点接收正确,设备给主机返回ACK,通知主机可以发送新的数据,如果数据包发生了CRC校验错误,将不返回任何握手信息;
    • 设备正在忙,无法给主机返回ACK,就发送NAK无效包,通知主机再次发送数据
    • 相应设备端点被禁止,发送错误包STALL包,事务提前结束,总线直接进入空闲状态

SETUT事务

  • 令牌包阶段——主机发送一个PID为SETUP的输出包给设备,通知设备要接收数据;
  • 数据包阶段——比较简单,就是主机往设备送数据,注意,这里只有一个固定为8个字节的DATA0包,这8个字节的内容就是标准的USB设备请求命令
  • 握手包阶段——设备接收到主机的命令信息后,返回ACK,此后总线进入空闲状态,并准备下一个传输(在SETUP事务后通常是一个IN或OUT事务构成的传输)。

USB的传输

控制传输(Control Transfers): 非周期性,突发

控制传输是一种可靠的双向传输,一次控制传输可分为三个阶段。

  1. 第一阶段为从HOST到Device的SETUP事务传输,这个阶段指定了此次控制传输的请求类型;
  2. 第二阶段为数据阶段,也有些请求没有数据阶段;
  3. 第三阶段为状态阶段,通过一次IN/OUT 传输表明请求是否成功完成。

控制传输对于最大包长度有固定的要求。对于高速设备该值为 64Byte ;对于低速设备该值为 8;全速设备可以是 8或 16或 32或 64。

中断传输(Interrupt Transfers): 周期性,低频率

允许有限延迟的通信 如人机接口设备(HID)中的鼠标、键盘、轨迹球等。

中断传输是一种保证查询频率的传输。中断端点在端点描述符中要报告它的查询间隔,主机会保证在小于这个时间间隔的范围内安排一次传输。

中断传输是一种轮询的传输方式,是一种单向的传输,HOST通过固定的间隔对中断端点进行查询,若有数据传输或可以接收数据则返回数据或发送数据,否则返回NAK,表示尚未准备好。

中断传输的延迟有保证,但并非实时传输,它是一种延迟有限的可靠传输,支持错误重传。 对于高速/全速/低速端点,最大包长度分别可以达到1024/64/8 Bytes。

批量传输(Bulk Transfers): 非周期性,突发

大容量数据的通信,数据可以占用任意带宽,并容忍延迟 。如USB打印机、扫描仪、大容量储存设备等。

批量输出事务

主机先发出一个OUT令牌包(包含设备地址,端点号)。
然后再发送一个DATA包,这时地址和端点匹配的设备就会收下这个数据包,主机切换到接收模式,等待设备返回握手包。
设备解码令牌包,数据包都准确无误,并且有足够的缓冲区来保存数据后就会使用ACK/NYET握手包来应答主机(只有高速模式才有NYET握手包,他表示本次数据成功接收,但是没有能力接收下一次传输),如果没有足够的缓冲区来保存数据,就返回NAC,告诉主机目前没有缓冲区可用,主机会在稍后时间重新该批量传输事务。如果设备检查到数据正确,但端点处于挂起状态,返回STALL。如果检测到有错误(如校验错误,位填充错误),则不做任何响应,让主机等待超时。

批量输入事务

主机首先发送一个IN令牌包(包含设备地址,端点号)。
主机切换到接收数据状态等待设备返回数据。如果设备检测到错误,不做任何响应,主机等待超时。如果此时有地址和端点匹配的设备,并且没有检测到错误,则该设备作出反应:设备有数据需要返回,就将一个数据包放在总线上;如果没有数据需要返回,设备返回NAK响应主机;如果该端点处于挂起状态,设备返回STALL。如果主机收到设备发送的数据包并解码正确后,使用ACK握手包应答设备。如果主机检测到错误,则不做任何响应,设备会检测到超时。
注意:USB协议规定,不允许主机使用NAK来拒绝接收数据包。主机收到NAK,知道设备暂时没有数据返回,主机会在稍后时间重新该批量输入事务。

等时传输(Isochronous Transfers): 周期性

持续性的传输,用于传输与时效相关的信息,并且在数据中保存时间戳的信息 ,如音频视频设备

等时(同步)传输用在数据量大、对实时性要求高的场合,如音频设备,视频设备等,这些设备对数据的延迟很敏感。对于音频或视频设备数据的100%正确性要求不高,少量的数据错误是可以容忍的,主要是保证数据不能停顿 ,所以等时传输是不保证数据100%!正(MISSING)确的。当数据错误时,不再重传操作。因此等时传输没有应答包,数据是否正确,由数据的CRC校验来确认。

USB身份识别

对于插入的USB设备,主机需要发送比较短的请求来确认设备的身份、类型、速度等信息,这个过程称之为枚举

枚举过程

  1. 等待稳定 :主机通过电平差检测到设备,等待100ms让设备电平趋于稳定。设备插入后主机通过检测电压的改变识别到设备接入,检测到设备后,并不急于与设备进行USB任何数据传输。
  2. 首次复位 :HUB发起复位,让设备进入初始的地址0模式。设备被复位后,会默认使用地址:0,端点号:0,与主机开始进行信息交换。所有的USB设备在总线复位后其地址都为0,这样主机就可以跟那些刚刚插入的设备通过地址0通信。枚举过程不是多设备并行处理,而是一次枚举一个设备。
  3. 首次查询设备描述符 :GET_DESCRIPTOR 主机查询设备描述符,只要前8字节。此次获取该描述符主机不会认真解析,应该仅仅只为检测是否正常通信。
  4. 二次复位 :在接收到设备描述符前8个字节后,再次重启设备。
  5. 设置地址 :SET_ADDRESS 主机下发设置地址命令,设备获取新地址
  6. 二次查询设备描述符 :GET_DEVICE_DESCRPTOR获取整个18字节的设备描述符
  7. 获取配置描述符 :GET_CONFIGURATION 获取9字节配置描述符
  8. 完成配置 :SET_CONFIGURATION

USB协议详解 - 图1

描述符

标准的usb描述符包含以下几部分:

  • 设备描述符
  • 配置描述符
  • 接口描述符
  • 端点描述符
  • 字符串描述符

USB协议详解 - 图2

设备描述符

一个设备只有一个设备描述符!

typedef struct _USB_DEVICE_DESCRIPTOR_{    
    BYTE        bLength,    
    BYTE        bDescriptorType,    
    WORD        bcdUSB,    
    BYTE        bDeviceClass,    
    BTYE        bDeviceSubClass,    
    BYTE        bDeviceProtol,    
    BYTE        bMaxPacketSize0,    
    WORD        idVenderI,    
    WORD        idProduct,    
    WORD        bcdDevice,    
    BYTE        iManufacturr,    
    BYTE        iProduct,    
    BYTE        iSerialNumber,    
    BYTE        iNumConfiguations
} USB_DEVICE_DESCRIPTOR;

详细描述如下:

  • bLength : 描述符大小.固定为0x12
  • bDescriptorType : 设备描述符类型.固定为0x01
  • bcdUSB : USB 规范发布号.表示了本设备能适用于那种协议,如2.0=0x0200,1.1=0x0110等
  • bDeviceClass : 类型代码(由USB指定),当它的值是0时,表示所有接口在配置描述符里,并且所有接口是独立的。当它的值是1到FEH时,表示不同的接口关联的。当它的值是FFH时,它是厂商自己定义的
  • bDeviceSubClass : 子类型代码(由USB分配),如果bDeviceClass值是0,一定要设置为0.其它情况就跟据USB-IF组织定义的编码
  • bDeviceProtocol : 协议代码(由USB分配),如果使用USB-IF组织定义的协议,就需要设置这里的值,否则直接设置为0。如果厂商自己定义的可以设置为FFH
  • bMaxPacketSize0 : 端点0最大分组大小(只有8,16,32,64有效)
  • idVendor : 供应商ID(由USB分配)
  • idProduct : 产品ID(由厂商分配),由供应商ID和产品ID,就可以让操作系统加载不同的驱动程序.
  • bcdDevice : 设备出产编码.由厂家自行设置
  • iManufacturer : 厂商描述符字符串索引.索引到对应的字符串描述符. 为0则表示没有
  • iProduct : :产品描述符字符串索引.同上.
  • iSerialNumber : 设备序列号字符串索引.同上
  • bNumConfigurations : 可能的配置数.指配置字符串的个数

如STM32中生成的USB配置如下:

__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
  0x12,                       /*bLength */
  USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/

  0x00,                       /*bcdUSB */

  0x02,
  0x00,                       /*bDeviceClass*/
  0x00,                       /*bDeviceSubClass*/
  0x00,                       /*bDeviceProtocol*/
  USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
  LOBYTE(USBD_VID),           /*idVendor*/
  HIBYTE(USBD_VID),           /*idVendor*/
  LOBYTE(USBD_PID_FS),        /*idProduct*/
  HIBYTE(USBD_PID_FS),        /*idProduct*/
  0x00,                       /*bcdDevice rel. 2.00*/
  0x02,
  USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
  USBD_IDX_PRODUCT_STR,       /*Index of product string*/
  USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
  USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
};

配置描述符

配置描述符定义了设备的配置信息,一个设备可以有多个配置描述符!

typedef struct _USB_CONFIGURATION_DESCRIPTOR_{    
    BYTE      bLength,    
    BYTE      bDescriptorType,    
    WORD      wTotalLength,    
    BYTE      bNumInterfaces,    
    BYTE      bConfigurationValue,    
    BYTE      iConfiguration,    
    BYTE      bmAttributes,    
    BYTE      MaxPower
} USB_CONFIGURATION_DESCRIPTOR;

详细描述如下:

  • bLength : 描述符大小,固定为0x09
  • bDescriptorType : 配置描述符类型,固定为0x02
  • wTotalLength : 返回整个数据的长度,指此配置返回的配置描述符,接口描述符以及端点描述符的全部大小
  • bNumInterfaces : 配置所支持的接口数,指该配置配备的接口数量,也表示该配置下接口描述符数量
  • bConfigurationValue : 作为Set Configuration的一个参数选择配置值
  • iConfiguration : 用于描述该配置字符串描述符的索引
  • bmAttributes : 供电模式选择,Bit4-0保留,D7:总线供电,D6:自供电,D5:远程唤醒
  • MaxPower : 总线供电的USB设备的最大消耗电流,以2mA为单位

接口描述符

接口描述符说明了接口所提供的配置,一个配置所拥有的接口数量通过配置描述符的bNumInterfaces决定

typedef struct _USB_INTERFACE_DESCRIPTOR_{
    BYTE      bLength,    
    BYTE      bDescriptorType,    
    BYTE      bInterfaceNumber,    
    BYTE      bAlternateSetting,
    BYTE      bNumEndpoint,    
    BYTE      bInterfaceClass,    
    BYTE      bInterfaceSubClass,    
    BYTE      bInterfaceProtocol,    
    BYTE      iInterface
} USB_INTERFACE_DESCRIPTOR;

详细描述如下:

  • bLength : 描述符大小,固定为0x09
  • bDescriptorType : 接口描述符类型,固定为0x04
  • bInterfaceNumber : 该接口的编号
  • bAlternateSetting : 用于为上一个字段选择可供替换的位置.即备用的接口描述符标号
  • bNumEndpoint : 使用的端点数目.端点0除外
  • bInterfaceClass : 类型代码(由USB分配)
  • bInterfaceSubClass : 子类型代码(由USB分配)
  • bInterfaceProtocol : 协议代码(由USB分配)
  • iInterface : 字符串描述符的索引

端点描述符

USB设备中的每个端点都有自己的端点描述符,由接口描述符中的bNumEndpoint决定其数量

typedef struct _USB_ENDPOINT_DESCRIPTOR_ {
    BYTE        bLength,
    BYTE        bDescriptorType,
    BYTE        bEndpointAddress,
    BYTE        bmAttributes,
    WORD        wMaxPacketSize,
    BYTE        bInterval
}USB_ENDPOINT_DESCRIPTOR;

详细描述如下:

  • bLength : 描述符大小.固定为0x07
  • bDescriptorType : 接口描述符类型.固定为0x05
  • bEndpointType : USB设备的端点地址.Bit7,方向,对于控制端点可以忽略,1/0:IN/OUT.Bit6-4,保留.BIt3-0:端点号
  • bmAttributes : 端点属性.Bit7-2,保留.BIt1-0:00控制,01同步,02批量,03中断
  • wMaxPacketSize :本端点接收或发送的最大信息包大小
  • bInterval : 轮训数据传送端点的时间间隔.对于批量传送和控制传送的端点忽略.对于同步传送的端点,必须为1,对于中断传送的端点,范围为 1-255

字符串描述符

其中字符串描述符是可选的.如果不支持字符串描述符,其设备,配置,接口描述符内的所有字符串描述符索引都必须为0

typedef struct _USB_STRING_DESCRIPTION_ {
    BYTE      bLength,
    BYTE      bDescriptionType,
    BYTE      bString[1];
}USB_STRING_DESCRIPTION;

详细描述如下:

  • bLength : 描述符大小.由整个字符串的长度加上bLength和bDescriptorType的长度决定
  • bDescriptorType : 接口描述符类型.固定为0x03
  • bString[1] : Unicode编码字符串