协议 - USB详解


【全文大纲】 : https://blog.csdn.net/Engineer_LU/article/details/135149485


1 . 前言

  • 1 . USB协议较为广泛,这里按以往风格描述物理层,协议层,应用层
  • 2 . 基于本人习惯简洁风格,此篇文章尽量把USB协议描述清晰
  • 3 . 接下来从物理层,协议层,应用层,从下往上深入浅出剖析

2 . USB外形类分

在这里插入图片描述

3 . 物理层

  1. USB2.0的结构简洁,VCC, D+, D-, GND通信.

  2. 主机的两个下拉电阻阻值为15K,从机的D+ D-上拉电阻为1.5K

  3. 通讯依靠D+,D-作为差分

  4. 对于低速,全速设备USB通信四种状态,逻辑0与逻辑1和JK状态不加以区分

    JKSE0SE1
    D +0101
    D -1001
  5. 对于高速设备,做了8b/10b编码,把逻辑0与逻辑1和JK状态区分开来

  6. 下图为USB2.0的结构 :
    在这里插入图片描述

  7. 当设备接入时,通过检测从机的上拉电阻接在了D- 或 D+来判断设备所属模式

    模式上拉电阻接入 (1.5K)速度
    低速D-1.5M
    全速D+12M
    高速D+480M
  8. 当设备拔出时,通过检测从机的D- 和 D+ 的上拉来判断设备拔出

    模式上拉电阻接入 (1.5K)
    拔出

4 . 协议层

4.1: USB协议层结构

  1. USB协议层结构图解,一次传输由多个事务组成,一个事务一般由三个包组成,、一个包由多个字段构成

在这里插入图片描述

4.2: USB传输事务关系

  1. 传输类型与事务数量的关系
传输类型典型事务数原因
控制传输2 - N固定结构:Setup + (可选Data) + Status
中断传输通常1数据量小,实时性要求
批量传输1 - N根据数据量分割
同步传输固定N/微帧带宽预留,时间敏感

传输类型(Transfer Type)的决定因素

决定层面决定因素具体机制示例
设备设计时端点描述符在端点描述符的bmAttributes字段的Bits[1:0]中指定:
• 00 = 控制传输
• 01 = 等时传输
• 10 = 批量传输
• 11 = 中断传输
HID设备的输入端点设置为中断传输;U盘的批量端点设置为批量传输
枚举过程中设备描述符bDeviceClass, bDeviceSubClass, bDeviceProtocol字段定义了设备的类、子类和协议,隐式决定了主要传输类型一个音频设备会被识别为需要等时传输
驱动加载时设备类和协议操作系统根据设备类加载相应驱动,驱动知道如何处理特定传输类型HID类驱动知道鼠标使用中断传输,存储设备驱动知道使用批量传输
应用程序数据特性需求应用根据数据特性选择:
• 控制/配置 → 控制传输
• 大文件 → 批量传输
• 实时数据 → 等时传输
• 小量实时 → 中断传输
视频会议软件选择等时传输;文件管理器选择批量传输

事务类型(Transaction Type)的决定因素,数据量与事务的关系

