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;
避坑指南:我以前调试一块自定义HID设备,死活枚举不过。抓包一看,Setup包的wLength填错了——主机发GET_DESCRIPTOR时,设备应该回18字节,结果我填成了0。主机直接认为设备不想理它,掐断了枚举。记住:wLength一定要和实际返回数据长度匹配,多了少了都可能引发“超时”或“STALL”。

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 批量读
注意:全速Bulk端点一次数据包最大64字节,高速最大512字节,超长数据会拆成多帧。我曾经因为FPGA端Bulk FIFO深度不够,连续收到IN令牌时漏了帧,导致PC端文件校验失败。解决方法是保证端点FIFO至少能缓存两个最大包。

3.3 中断传输(Interrupt Transfer)

特点:周期性查询,保证最大延迟(bInterval字段指定轮询间隔)。全速端点间隔1~255ms,高速端点最小125μs(微帧)。数据丢失会重传,可靠但占用带宽小。

应用场景:鼠标、键盘、游戏手柄、HID类设备,以及需要及时响应的自定义设备。比如我做过一个USB脚踏开关,要求按键按下后10ms内上报,用中断传输,间隔设置成8ms,用户几乎感受不到延迟。

帧格式:主机在每个轮询间隔发送IN ,设备返回数据+ACK,或NAK(无数据上报)。数据包最大有效负载:全速64字节,高速1024字节(实际受限于bInterval)。

一个经验:中断传输的bInterval并不是越短越好。我见过有人给全速HID设1ms轮询,结果USB总线被这个端点占满,其他传输直接卡死。全速总线帧周期1ms,一个端点占1ms意味着整条总线就它一个在跑。建议:鼠标键盘设8~16ms,游戏手柄设4~8ms。

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) 无
USB四种传输类型判断流程图 USB传输类型 控制传输 批量传输 中断传输 同步传输 双向、可靠 小数据、命令 枚举/配置 单向大块 低优先级 存储/打印 周期性查询 低延迟 HID/实时输入 固定带宽 无重传 音频/视频 选择依据:数据类型 → 实时性要求 → 可靠性要求

以上就是四种传输类型的核心内容。嗯,你可能会问:实际调试中怎么快速判断一个端点用错了类型?我的经验是看描述符中的bEndpointAddress和bmAttributes。如果枚举失败,先抓一帧总线数据看看主机返回的STALL或者超时,十有八九是传输类型和端点特性不匹配。

最后一句不是套话:多动手抓包、多读Spec,比任何教程都管用。今天的内容够消化一阵了,拿你手边的设备测一测,哪里卡住就知道该翻哪一页了。