1.单模式
(1) host only, 使用于内部互联芯片USB做host的情况
(2) device only, 使用于内部互联芯片USB做device的情况
2. otg模式
(1) typec OTG: 基于typec接口 + cclogic的设计方案
(2) phy OTG: 基于GPIO实现USB模式的切换的设计方案
主从结构,总线上只能有一个主机,依靠hub向下扩展,一条总线最多可以接127个设备。所有USB传输,都是由主机发起,设备device没有主动通知主机的能力
看上图,每个USB 设备都有一个唯一的设备地址,设备地址是设备连接主机时,由主机分配的,主机依靠设备地址与usb device通信;
但在设备内部会被分的更细,设备会有很多端点,每个端点都有唯一的端点号,这个是设计设备的时候给定的(代码里写好,其实就是配寄存器),比如我们之前写的通过bulk裸传liveview数据的功能,就用到了某个端点。注意其中端点0比较特殊,它是用来进行对设备枚举和控制的
对于端点的进一步理解,可以看一下端点描述符,所谓描述符,可以理解成描述端点的结构体,我们直接看下结构定义好了:
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 : 本端点接收或发送的最大信息包大小(说明最大是 2^16 Bytes = 64KB)
bInterval : 轮训数据传送端点的时间间隔.对于批量传送和控制传送的端点忽略.对于同步传送的端点,必须为1,对于中断传送的端点,范围为1-255。
一个接口(interface)含有0个或者多个端点(endpoint),端点是USB通信的最基本形式。看一下接口的描述符定义;
#pragma data_alignment=1 //对齐方式为Byte typedef struct _USB_Desc_Interface_t { uint8_t bLength; // 固定值9B uint8_t bDescriptorType; // 固定值Interface(0x04) uint8_t bInterfaceNum; // 接口索引号 uint8_t bAlternateSetting; // 备用接口号 uint8_t bNumberEndpoints; // 端点数量 uint8_t bInterfaceClass; // 接口类型 uint8_t bInterfaceSubclass; // 接口子类型 uint8_t bInterfaceProtocol; // 接口协议 uint8_t bInterfaceStringIndex; // 接口名称的字符串索引号 }USB_Desc_Interface_t;
要理解接口的含义,我们需要看一下描述符集的层次结构:
从下往上看:
接口描述符中,有一个比较重要的属性叫做bInterfaceClass 接口类型,其定义参考USB IF,这里摘一段官网的解释
USB defines class code information that is used to identify a device’s functionality and to nominally load a device driver based on that functionality. The information is contained in three bytes with the names Base Class, SubClass, and Protocol. (Note that ‘Base Class’ is used in this description to identify the first byte of the Class Code triple. That terminology is not used in the USB Specification). There are two places on a device where class code information can be placed. One place is in the Device Descriptor, and the other is in Interface Descriptors. Some defined class codes are allowed to be used only in a Device Descriptor, others can be used in both Device and Interface Descriptors, and some can only be used in Interface Descriptors. The table below shows the currently defined set of Base Class values, what the generic usage is, and where that Base Class can be used (either Device or Interface Descriptors or both).
这句话是什么意思呢,就是说接口类型这个属性是用来识别设备功能的,同时host也可以据此加载对应的驱动。有两个地方都可以包含这个接口类型,一个地方就是我们正在看的接口描述符,另外一个地方就是设备描述符。其中有一些class codes是只给设备描述符用的,有一些是只给接口描述符用的,剩下的则是二者都可使用,比如网站上列出了下面的list:
对照一下设备描述看:
typedef struct _USB_Desc_Device_t { uint8_t bLength; // 固定值18B uint8_t bDescriptorType; // 固定值Device(0x01) uint16_t wBcdUSB; // USB Spec版本 uint8_t bDeviceClass; // 设备类型 uint8_t bDeviceSubClass; // 设备子类型 uint8_t bDeviceProtocol; // 协议类型 uint8_t bMaxPacketSize0; // EP0的最大包长度 uint16_t wIdVendor; // 厂商ID uint16_t wIdProduct; // 产品ID uint16_t wBcdDevice; // 设备软件版本 uint8_t bStringIndexManufacturer; // 厂商名称字符串索引号 uint8_t bStringIndexProduct; // 产品名称字符串索引号 uint8_t bStringIndexSerialNumber; // 序列号索字符串引号 uint8_t bNumConfigurations // 配置数量>=1 }USB_Desc_Device_t;
里面也有设备类型,映证了上面的说法。这里注意一个比较特殊的值,如果说设备类型是00h, 则说明class code要到接口描述符中去获取。
还剩下一个配置描述符,如何理解配置描述呢?
#pragma data_alignment=1 //对齐方式为Byte typedef struct _USB_Desc_Configuration_t { uint8_t bLength; // 固定值9B uint8_t bDescriptorType; // 固定值Configuration(0x02) uint16_t wTotalConfigurationSize; // 配置集合的总大小 uint8_t bTotalInterfaces; // 配置集合的接口数量 uint8_t bConfigurationNumber; // 当前配置的序号(从1开始) uint8_t bConfigurationStrIndex; // 配置名称的字符串索引号 uint8_t bConfigAttributes; // 配置集合的属性 uint8_t bMaxPowerConsumption; // 最大供电电流,单位是2mA }USB_Desc_Configuration_t; // 配置集合的属性 typedef struct _bConfigAttributes_t{ uint8_t b5reserved:5; // 保留置0 uint8_t b1RemoteWakeup:1; // 置1表示支持远程唤醒 uint8_t b1Selfpowerd:1; // 置1表示支持自己供电 uint8_t b1reserved:1; // 保留置1 }bConfigAttributes_t;
这个时候我们大概有了一个这样的认知,一个usb设备,有多个配置,这些配置本身的描述符不重要,重要的是这些配置里面包含了多个interface,
每个interface对应着设备的实际功能,比如一个眼镜的usb口,它可以被枚举成一个mass storage设备,它也可以被枚举成一个video 播放器等等,如果有cc,它还可以变为host 去枚举别的设备