决定层面决定因素具体机制示例
Setup事务控制传输的结构所有控制传输都必须以Setup事务开始枚举时获取描述符必须用Setup事务发送GET_DESCRIPTOR请求
IN事务数据传输方向需要从设备读取数据时:
1. Setup包的bmRequestType方向位=1
2. 批量/中断/等时传输的读操作
鼠标发送移动数据(中断IN)、读取U盘文件(批量IN)
OUT事务数据传输方向需要向设备写入数据时:
1. Setup包的bmRequestType方向位=0
2. 批量/中断/等时传输的写操作
向打印机发送文档(批量OUT)、配置设备参数(控制OUT)
Data事务的数量数据长度和包大小数据事务数 = ceil(数据总长度 / 端点最大包长)读取512字节数据,端点最大包长64,需要8个IN事务
Status事务方向数据阶段方向• 数据阶段为IN → Status事务为OUT
• 数据阶段为OUT → Status事务为IN
• 无数据阶段 → Status事务为IN
SET_ADDRESS无数据阶段,Status事务用IN事务
  1. 传输类型主要由:
    端点描述符(硬件设计时决定)
    设备类规范(协议标准要求)
    数据特性(应用需求)

  2. 事务类型主要由:

    传输类型(控制传输有固定结构)
    数据方向(IN或OUT)
    数据量大小(决定事务数量)
    协议阶段(Setup/Data/Status)

  3. 简单记忆:

    传输类型 = 用什么交通工具(公交、地铁、出租车、专车)
    事务类型 = 上下车的具体动作(上车刷卡、找座位、下车刷卡)


  1. USB事务类型与字段详解

    USB事务一共有setup,in,out事务,另外还有一个status事务,但 status 事务不是USB协议中的标准独立事务类型。它是控制传输的状态阶段,实际上就是一个零长度的IN或OUT事务。因此,我们将重点描述四种基本事务类型。

    下表详细描述了Setup、IN、OUT和Status四种事务的组成、作用和各字段:

    表1:Setup事务(控制传输的设置阶段),作用 :启动一个控制传输,发送8字节的标准设备请求(如获取描述符、设置地址等)

    事务组成包序列发送方各字段作用备注/特殊规则
    Setup事务1. SETUP令牌包主机PID(0x2D): 标识为SETUP类型
    ADDR: 目标设备地址(通常为0,枚举时)
    ENDP: 端点号(总是0,控制端点)
    CRC5: 校验地址和端点
    总是发往设备的控制端点(端点0)
    2. DATA0数据包主机PID(0xC3): 固定使用DATA0
    DATA(8字节): 包含标准请求: bmRequestType, bRequest, wValue, wIndex, wLength
    CRC16: 校验8字节数据
    固定8字节长度,固定DATA0 PID,重置数据切换
    3. ACK握手包设备PID(0xD2): 确认接收成功设备必须在接收到有效的Setup包后返回ACK

    表2:IN事务(数据从设备到主机),作用 :从设备读取数据,用于控制传输的数据阶段、批量读取、中断传输读取等

    事务组成包序列发送方各字段作用备注/特殊规则
    IN事务1. IN令牌包主机PID(0x69): 标识为IN类型
    ADDR: 目标设备地址
    ENDP: 端点号(指定具体端点)
    CRC5: 校验地址和端点
    主机请求从指定端点读取数据
    2. 数据包设备PID(DATA0/DATA1/…): 根据数据切换状态
    DATA: 要发送给主机的数据
    CRC16: 校验数据内容
    设备可以发送NAK(忙)或STALL(错误)代替数据包
    3. 握手包主机PID(ACK/…): 确认数据接收状态主机成功接收后发送ACK;失败则不回应(超时)

    表3:OUT事务(数据从主机到设备),作用 :向设备写入数据,用于控制传输的数据阶段、批量写入、中断传输写入等。

    事务组成包序列发送方各字段作用备注/特殊规则
    OUT事务1. OUT令牌包主机PID(0xE1): 标识为OUT类型
    ADDR: 目标设备地址
    ENDP: 端点号(指定具体端点)
    CRC5: 校验地址和端点
    主机准备向指定端点写入数据
    2. 数据包主机PID(DATA0/DATA1/…): 根据数据切换状态
    DATA: 要发送给设备的数据
    CRC16: 校验数据内容
    主机发送实际数据,长度由端点最大包长决定
    3. 握手包设备PID(ACK/NAK/STALL): 确认数据接收状态设备成功接收返回ACK;忙则返回NAK;错误则返回STALL

    表4:Status事务(控制传输的状态阶段 - 实际是特殊IN/OUT事务),作用 :作为控制传输的最后一个阶段,确认整个控制传输是否成功完成。它不是独立的事务类型,而是零长度的IN或OUT事务。

    事务组成包序列发送方各字段作用备注/特殊规则
    Status事务(作为OUT事务时)1. OUT令牌包主机PID(0xE1): OUT类型
    ADDR: 目标设备地址
    ENDP: 端点号(通常为0)
    CRC5: 校验地址和端点
    仅当数据阶段是IN时,状态阶段用OUT事务
    2. DATA1数据包主机PID(0x4B): 固定使用DATA1
    DATA: 零长度(空)
    CRC16: 校验空数据
    零长度包,固定DATA1 PID,表示传输成功完成
    3. ACK握手包设备PID(0xD2): 确认状态接收成功设备确认整个控制传输完成
    Status事务(作为IN事务时)1. IN令牌包主机PID(0x69): IN类型
    ADDR: 目标设备地址
    ENDP: 端点号(通常为0)
    CRC5: 校验地址和端点
    当数据阶段是OUT或没有数据阶段时,状态阶段用IN事务
    2. DATA1数据包设备PID(0x4B): 固定使用DATA1
    DATA: 零长度(空)
    CRC16: 校验空数据
    零长度包,固定DATA1 PID,表示设备处理成功
    3. ACK握手包主机PID(0xD2): 确认状态接收成功主机确认整个控制传输完成
  2. USB事务类型总结与对比

事务类型协议层地位使用场景数据方向数据包PID数据长度
Setup控制传输的必需起始阶段枚举、设备控制请求主机→设备固定DATA0固定8字节
IN通用读取事务批量读取、中断读取、控制传输数据阶段(读)设备→主机DATA0/DATA1交替0-端点最大包长
OUT通用写入事务批量写入、中断写入、控制传输数据阶段(写)主机→设备DATA0/DATA1交替0-端点最大包长
Status控制传输的结束阶段控制传输状态确认双向(零长度)固定DATA1固定0字节

关键理解
关键理解要点

1 . 事务的构成:每种事务都由令牌包 + 数据包 + 握手包组成(等时传输例外,没有握手包)。
2 . Status不是独立事务:它是控制传输的状态阶段,根据数据阶段方向,可以是IN或OUT事务,但必须是零长度且使用DATA1 PID。
3 . PID使用规则
Setup事务:固定DATA0
Status事务:固定DATA1
其他数据事务:DATA0/DATA1交替(数据切换机制)
4 . 数据方向规则
数据阶段方向由Setup包的bmRequestType方向位决定
Status阶段方向与数据阶段方向相反(或当无数据阶段时,为IN)
5 . 控制传输的完整流程:控制传输 = Setup事务 + [0-N个数据事务(IN/OUT)] + Status事务(IN/OUT,零长度)

4.3: USB包与字段关系

每个事务一般由三个包构成,各包的字段解析

