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树查看器先看一眼描述符结构,确认无误再写固件。
设备描述符 (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是否与主机控制器驱动匹配。不匹配的话,后面所有努力都是白费。