1. USB协议基础回顾:USB 2.0与USB 3.x体系结构差异、传输类型概述、USB描述符层级结构

做USB开发这么多年,我见过太多工程师一上来就调批量传输,结果死活跑不满带宽。回头一看,连端点描述符里的wMaxPacketSize都配错了。说白了,USB调优的根基就在协议本身。这一章我们先把地基夯实。

1.1 USB 2.0与USB 3.x体系结构差异

USB 2.0和USB 3.x,别看接口长得差不多,内部完全是两套东西。我刚开始从2.0切到3.0时,以为只是速度翻倍,结果被主机控制器驱动折腾了一周。

对比项 USB 2.0 (Hi-Speed) USB 3.x (SuperSpeed)
信号线 D+ / D- (差分对) D+ / D- + SSTX / SSRX (两对差分)
传输模式 半双工,主机轮询 全双工,异步通知
拓扑结构 星型,最多7层Hub 星型,但引入双总线架构
数据传输 帧/微帧调度 (1ms / 125µs) 包路由 + 流控 (异步)
电源管理 全局挂起/唤醒 链路级电源管理 (U0-U3)

这里有个关键点:USB 2.0是主机主动轮询,设备只能等主机来问。而USB 3.x引入了异步通知机制,设备可以主动发NRDY告诉主机“我还没准备好”。这个差异对批量传输性能影响巨大,后面我们会专门讲。

核心差异一句话总结:USB 2.0是共享总线、半双工、轮询驱动;USB 3.x是点对点通道、全双工、流控驱动。你调批量传输时,脑子里必须清楚当前跑在哪个协议版本上。

1.2 传输类型概述

USB定义了四种传输类型。每种类型都有它的脾气。我见过有人拿中断传输传大块数据,结果带宽惨不忍睹。选对类型,调优就成功了一半。

控制传输 (Control Transfer)

这是USB的“官方语言”。设备枚举、描述符获取、命令下发都走这条路。控制传输有固定的三个阶段:Setup、Data(可选)、Status。我建议你在调试初期,先用逻辑分析仪抓一下控制传输的包,确认设备枚举正常,再往下走。

批量传输 (Bulk Transfer)

咱们课程的主角。批量传输的特点是:保证数据正确,但不保证延迟。USB 2.0下批量传输占满带宽没问题,但USB 3.x下要小心流控机制。我曾经在一个项目中,批量传输速率死活上不去,最后发现是端点没配成Stream模式。

中断传输 (Interrupt Transfer)

名字叫“中断”,其实还是主机轮询。只是轮询间隔可以保证。适合鼠标、键盘这类需要低延迟的小数据量设备。注意:USB 2.0中断传输最大包只有64字节,USB 3.x可以到1024字节。

同步传输 (Isochronous Transfer)

没有重传机制,数据丢了就丢了。适合音频、视频这类实时流。同步传输对带宽有预留保证,但代价是没有纠错。我调试USB摄像头时,经常要在这上面做文章。

传输类型 保证交付 保证延迟 带宽预留 典型应用
控制 是 否 10% 枚举、命令
批量 是 否 剩余带宽 U盘、数据采集
中断 是 是 有上限 HID设备
同步 否 是 有预留 音频、视频

我的经验:批量传输在USB 2.0下理论带宽是53.248 MB/s,但实际能跑到40 MB/s就算不错了。别被理论值忽悠,后面我们会手把手教你测实际吞吐量。

1.3 USB描述符层级结构

描述符是USB设备的“身份证”。主机通过读取描述符来了解设备是什么、能干什么。描述符的层级结构,说白了就是一棵树。

USB描述符层级结构 设备描述符 配置描述符 接口描述符 端点描述符 说明: • 一个设备只有一个设备描述符 • 一个设备可以有多个配置描述符(但同一时间只能激活一个) • 一个配置下可以有多个接口描述符(复合设备常见) • 一个接口下可以有多个端点描述符(控制端点0除外)

嗯,这里要注意:描述符的获取顺序是固定的。主机先拿设备描述符,再拿配置描述符,然后根据配置描述符里的信息,逐个拿接口和端点描述符。我调试时习惯用USB树查看器先看一眼描述符结构,确认无误再写固件。

设备描述符 (Device Descriptor)

最顶层,描述设备的VID、PID、USB版本、最大包大小等。其中bMaxPacketSize0这个字段特别重要,它决定了端点0的控制传输包大小。我见过有人把这里配成64,但实际硬件只支持8,结果枚举失败。

配置描述符 (Configuration Descriptor)

描述设备的功耗、供电方式、接口数量等。一个设备可以有多个配置,但同一时间只能激活一个。比如一个设备可以有一个“全功能配置”和一个“省电配置”。

接口描述符 (Interface Descriptor)

描述一个功能单元。比如一个复合设备可能有“键盘接口”和“鼠标接口”。接口描述符里会指明使用的端点数量。

端点描述符 (Endpoint Descriptor)

这是咱们调优的重点。端点描述符定义了端点的地址、方向、传输类型、最大包大小、轮询间隔等。批量传输的性能,很大程度上取决于wMaxPacketSize和bInterval的配置。

避坑指南:我曾经在一个项目中,把批量端点的wMaxPacketSize配成了512字节(USB 2.0下合法值),但主机控制器驱动只支持到64字节的批量传输。结果数据传着传着就卡死了。所以,描述符里的值一定要和主机控制器能力匹配。

1.4 描述符与端点配置的关系

描述符是静态的,端点配置是动态的。设备枚举时,主机读取描述符,然后根据描述符里的信息来配置端点。端点配置的核心参数包括:

  • 端点地址:低4位是端点号,高位是方向(IN/OUT)
  • 传输类型:控制、批量、中断、同步
  • 最大包大小:USB 2.0批量最大512字节,USB 3.x批量最大1024字节
  • 轮询间隔:批量传输在USB 2.0下固定为0,USB 3.x下可以配置

我个人习惯在固件里把端点描述符定义成一个结构体数组,方便后期调优时修改参数。比如批量传输的wMaxPacketSize,我通常会先配成硬件支持的最大值,然后根据实际测试结果往下调。

调优起点:批量传输性能调优,第一步就是确认端点描述符里的wMaxPacketSize和bInterval是否与主机控制器驱动匹配。不匹配的话,后面所有努力都是白费。