4.3.1 :令牌包
  1. 发起并定义一次数据事务的方向和目的地,在USB总线上,永远由主机发起所有通信。令牌包就是主机发出的“命令”,它告诉特定设备:“现在轮到你,我要求你进行一个特定操作”。

    定义事务类型

    • SETUP: 发起一次控制传输的请求阶段(如:读取设备信息)。
    • IN: 要求设备向主机发送数据(如:读取U盘文件)。
    • OUT: 通知设备准备从主机接收数据(如:向打印机发送文档)。
    • SOF (Start of Frame): 在全速/高速下,每1ms(125μs)广播一次,提供时间基准,用于同步和带宽管理。

    指定目标:包含设备地址和端点号,精确地指出与哪一个设备的哪一个“数据通道”(端点)进行通信。
    简单比喻:就像一个物流中心的调度员,拿着喇叭喊:“3号仓库的1号门(地址3,端点1),现在请你把货发出来(IN)!”

    令牌包(Token Packet)字段详解

    字段名称长度(位)在包中的位置作用与描述示例/备注
    SYNC8 (低速/全速)
    32 (高速)
    起始时钟同步。固定的位模式,用于接收方同步其时钟,准确采样后续数据。全速:0x80 (二进制 1000 0000),经NRZI编码后为连续的01交替。
    PID8SYNC之后包标识符。唯一标识此包为令牌包,并指定其具体类型(IN/OUT/SETUP/SOF)。0x69 = IN令牌
    0xE1 = OUT令牌
    0x2D = SETUP令牌
    0xA5 = SOF令牌
    ADDR7PID之后设备地址。指定本次事务要访问的USB设备地址(0-127)。地址0用于默认控制端点,仅在枚举阶段使用。地址 3 表示与已枚举的、地址为3的设备通信。
    ENDP4ADDR之后端点号。与ADDR结合,精确指定目标设备内的特定数据端点(0-15)。端点0是必须存在的控制端点。端点 1 可能对应设备的某个批量输入端点。
    CRC55ADDR和ENDP之后循环冗余校验。校验ADDR和ENDP字段在传输中是否出错。多项式为 x⁵ + x² + 1。接收方重新计算CRC5,若与收到的不符,则丢弃整个包。
    EOP信号电平包末尾包结束。并非一个数据字段,而是一个特定的信号状态(SE0后接J状态),表示包传输结束。发送方将D+和D-都拉低(SE0)约2个位时间,再恢复空闲状态(J)。

    关键补充说明

    PID的构成:PID字节的低4位是类型码,高4位是低4位的反码,用于校验PID本身的有效性。例如,IN的类型码是1001,其PID字节为1001 0110 (0x69)。

    SOF令牌的特殊性:SOF(帧起始)包的结构略有不同。它的ADDR和ENDP字段被一个11位的帧号(Frame Number)取代,用于同步和跟踪时间。

    令牌包的作用流程:主机通过发送一个令牌包,启动一个完整的事务。例如,发送一个 PID=IN, ADDR=3, ENDP=1 的令牌包,就意味着:“请地址为3的设备,从它的1号端点向我发送数据”。随后才会进入数据包和握手包阶段。


4.3.2 :数据包
  1. 承载实际需要传输的有效信息,一旦令牌包发出了指令,数据包就负责运送真正的“货物”。它只存在于有数据需要传输的事务中。

    关键职责

    • 运输数据:数据可以是命令(Setup包中的8字节请求)、文件内容、鼠标移动坐标、音频流等任何有效载荷。
    • 确保顺序:通过 DATA0 和 DATA1(以及高速下的 DATA2/MDATA)的交替切换 (Data Toggle) 机制,发送方和接收方可以检测数据包是否丢失或重复,从而保证数据的正确顺序。
    • 数据校验:包含强大的CRC16校验码,接收方可以用它来验证数据在传输过程中是否发生位错误。

    简单比喻:就是一辆辆装载着实际货物的卡车,卡车侧面贴着“DATA0”或“DATA1”的标签,用于核对顺序。车厢里装着真正的货物(数据)。

    数据包(Data Packet)字段详解

    字段名称长度(位)在包中的位置作用与描述示例/备注
    SYNC8 (低速/全速)
    32 (高速)
    起始时钟同步。固定的位模式,用于接收方同步时钟,准确采样后续数据。这是接收方识别一个包开始的标志。同令牌包,是一个特定的边沿信号。
    PID8SYNC之后数据包标识符。标识此包为数据包,并指定其数据切换序列类型。这是实现可靠传输、防止丢包或重复的关键。0xC3 = DATA0
    0x4B = DATA1
    0x87 = DATA2 (仅高速等时)
    0x0F = MDATA (仅高速)
    DATA可变(0 ~ 8192位)PID之后有效载荷。这是实际需要传输的信息主体,长度由具体传输需求和端点能力决定。可以是设备描述符、文件数据、HID报告、音频采样等。零长度用于状态阶段。
    CRC1616DATA之后循环冗余校验。用于校验整个DATA字段在传输过程中是否发生比特错误。多项式为 x¹⁶ + x¹⁵ + x² + 1。接收方计算DATA字段的CRC16,若与收到值不匹配,则数据包被视为损坏,并期待发送方重传。
    EOP信号电平包末尾包结束。一个特定的信号状态(SE0后接J状态),物理上标识当前包的传输结束。与令牌包和握手包的EOP信号形式相同。

    关键补充说明

    PID与数据切换(Data Toggle):DATA0和DATA1 PID是数据包可靠性的核心。发送方和接收方各自维护一个“切换位”。成功传输一个数据包后,双方同步地将期待的下一个PID从DATA0切至DATA1,或从DATA1切回DATA0。如果接收方收到一个非预期的PID(如连续两个DATA0),则表明发生了丢包或重复,可据此进行恢复。DATA2和MDATA用于高速等时传输的更复杂序列。

    DATA字段的长度限制:
    低速:最大 8 字节。

    全速:
    控制传输:最大 8、16、32 或 64 字节(由设备描述符bMaxPacketSize0指定)。
    中断/批量传输:最大 64 字节。
    同步传输:最大 1023 字节。

    高速:
    控制传输:最大 64 字节。
    批量传输:最大 512 字节。
    中断传输:最大 1024 字节。
    等时传输:最大 1024 字节。

    特殊的数据包形式:
    Setup包:在控制传输中,它是一个DATA字段固定为8字节、PID固定为DATA0的数据包,用于承载主机发送给设备的请求(bmRequestType, bRequest, wValue, wIndex, wLength)。
    Status包:在控制传输的状态阶段,它是一个DATA字段长度为0、PID固定为DATA1的数据包,用于确认整个控制传输的完成。
    与令牌包字段的对比:数据包没有ADDR(地址)和ENDP(端点)字段,因为这些信息由发起此次数据传输的前置令牌包(IN或OUT)已经指定。数据包使用更强大的CRC16(而非CRC5)来保护其可变长的数据载荷。


