4. 批量传输特性:可靠性、带宽分配与数据包大小
批量传输(Bulk Transfer)是 USB 协议中唯一以“数据完整性优先”为设计目标的传输类型。在 QNX 嵌入式系统中,批量传输广泛用于存储设备(U 盘、eMMC 读卡器)、网络适配器(RNDIS/ECM)以及部分数据采集设备。理解其可靠性机制、带宽分配策略和数据包大小约束,是排查批量传输故障的理论基础。
4.1 批量传输的可靠性保障
批量传输通过硬件级重传和错误检测机制保证数据完整性,不依赖软件超时轮询。其可靠性由以下三层构成:
| 层次 | 机制 | 说明 |
|---|---|---|
| 物理层 | NRZI 编码 + 位填充 | 防止长连续电平导致时钟失锁,保证信号边沿密度 |
| 协议层 | CRC16 / CRC32 | 数据包尾部附加校验码,接收端校验失败则丢弃并等待重传 |
| 传输层 | ACK/NAK 握手 | 主机发送 OUT 后等待设备 ACK;设备发送 IN 后等待主机 ACK |
关键点:批量传输不保证延迟,但保证数据不丢失。在 QNX 驱动中,如果端点返回 NAK 超过一定次数,主机控制器(HCD)会触发错误恢复流程,驱动层应通过
usbd_ep_abort() 或重置端点来恢复。
4.2 带宽分配:批量传输的“剩余带宽”策略
USB 总线采用时分复用帧结构,批量传输在所有周期性传输(等时、中断)完成后,利用剩余带宽进行传输。这意味着:
- 优先级最低:等时传输 > 中断传输 > 批量传输 > 控制传输(特殊)
- 带宽不保证:如果总线上挂载了多个高速等时设备,批量传输可能长时间得不到调度
- 公平轮询:主机控制器(EHCI / xHCI)在每帧中轮询所有批量端点,但每个端点最多发送一次批量事务
| USB 版本 | 帧长度 | 批量传输最大理论带宽 | 实际可用带宽(典型) |
|---|---|---|---|
| USB 1.1(全速) | 1 ms | 1.216 MB/s | ~1.0 MB/s |
| USB 2.0(高速) | 125 µs(微帧) | 53.248 MB/s | ~40 MB/s |
| USB 3.0(超高速) | 125 µs | 400 MB/s(单向) | ~350 MB/s |
QNX 驱动排查提示:如果批量传输吞吐量远低于理论值,首先检查总线上是否存在高带宽等时设备(如 UVC 摄像头、USB 音频设备)。使用
io-usb-dso -v 查看当前帧分配情况,确认批量传输是否被周期性传输挤压。
4.3 数据包大小:全速、高速、超高速的差异
批量传输的数据包大小由 USB 规范严格定义,且与端点描述符中的 wMaxPacketSize 字段一致。不同速度等级下的固定值如下:
| 速度等级 | 批量端点 wMaxPacketSize | 每帧/微帧最大事务数 | 备注 |
|---|---|---|---|
| 全速(Full Speed) | 8 / 16 / 32 / 64 字节 | 1 | 通常配置为 64 字节 |
| 高速(High Speed) | 512 字节 | 最多 3 个突发事务 | 支持 Ping 协议 |
| 超高速(Super Speed) | 1024 字节 | 最多 16 个突发事务 | 支持 Streams 协议 |
QNX 端点配置示例:在 QNX 的
usbd_ep_init() 中,必须将 wMaxPacketSize 设置为对应速度的固定值。如果设备描述符中声明了非标准值(如全速批量端点设为 128 字节),主机将拒绝配置,驱动会返回 USBD_STATUS_INVALID_PARAM。
/* QNX 批量端点初始化代码片段 */
usbd_ep_init_t ep_init;
memset(&ep_init, 0, sizeof(ep_init));
ep_init.bEndpointAddress = 0x01 | USB_DIR_IN; /* 批量 IN 端点 */
ep_init.bmAttributes = USB_EPTYPE_BULK; /* 批量传输 */
ep_init.wMaxPacketSize = 512; /* 高速固定 512 字节 */
ep_init.bInterval = 0; /* 批量传输忽略此字段 */
status = usbd_ep_init(usbd_handle, &ep_init, &ep_handle);
if (status != USBD_STATUS_SUCCESS) {
fprintf(stderr, "批量端点初始化失败: 0x%x\n", status);
return -1;
}
4.4 批量传输故障排查要点
实战建议:在 QNX 下排查批量传输问题时,优先使用
•
•
•
usb_debug -t bulk 跟踪批量传输事务日志。关注以下关键指标:•
bulk_xfer_count:成功传输的事务数•
bulk_nak_count:NAK 重试次数(正常应 < 总事务数的 5%)•
bulk_error_count:CRC 错误或超时次数(应为 0)
4.5 批量传输与 QNX 内存对齐要求
QNX USB 驱动要求批量传输的 DMA 缓冲区满足以下对齐条件,否则可能导致数据损坏或 USBD_STATUS_INVALID_PARAM:
- 全速:缓冲区地址 4 字节对齐,长度任意
- 高速:缓冲区地址 512 字节对齐,长度必须是 512 的整数倍(最后一个短包除外)
- 超高速:缓冲区地址 1024 字节对齐,长度必须是 1024 的整数倍
/* 高速批量传输缓冲区分配示例 */
void *bulk_buffer;
posix_memalign(&bulk_buffer, 512, 512 * 64); /* 64 个 512 字节块 */
usbd_xfer_t *xfer = usbd_xfer_alloc(usbd_handle);
usbd_xfer_setup(xfer, ep_handle, bulk_buffer, 512 * 64,
USB_XFER_FLAG_BULK, NULL, NULL);
常见错误:使用
malloc() 分配的缓冲区通常只对齐到 16 字节,在高速/超高速批量传输中会导致 DMA 引擎无法直接访问,驱动会回退到 PIO 模式,吞吐量下降 50% 以上。务必使用 posix_memalign() 或 mmap() 分配对齐缓冲区。