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() 或重置端点来恢复。
批量传输可靠性握手流程(主机→设备 OUT 传输) 主机(Host) 设备(Device) ① OUT 数据包(含 CRC) ② ACK 握手(校验通过) ③ NAK(设备忙,主机重试) 主机收到 NAK 后不会丢弃数据,而是重新调度该传输事务 直到收到 ACK 或主机控制器超时(通常 3~5 秒)

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 批量传输故障排查要点

批量传输故障排查决策树 批量传输失败 端点未配置 检查 usbd_ep_init() 返回值 确认 wMaxPacketSize 正确 带宽不足 使用 io-usb-dso -v 查看帧分配 移除高带宽等时设备测试 NAK 风暴 检查设备固件是否及时处理数据 增加端点 FIFO 深度
实战建议:在 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() 分配对齐缓冲区。