4.3.3 :握手包
  1. 对刚刚完成的事务阶段给予“成功”、“忙”或“出错”的即时反馈。握手包是整个USB通信可靠性和流量控制的基石。它不携带任何应用数据,只传递状态。

    关键类型与作用

    • ACK (Acknowledge):确认。接收方(设备或主机)无误地收到了数据包
    • NAK (Negative Acknowledge):否定。设备暂时无法发送或接收数据(例如:缓冲区满、尚未准备好)。
    • STALL:停滞。端点发生了错误或请求不被支持。主机需要介入修复(如复位端点)。
    • NYET:尚未就绪。仅用于高速传输,表示“这次数据收到了,但缓冲区已满,下次发送前请先询问(PING)”。
    • 同步传输 :(如音频、视频)没有握手包,为了确保实时性,它牺牲了可靠性(数据出错不重传)。

    指定目标:包含设备地址和端点号,精确地指出与哪一个设备的哪一个“数据通道”(端点)进行通信。
    简单比喻:就像一个物流中心的调度员,拿着喇叭喊:“3号仓库的1号门(地址3,端点1),现在请你把货发出来(IN)!”

    握手包(Handshake Packet)字段详解

    字段名称长度(位)在包中的位置作用与描述示例/备注
    SYNC8 (低速/全速)
    32 (高速)
    起始时钟同步。固定的位模式,用于接收方同步时钟,准确采样后续的PID。虽然握手包很短,但仍需要同步以确保可靠接收。同其他包,是一个特定的边沿信号。
    PID8SYNC之后握手包标识符。这是握手包的核心,唯一的有效信息字段,直接表达事务的状态结果。0xD2 = ACK
    0x5A = NAK
    0x1E = STALL
    0x96 = NYET (仅高速)
    EOP信号电平包末尾包结束。一个特定的信号状态(SE0后接J状态),物理上标识当前包的传输结束。与令牌包和数据包的EOP信号形式相同。

    关键补充说明
    1 . 握手包的本质:握手包是USB通信中唯一一个只包含PID而不携带任何应用数据的包。它结构简单,没有地址、端点和数据字段,也没有CRC校验(PID自身的校验位已足够)。它的唯一目的就是提供即时状态反馈。

    2 . PID的详细解释:
    ACK (Acknowledge):成功确认。接收方(可能是主机或设备)无误地收到了数据包(CRC校验正确,且数据切换PID符合预期)。这是事务成功的标志。

    NAK (Negative Acknowledge):临时否定。只能由设备发送,表示设备暂时无法处理该事务(例如:输入端点尚无数据可发,或输出端点缓冲区已满)。这不是错误,而是一种流量控制机制,主机会稍后重试。

    STALL:功能错误/停滞。只能由设备发送,表示端点遇到了无法自行恢复的错误(如收到了不支持的请求),或已被明确停止(Halted)。这是一个错误状态,通常需要主机通过控制传输进行干预(如发送CLEAR_FEATURE请求来复位端点)。

    NYET (Not Yet):尚未就绪。仅用于高速传输,且仅由设备在特定的分割事务或PING协议中发送。它表示“当前数据事务已成功,但接收缓冲区将满,请主机在发送下一个数据包前先进行查询(PING)”。

    3 . 握手包的发送方向:
    在 IN 事务 中,数据包由设备发送,若主机成功接收,则主机回复 ACK 握手包;若接收出错,主机不回复任何握手包(即超时)。

    在 OUT/SETUP 事务 中,数据包由主机发送,若设备成功接收,则设备回复 ACK;若设备忙则回复 NAK;若端点出错则回复 STALL。

    4 . 握手包的缺失:等时传输(Isochronous)没有握手包。这是由其实时性特性决定的——为了确保固定的传输速率和低延迟,等时传输宁可容忍偶尔的数据错误,也不愿通过重传机制破坏时序。
    握手包与错误处理:

    如果接收方检测到数据包的 CRC 错误,它会直接丢弃该包,且不发送任何握手包。发送方会因收不到预期的ACK(或NAK/STALL)而超时,并触发重传机制。

    握手包本身没有CRC字段,其完整性依靠其很短的固定长度(只有SYNC和PID)以及PID自身高4位的校验码来保证。


4.4 首次通信

  1. 当主机识别到有设备接入后,主机会在总线上对 { “地址0” “端点0” } 发送信息,从机接入时,从 { “地址0” “端点0” } 处接收信息,这里的信息包含了主机分配给从机的 新地址,从机回复主机确认后,从机按 新地址 自居,从机找到家了,从此可以和主机愉快的生活了,主机就可以到 新地址 访问了,然后主机会向 新地址 请求完整的 设备描述符,配置描述符 来获取接口,如果接口存在多个,会继续遍历,当主机知晓设备的完整信息后,就完成了 枚举 的过程。

4.5 USB描述符

