目录
6.2、大容量数据传输 批量传输(Bulk Transfers): U盘
6.3、同步传输(Isochronous Transfers): 摄像头
6.4、中断传输(Interrupt Transfers): 鼠标键盘
一、USB总体概况
1.1、USB通信过程简介
- 设备插到主机上
- 主机开始检测设备类型(高速/全速/低速)
- 复位设备
- 主机开始对设备枚举(根据枚举得到的各种信息加载合适的驱动程序,比如根据信息知道是一个鼠标设备,则加载鼠标的驱动程序对接下来的数据进行处理)
- 枚举完成后主机要发送令牌包(IN / OUT)查询有效端点是否有数据,有数据时设备自然会返还给主机
1.2、USB枚举过程简介
- 主机获取设备描述符(部分)
- 主机对从机设置设备地址(非零,相当于我们的学号id)
- 主机再次获取从机设备描述符(全部)
- 主机获取配置描述符(了解从机配置,接口,端点)情况
- 如果有字符串描述符还有获取字符串描述符
- 设置配置请求,就是激活配置,如果没有这一步对应的配置就不可用
- 针对不同的类,获取它们独特的类描述符(比如HID报告描述符)
注意:
- 上面的枚举1-4,6步骤是必须的,
- 主机和从机通信时,从机时不能主动发数据给主机的,必须要等主机给从机发送令牌包后,根据主机的需求发送相应的数据
1.3、USB 配置 接口 端点 的关系
1、一个设备可以有多个配置,不同的配置对应不同的功能
比如,一个USB接口的CD-ROM,作为一个设备,
它具有两种功能,1读取光盘 和 2播放CD,所以有2个Configuration描述符
2、一个功能的实现要涉及许多接口,
比如当CD播放机使用时,需要音频接口,同时还需要控制CD机的接口。
3、一个接口又有许多端点组成,一般真正通信都是针对端点进行的,比如用端点0来进行控制枚举传输
stm32 支持8个双向端点,16个单向端点,每个端点只能时一个方向(OUT / IN),除了端点0
二、区分高速全速 低速设备的方法
d+上面接电阻:全速/高速设备 d- 上接电阻:低速设备
三、USB设备插拔检测机制
3.1、没有插上usb设备主机情况
- D+和D-数据线上的下拉电阻起作用,使得二者都在低电平;主机端看来就是个SE0状态;
- 同样地,当数据线上的SE0状态持续一段时间了,就被主机认为是断开状态
3.2、 插上usb设备时
当主机检测到某一个数据线电平拉高并保持了一段时间,就认为有设备连上来了
主机必需在驱动SE0状态以复位设备之前, 立刻采样总线状态来判断设备的速度
四、USB通信数据包解释以及包的传输过程
4.1、Packet的组成
4.2 、USB包的分类(令牌,数据包,握手包、帧首包)
包的分类组要是靠PID域来说明的,其中令牌包最重要
4.2.1、令牌包:
IN OUT SETUP 三个命令可选,并且都由主机发出,用来启动一次传输
主机和从机通信时,从机时不能主动发数据给主机的,必须要等主机给从机发送令牌包后,根据主机的需求发送相应的数据
1、IN 主机用来从设备读取数据
2、OUT 主机用来向设备发送数据
3、SETUP 主机用来向设备发送控制命令,接下来就是主机发送一次命令数据给(这个数据一般时获取描述符请求)从机 一般枚举的时候用
例如SETUP包:
4.2.2、数据包:
数据包:一般是DATA0 DATA1交替发出,如本次发送DATA0 下次就发送DATA1,主要目的就是为了校验
图中DATA0 编码是0xC3
4.2.3、握手包
用来确认应答
>> ACK:传输正确完成
>> NAK:设备暂时没有准备好接收数据,或没有准备好发送数据
>> STALL:设备不能进行传输
>> NYET/ERR:仅用于高速传输,设备没有准备好或出错
4.3、包的传输顺序
一般都是先由主机发送命令,然后才是数据过程,再时应答过程
五、枚举过程
5.1、枚举过程的通俗比喻
1、主机(下称H):你是什么设备(获取设备描述符请求)?
设备(下称D):12 01 0100……Device Descriptor
2、H:你有几种功能(获取配置描述符请求)?
D:09 02 09……Configuration Descriptor
3、H:每个功能有几个接口(获取接口描述符)?
D:09 04 00……Interface Descriptor
4、H:每个接口使用哪几个端点(获取端点描述符)?
D:06 05 82……Endpoint Descriptor
5、H:好了,我知道你是谁了,开始传输数据吧!
D:OK, Read Go
.2、主机标准请求
主机要获得从机的描述符就要发送相关8字节标准请求
5.3、描述符介绍
5.3.1、设备描述符
以stm32为例:
/*usb_desc.c*/
/* USB Standard Device Descriptor */
const uint8_t Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC] =
{
0x12, /*bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
0x00, /*bcdUSB */
0x02,
0x00, /*bDeviceClass*/
0x00, /*bDeviceSubClass*/
0x00, /*bDeviceProtocol*/
0x40, /*bMaxPacketSize 64 最大64字节*/
0x83, /*idVendor (0x0483)*/
0x04,
0x10, /*idProduct = 0x5710*/
0x57,
0x00, /*bcdDevice rel. 2.00*/
0x02,
1, /*Index of string descriptor describing
manufacturer */
2, /*Index of string descriptor describing
product*/
3, /*Index of string descriptor describing the
device serial number */
0x01 /*bNumConfigurations 配置描述符*/
}
; /* Joystick_DeviceDescriptor */
5.3.2、配置描述符
0x09, /* bLength: Configuration Descriptor size */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
JOYSTICK_SIZ_CONFIG_DESC, /*#define JOYSTICK_SIZ_CONFIG_DESC 34 这是一个大数组,整个数组大小34字节*/
/* wTotalLength: Bytes returned */
0x00,
0x01, /*bNumInterfaces: 1 interface 接口数1*/
0x01, /*bConfigurationValue: Configuration value*/
0x00, /*iConfiguration: Index of string descriptor describing
the configuration*/
0xE0, /*bmAttributes: Self powered */
0x32, /*MaxPower 100 mA: this current is used for detecting Vbus*/
5.3.3、 接口描述符
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, /*bLength: Interface Descriptor size*/
USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/
0x00, /*bInterfaceNumber: Number of Interface 序号,编号从0开始,第二个接口就是1*/
0x00, /*bAlternateSetting: Alternate setting*/
0x01, /*bNumEndpoints 该接口的端点数目*/
0x03, /*bInterfaceClass: HID*/
0x01, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x02, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
0, /*iInterface: Index of string descriptor*/
5.3.4、类描述符(比如HID类描述符)这个时可选的(如果不是标准类,就不需要)
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x00, /*bcdHID: HID Class Spec release number*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
JOYSTICK_SIZ_REPORT_DESC,/*wItemLength: Total length of Report descriptor*/
0x00,
/******************** Descriptor of Joystick Mouse endpoint ********************/
5.3.5、端点描述符
/******************** Descriptor of Joystick Mouse endpoint ********************/
/* 27 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
0x81, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint 0控制 1等时 2批量 3中断*/
0x04, /*wMaxPacketSize: 4 Byte max */
0x00,
0x20, /*bInterval: Polling Interval (32 ms)*/
5.4、获取设备描述符
5.5、设置地址请求
5.6、获取配置描述符
5.7、设置配置请求
就是让某个配置有效
六、 USB枚举后的数据传输过程 以及 四种传输类型
6.1、控制传输 枚举
(一般用于枚举过程端点0,主机给从机发命令或回应状态时,这个过程是随机突发的的,也就是主机随时发命令,从机只能是待命)
6.2、大容量数据传输 批量传输(Bulk Transfers): U盘
大容量传输一般用于非零端点,并且针对大数据传输(如U盘),数据可以占用任意带宽,并容忍延迟 ,并且这个过程也是随机突发的,因为控制权在主机,用户随时要读取设备(u盘)数据,所以这个过程是非周期的
stm32 大容量传输分析
6.3、同步传输(Isochronous Transfers): 摄像头
周期性的,持续性的传输,用于传输与时效相关的信息,并且在数据中保存时间戳的信息 比如(摄像头图像传输)
6.4、中断传输(Interrupt Transfers): 鼠标键盘
周期性,低频率,比如hid鼠标键盘,(主机是周期性查询端点有没有数据的,只要鼠标有动作,就可以往端点缓存送数据,等到主机查询的时候,数据就会被主机读走)所以在设备初始化的时候要初始化主机查询时间间隔
超时轮询时间间隔在从机端点描述符中获取
博客园连接:https://www.cnblogs.com/shenLong1356/p/11287833.html
https://blog.youkuaiyun.com/g200407331/article/details/51682597/