3、USB传输类型:控制传输、批量传输、中断传输、同步传输
做USB调试这些年,我最常被问的问题就是:“这四种传输到底怎么选?”说实话,我刚入行也懵——Spec上写得清楚,可一落地就各种坑。今天咱们把这四种类型掰开揉碎,从帧结构到实际雷区,一次性讲透。
3.1 控制传输(Control Transfer)
特点:唯一双向的传输类型,由主机发起,用于设备枚举、命令配置、状态查询。它有两个阶段:Setup阶段(主机发请求)+ Data阶段(可选,双向)+ Status阶段(握手)。我习惯把控制传输比作“指挥官的指令通道”——设备还没准备好批量干活,先靠它把规矩定好。
应用场景:USB描述符获取、设置地址、配置设备、类特定命令(如HID报告描述符)。几乎所有USB设备第一次插上电脑,枚举过程就是一连串的控制传输。
帧格式:控制传输在总线上的最小事务单元是包 + Data包 + Handshake包。但具体到Setup事务,格式固定:
// 控制传输的Setup包结构(8字节)
typedef struct {
uint8_t bmRequestType; // 方向(0=主机->设备,1=设备->主机) + 类型 + 接收者
uint8_t bRequest; // 请求码(如 GET_DESCRIPTOR = 0x06)
uint16_t wValue; // 参数高16位
uint16_t wIndex; // 参数低16位
uint16_t wLength; // 后续Data阶段传输的字节数
} USB_SETUP_PACKET;
3.2 批量传输(Bulk Transfer)
特点:非周期性、大块数据传输,通过错误检测和重传保证可靠。占用空闲总线带宽,优先级最低。你想想看,打印机或扫描仪传一页文档,几MB甚至几十MB,用批量传输最合适——不在乎慢个毫秒,但数据必须一字不差。
应用场景:U盘读写、打印机数据流、USB转串口、大容量存储设备(Mass Storage Class)。我个人做过一个工业相机,用批量传输把原始图像数据搬到PC,每帧几MB,CRC校验一遍都不放。
帧格式:批量传输只有数据阶段和握手阶段。数据包最大有效负载为64字节(全速)或512字节(高速)。主机发OUT +数据,设备回ACK/NAK/STALL;或者主机发IN ,设备回数据+ACK。
| 端点方向 | 主机动作 | 设备响应 | 备注 |
|---|---|---|---|
| OUT | 发OUT +数据 | 返回ACK(接收成功)/ NAK(忙)/ STALL(错误) | 批量写 |
| IN | 发IN | 发数据+ACK,或发NAK/STALL | 批量读 |
3.3 中断传输(Interrupt Transfer)
特点:周期性查询,保证最大延迟(bInterval字段指定轮询间隔)。全速端点间隔1~255ms,高速端点最小125μs(微帧)。数据丢失会重传,可靠但占用带宽小。
应用场景:鼠标、键盘、游戏手柄、HID类设备,以及需要及时响应的自定义设备。比如我做过一个USB脚踏开关,要求按键按下后10ms内上报,用中断传输,间隔设置成8ms,用户几乎感受不到延迟。
帧格式:主机在每个轮询间隔发送IN ,设备返回数据+ACK,或NAK(无数据上报)。数据包最大有效负载:全速64字节,高速1024字节(实际受限于bInterval)。
3.4 同步传输(Isochronous Transfer)
特点:固定带宽、无重传、保证传输速率但不保证数据正确。它不握手,丢了就丢了。说白了,就是“实时优先,正确靠后”。音频、视频这种丢了几个字节只感觉一丁点杂音,人耳能接受,但延迟高了直接卡顿,那就没法忍。
应用场景:USB摄像头(UVC)、USB麦克风(UAC)、扬声器、数字视频采集。我做USB麦克风调试时,同步端点带宽预留不够,高频段总是爆音。后来改大端点的wMaxPacketSize才解决。
帧格式:主机发IN/OUT 后直接传数据,没有握手阶段。数据包大小固定,全速最大1023字节,高速最大1024字节(实际受总线带宽限制)。同步传输还分“数据同步类型”:异步、同步、自适应,多数设备用同步(时钟同步)。这里不展开了。
| 传输类型 | 可靠性 | 带宽保证 | 典型数据量 | 典型端点方向 | 重传 |
|---|---|---|---|---|---|
| 控制 | 高 | 低 | 小(≤64B) | 双向(EP0) | 有 |
| 批量 | 高 | 无 | 大(≥512B) | 单向(IN/OUT) | 有 |
| 中断 | 高 | 有(按间隔) | 小(≤64B FS) | 单向(IN为主) | 有 |
| 同步 | 低 | 有(预留带宽) | 中(1023~1024B) | 单向(IN/OUT) | 无 |
以上就是四种传输类型的核心内容。嗯,你可能会问:实际调试中怎么快速判断一个端点用错了类型?我的经验是看描述符中的bEndpointAddress和bmAttributes。如果枚举失败,先抓一帧总线数据看看主机返回的STALL或者超时,十有八九是传输类型和端点特性不匹配。
最后一句不是套话:多动手抓包、多读Spec,比任何教程都管用。今天的内容够消化一阵了,拿你手边的设备测一测,哪里卡住就知道该翻哪一页了。