描述符前言 :

  • 在写描述符之前,这里将USB意义简述一下。
  • USB协议总是主机发起通信,如果从机的内容比较多,那么主机该如何与从机的某个局部信息进行交互呢?
  • 无论从机有多少信息,我们把它分而治之不就可以了吗,就像一省有N市,一市有N镇,一镇有N村,假如你想了解某个人的信息,那么通过省市镇村就可以找到对方进行交互,USB协议里也是一样,逐层解析。
  • 所以诞生了设备描述符,配置描述符,接口描述符,端点描述符,报告描述符,特殊描述符,字符串描述符,各描述符都有自己的数据结构,以下详述了各描述符意义。
  • 以下引用部分CherryUSB协议栈的数据结构描述

在这里插入图片描述

4.3.1 设备描述符
  1. 设备的基本信息: 设备描述符包含了有关 USB 设备的基本信息,如设备类别、设备子类别、设备协议、最大包大小等。这些信息有助于主机系统正确识别和配置设备
  2. 供应商和产品标识: 设备描述符包含供应商标识(Vendor ID)和产品标识(Product ID),这两个标识唯一地标识了设备的制造商和产品。这对于主机系统正确识别和匹配设备驱动程序非常重要
  3. 设备版本信息: 设备描述符包含了设备的版本号,有助于主机系统确定设备的硬件或固件版本。
  4. 设备支持的 USB 规范版本: 设备描述符指明了设备支持的 USB 规范版本,这有助于主机系统适配与设备进行通信。
  5. 配置描述符的索引: 设备描述符中包含配置描述符的索引,主机系统可以通过这个索引获取设备的配置信息。
#define USB_DEVICE_DESCRIPTOR_INIT(bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, idVendor, idProduct, bcdDevice, bNumConfigurations) \
	0x12,                       /* bLength */                                                                                              \
    USB_DESCRIPTOR_TYPE_DEVICE, /* bDescriptorType */                                                                                      \
    WBVAL(bcdUSB),              /* bcdUSB */                                                                                               \
    bDeviceClass,               /* bDeviceClass */                                                                                         \
    bDeviceSubClass,            /* bDeviceSubClass */                                                                                      \
    bDeviceProtocol,            /* bDeviceProtocol */                                                                                      \
    0x40,                       /* bMaxPacketSize */                                                                                       \
    WBVAL(idVendor),            /* idVendor */                                                                                             \
    WBVAL(idProduct),           /* idProduct */                                                                                            \
    WBVAL(bcdDevice),           /* bcdDevice */                                                                                            \
    USB_STRING_MFC_INDEX,       /* iManufacturer */                                                                                        \
    USB_STRING_PRODUCT_INDEX,   /* iProduct */                                                                                             \
    USB_STRING_SERIAL_INDEX,    /* iSerial */                                                                                              \
    bNumConfigurations          /* bNumConfigurations */

设备描述符总结

  • 设备描述符是设备插入 USB 总线时被主机系统主动请求的第一个描述符。
  • 主机系统通过读取设备描述符可以获取设备的基本特性,从而为设备进行正确的配置和管理。
  • 设备描述符是 USB 设备描述符的核心组成部分,提供了主机系统获取关于设备基本信息的入口,有助于主机正确识别、配置和与设备进行通信。

4.3.2. 配置描述符
  1. 配置的基本信息: 配置描述符包含了有关设备配置的基本信息,如配置值、总长度、最大功率需求等。这些信息有助于主机系统了解设备的配置。
  2. 接口数量: 配置描述符指明了该配置下包含的接口的数量,主机系统可以通过这个信息了解设备提供了多少个功能或服务。
  3. 供电特性: 配置描述符包含了设备的供电特性,例如设备是否通过总线供电、是否支持远程唤醒等。
  4. 接口描述符的索引: 配置描述符中包含了接口描述符的索引,主机系统可以通过这个索引获取配置下每个接口的详细信息。
  5. 分配地址的标志: 配置描述符中的"bAttributes"字段指明了该配置是否是用于分配设备地址的配置,这对于 USB 设备的初始化阶段很重要。
#define USB_CONFIG_DESCRIPTOR_INIT(wTotalLength, bNumInterfaces, bConfigurationValue, bmAttributes, bMaxPower) \
    0x09,                              /* bLength */                                                       \
    USB_DESCRIPTOR_TYPE_CONFIGURATION, /* bDescriptorType */                                               \
    WBVAL(wTotalLength),               /* wTotalLength */                                                  \
    bNumInterfaces,                    /* bNumInterfaces */                                                \
    bConfigurationValue,               /* bConfigurationValue */                                           \
    0x00,                              /* iConfiguration */                                                \
    bmAttributes,                      /* bmAttributes */                                                  \
    USB_CONFIG_POWER_MA(bMaxPower)     /* bMaxPower */

配置描述符总结

  • 配置描述符提供了主机系统有关设备配置的基本信息。
  • 一个 USB 设备可以有一个或多个配置,每个配置可以包含一个或多个接口,每个接口可以包含一个或多个端点。
  • 主机系统通过读取配置描述符,能够了解设备的整体结构和提供的功能,从而为设备进行正确的配置和管理。
  • 配置描述符是 USB 设备描述符的关键组成部分,有助于主机系统正确识别、配置和与设备进行通信。

4.3.3. 接口描述符
  1. 接口的基本信息: 接口描述符包含了关于接口的基本信息,如接口号、接口类别、子类别、协议等。
  2. 端点数量: 接口描述符指明了该接口上包含的端点的数量。每个端点用于不同的数据传输目的,如控制传输、批量传输、中断传输或同步/异步传输等。
  3. 接口描述符的索引:接口描述符中包含了该接口的索引,主机系统可以通过这个索引获取接口的详细信息。
  4. 接口的特殊属性: 接口描述符中的一些字段提供了关于接口的特殊属性的信息,如是否支持 HID(Human Interface Device)等。
  5. 接口关联描述符: 在某些情况下,接口描述符可能包含关联其他接口的信息,用于表示多个接口之间的关系。
// 示例:CDC控制接口(接口0)
    0x09,                           // bLength: 固定9字节
    USB_DESCRIPTOR_TYPE_INTERFACE,  // bDescriptorType: 接口描述符(0x04)
    0x00,                           // bInterfaceNumber: 接口编号(0)
    0x00,                           // bAlternateSetting: 备选设置(通常0)
    0x01,                           // bNumEndpoints: 此接口拥有的端点数量(1个,即INT端点)
    0x02,                           // **bInterfaceClass: 类代码(0x02 = Communication)**
    0x02,                           // **bInterfaceSubClass: 子类(0x02 = Abstract Control Model)**
    0x01,                           // **bInterfaceProtocol: 协议(0x01 = AT Commands)**
    0x00,                           // iInterface: 描述此接口的字符串索引(常为0)

// 示例:CDC数据接口(接口1)
    0x09,
    USB_DESCRIPTOR_TYPE_INTERFACE,
    0x01,                           // bInterfaceNumber: 接口编号(1)
    0x00,
    0x02,                           // bNumEndpoints: 2个端点(BULK IN和OUT)
    0x0A,                           // **bInterfaceClass: 类代码(0x0A = CDC Data)**
    0x00,                           // bInterfaceSubClass: 子类(0)
    0x00,                           // bInterfaceProtocol: 协议(0)
    0x00,

接口描述符总结

  • 接口描述符对于主机系统正确识别和配置设备的每个接口非常重要。
  • 主机系统通过读取接口描述符可以了解设备提供了多少个接口,每个接口的功能是什么,以及每个接口上有多少个端点。
  • 接口描述符是 USB 设备描述符的一部分,用于提供关于每个接口的基本信息,帮助主机系统正确识别、配置和与设备进行通信。

4.3.4. 端点描述符
  1. 端点地址(Endpoint Address): 描述端点的地址,包括方向(输入或输出)和端点号。
  2. 端点类型(Attributes): 描述端点的类型,如控制、同步、异步等。
  3. 最大包大小(Max Packet Size):表示每个 USB 事务中传输的最大数据包大小。
  4. 传输间隔(Interval): 对于同步和中断端点,表示两次传输之间的时间间隔。
// 示例:批量OUT端点(地址0x02)
    0x07,                           // bLength: 固定7字节
    USB_DESCRIPTOR_TYPE_ENDPOINT,   // bDescriptorType: 端点描述符(0x05)
    CDC_OUT_EP,                     // bEndpointAddress: 端点地址(0x02,方向OUT)
    0x02,                           // **bmAttributes: 传输类型(0b0010 = 批量传输)**
                                     //    (0b0011 = 中断传输,0b0001 = 同步传输)
    0x40, 0x00,                     // wMaxPacketSize: 最大包长(全速模式下64字节)
    0x00,                           // bInterval: 轮询间隔(批量传输忽略,中断传输需设置)

// 示例:中断IN端点(地址0x83)
    0x07,
    USB_DESCRIPTOR_TYPE_ENDPOINT,
    CDC_INT_EP,                     // bEndpointAddress: (0x83,方向IN)
    0x03,                           // bmAttributes: 中断传输(0b0011)
    0x08, 0x00,                     // wMaxPacketSize: 8字节(状态通知数据量小)
    0x0A,                           // **bInterval: 轮询间隔10个帧(即10ms)**

端点描述符总结

  • 端点描述符提供了主机系统关于设备上每个端点的详细信息,主机系统根据这些信息来正确配置和管理数据传输。
  • 不同类型的端点有不同的用途,例如控制端点用于设备和主机之间的基本控制和配置,而同步和异步端点则用于数据传输等。
  • 每个 USB 接口可以包含多个端点,其中包括一个控制端点(Endpoint 0),用于设备和主机之间的基本通信。
  • 端点描述符通常跟随在接口描述符之后,为主机系统提供有关每个端点的配置信息。
  • 端点描述符是 USB 设备描述符的关键组成部分,提供了主机系统关于设备上每个端点的详细信息,有助于正确配置和管理数据传输。

4.3.5. 报告描述符
  1. 定义数据结构: 描述HID设备发送和接收的数据报告的具体格式,包括字段数量、大小、用途等。。
  2. 描述数据项: 定义每个数据项(如按键、坐标、状态等)的用途、逻辑范围、单位等属性。
  3. 编码方式:使用紧凑的二进制格式描述复杂的数据结构,通过项目序列定义各种数据字段。
  4. 报告类型: 通常包括输入报告(设备到主机)、输出报告(主机到设备)和特征报告(双向配置数据)。
  5. 用途说明: 让主机能够正确解析来自HID设备的原始数据,如将字节流转换为有意义的按键事件或鼠标移动。
每个数据项的第一个字节(前缀)定义了它的类型和作用,结构如下:
Bits:  [7:6]       [5:4]         [3:0]
功能:  项目类型    项目标签       数据大小(bSize)

1. 项目类型 (2位,bits 7:6)(二进制)	类型	说明
00			主项目	定义或分组报告的数据域,类似于语言中的“名词”,描述报告里有什么。
01			全局项目	描述数据的通用属性(如逻辑范围、单位),其状态会持续影响后续所有项目,直到被改变,类似于“形容词”。
10			局部项目	描述特定用途的属性(如用法、字符串索引),其影响范围通常到下一个主项目为止,类似于“修饰语”。
11			保留	未使用。


2. 项目标签 (4位,bits 5:4 与 bits 3:0 的一部分)
与项目类型结合,共同确定项目的具体含义。例如,0x81 (1000 0001) 表示一个全局项目(类型10),标签是Input。


3. 数据大小 (2位,bits 3:2)
定义该项目后跟随的数据字节数:
bSize	数据字节数
00		0字节
01		1字节
10		2字节
11		4字节
static const uint8_t hid_mouse_report_desc[] = {
    // ===== 全局项:设置使用场景 =====
    0x05, 0x01,     // Usage Page (Generic Desktop)      // 全局项:声明主功能在“通用桌面”页面
    0x09, 0x02,     // Usage (Mouse)                     // 局部项:具体用途是“鼠标”
    0xA1, 0x01,     // Collection (Application)          // 主项:开始一个“应用集合”,描述整个鼠标功能

    // ===== 第一层:鼠标按键 =====
    0x09, 0x01,     //   Usage (Pointer)                 // 局部项:用途是指针设备
    0xA1, 0x00,     //   Collection (Physical)           // 主项:开始一个“物理集合”,描述物理上的指针

    // --- 定义3个独立按键(每个占1 bit) ---
    0x05, 0x09,     //     Usage Page (Button)           // 全局项:切换到“按键”页面
    0x19, 0x01,     //     Usage Minimum (Button 1)      // 局部项:最小用途ID是按键1
    0x29, 0x03,     //     Usage Maximum (Button 3)      // 局部项:最大用途ID是按键3(共3个按键)
    0x15, 0x00,     //     Logical Minimum (0)           // 全局项:数据的逻辑最小值是0(未按下)
    0x25, 0x01,     //     Logical Maximum (1)           // 全局项:数据的逻辑最大值是1(按下)
    0x95, 0x03,     //     Report Count (3)              // 全局项:接下来有3个字段
    0x75, 0x01,     //     Report Size (1)               // 全局项:每个字段占1个比特
    0x81, 0x02,     //     Input (Data,Var,Abs)          // 主项:定义3个1比特的输入字段,代表按键1-3

    // --- 定义5个填充位(占5 bit) ---
    0x95, 0x01,     //     Report Count (1)              // 全局项:接下来有1个字段(组)
    0x75, 0x05,     //     Report Size (5)               // 全局项:该字段(组)占5个比特
    0x81, 0x01,     //     Input (Cnst,Var,Abs)          // 主项:定义5个比特的常量输入字段(填充,无意义)

    // ===== 第二层:鼠标移动和滚轮 =====
    0x05, 0x01,     //     Usage Page (Generic Desktop)  // 全局项:切回“通用桌面”页面
    0x09, 0x30,     //     Usage (X)                     // 局部项:用途是X轴
    0x09, 0x31,     //     Usage (Y)                     // 局部项:用途是Y轴
    0x09, 0x38,     //     Usage (Wheel)                 // 局部项:用途是滚轮(垂直滚轮)

    0x15, 0x81,     //     Logical Minimum (-127)        // 全局项:数据逻辑最小值是-127
    0x25, 0x7F,     //     Logical Maximum (127)         // 全局项:数据逻辑最大值是127
    0x75, 0x08,     //     Report Size (8)               // 全局项:每个字段占8个比特(1字节)
    0x95, 0x03,     //     Report Count (3)              // 全局项:接下来有3个字段(X, Y, Wheel)
    0x81, 0x06,     //     Input (Data,Var,Rel)          // 主项:定义3个8比特的**相对值**输入字段

    0xC0,           //   End Collection                  // 主项:结束“物理集合”
    0xC0            // End Collection                    // 主项:结束“应用集合”
};


报告描述符总结

  • 报告描述符是在 HID 类别中定义的,典型的 HID 设备如键盘或鼠标通常会包含一个或多个报告描述符。
  • 主机系统通过读取报告描述符可以了解 HID 设备生成数据报告的结构,从而正确解析和处理来自 HID 设备的数据。
  • 报告描述符在 HID 设备中起到了定义设备数据报告结构的关键作用,它是 USB 设备描述符的一部分,用于描述 HID 设备生成的数据报告的格式和内容。

4.3.6. 特殊描述符
  1. String Descriptor(字符串描述符): USB 设备可以包含多个字符串描述符,用于提供设备的可读文本信息,如制造商名称、产品名称、序列号等。

  2. Interface Association Descriptor(接口关联描述符): 这是一种辅助描述符,用于关联多个接口。例如,一个设备可能同时提供音频输入和输出,这两个功能可能被关联在一起。

  3. Endpoint Companion Descriptor(端点伴随描述符): 在 USB 3.0 中引入,提供了关于端点的额外信息,如是否支持超速传输等。

  4. BOS (Binary Object Store) Descriptor(二进制对象存储描述符): 用于提供设备的固件升级和其他二进制对象的信息。

  5. Device Capability Descriptor(设备能力描述符): 提供了关于设备支持的一些特殊功能和能力的信息,如 USB PD(USB Power Delivery)的支持等。

特殊描述符总结

  • 一般HID,CDC设备会带有特殊描述符,补充描述
  • 这些描述符可能是标准描述符,也可能是设备特定的描述符。
  • 特殊描述符的存在使得设备能够提供额外的信息,或者支持一些规范中未明确定义的功能。
  • 需要查阅设备的技术文档或者 USB 设备的特定规范以了解特殊描述符的具体细节和用途,因为它们的内容和用途在不同类型的设备中可能有很大的差异。

4.3.7. 字符串描述符
  1. 语言标识符描述符(Language ID Descriptor): 这是一种特殊的字符串描述符,用于指示设备支持的语言。语言标识符描述符的索引为零,它的值是一个语言标识符列表,表示设备支持的语言。

  2. 字符串描述符: 每个字符串描述符包含了一个 UTF-16 编码的字符串,用于表示特定的信息,如制造商名称、产品名称、序列号等。字符串描述符的索引值是非零的,每个索引值对应一种特定的字符串。

// 字符串描述符数组(注意:索引0是语言ID)
// 索引0:语言ID(例如美式英语 0x0409)
USB_LANGID_INIT(USBD_LANGID_STRING),
// 索引1:制造商字符串
0x14, 0x03, 'C',0, 'h',0, 'e',0, 'r',0, 'r',0, 'y',0, 'U',0, 'S',0, 'B',0,
// 索引2:产品字符串
0x26, 0x03, 'C',0, 'h',0, ..., 'D',0, 'E',0, 'M',0, 'O',0,
// 索引3:序列号字符串
0x16, 0x03, '2',0, '0',0, '2',0, '2',0, '1',0, '2',0, '3',0, '4',0, '5',0, '6',0,

字符串描述符总结

  • 字符串描述符的格式包括一个字节的长度信息,后面是一个或多个包含 UTF-16 编码的字符。
  • USB 规范规定字符串描述符的字符编码必须为 UTF-16LE(Little Endian)。
  • 例如,如果要获取设备的制造商名称,主机系统可以向设备发送请求,指定索引值为设备制造商名称的字符串描述符,设备会回复一个包含制造商名称的字符串描述符。
  • 字符串描述符提供了对设备信息的人类可读访问,有助于用户和操作系统正确识别和管理连接到系统的 USB 设备。
  • 字符串描述符是 USB 设备描述符中的一种类型,用于提供设备的人类可读的文本信息。

4.6 数据通信

USB协议里从机不会主动发起通信,因为主机很多事情做,总线却只有一个,所以当主机 “忙完”, 就会主动向从机发起通信,通信过程包含三种情况。

在这里插入图片描述

  1. 控制传输: 用于在主机和设备之间进行基本的命令和配置
  2. 批量传输: 用于需要高带宽但不要求低延迟的数据传输
  3. 中断传输: 用于传输具有周期性且对延迟敏感的小量数据
  4. 同步传输: 用于实时传输音频、视频等对数据完整性要求不高但对实时性要求较高的应用

主机一开始请求过程会发送令牌包(TOKEN),请求中声明有数据要传输则有数据过程(长度描述不为0),最后由从机发起状态过程,结束本次通信。
如果主机向从机获取数据,那么主机获取到数据后,状态过程由主机发起结束。


4.7 :设备类型描述

  1. HID设备是人机交互设备,鼠标键盘这些为HID设备
  2. CDC设备是数据通信类,例如USB模拟串口这类

HID设备的数据在报告描述符内描述数据结构,然后就可以通过传输包来交互数据,报告描述符网上很多,若是不需要深入了解,可以直接用现成的。

5 . 小结

  1. 传输都由主机发起,一共四种传输(控制传输,中断传输,批量传输,同步传输),一次传输分为事务三种(setup事务,in事务,out事务),事务下面是包,都分别是令牌包、数据包(可选)、握手包(可选)组成,包下面是具体的字段,然后setup事务是枚举阶段用的,还有无其他阶段不确定,然后in事务是用来获取设备的数据的,out事务是主动往设备发数据,USB的4种传输类型,每种传输由一种或多种事务组成,事务有3种基本类型:SETUP、IN、OUT,关于SETUP事务:不仅用于枚举,正常运行时也用于类特定命令(如HID的Set_Report、CDC的Set_Line_Coding等)。

    控制传输 = 1个SETUP事务 + 0个或多个IN/OUT事务(DATA阶段)+ 1个STATUS事务(也是一个IN或OUT事务)
    其他传输(中断/批量/同步)= N个连续的IN事务或N个连续的OUT事务

  2. 一开始是设备描述符,用来描述设备的vid,pid,设备的usb版本然后是配置描述符

  3. 配置描述符里一般直接描述接口描述符,端点描述符,主机通过配置描述符的wTotalLength字段一次性读取整个配置链(配置+接口+端点+类特定描述符)。

  4. 接口描述符描述设备是什么类型,例如hid,cdc,还是0xff自定义设备,然后端点描述符描述端点地址,端点的缓存区大小,以及端点希望主机要多久查询一次

  5. 关于每个包里面的字段,再深入就是物理层了,而usb采用NRZI编码,因为usb定义全速和低速要从物理层区分开,所以分为了j和k状态,两者差分状态相反,全速时j为差分1好像,然后k为差分0,然后NRZI编码,是从NR(中间会经过0电平停顿),NRZ(会直接跳变),NRZI(逢0跳变,逢1维持,若连续6个1,则强制加入一个0,以让双方同步,防止频偏误差),物理层是反过来推导的,是先有数据流A,根据数据流做连续6个1做强制插入1个0来同步频偏误差,当这一层进行完后得到新一组数据B,再进行NRZI逢0变化,逢1维持,得到新一组数据C,然后最后根据数据流C进行JK转化差分真正物理层输出

    原始数据流A:要发送的二进制比特(如 110111111…)
    位填充后数据流B:检测连续6个’1’,插入一个’0’(得到 1101111101…)
    NRZI编码后电平序列C:逢’0’跳变,逢’1’维持(得到一个J/K状态序列)
    物理输出:将J/K状态转化为D+/D-的差分电压。

技术交流QQ群 : 745662457
群内专注 - 问题答疑,技术研究

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客 - L U

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值