本讲目标

理解一个 USB 设备如何通过多个接口提供不同功能,并认识复合设备的描述符组织方式。

一、一个 USB 插头可以承载多个功能吗?

当然可以。

例如,一个单片机设备可以同时提供:

  • HID 键盘功能。
  • HID 鼠标功能。
  • CDC 虚拟串口功能。

电脑只需要通过一个 USB 连接,就可以识别这些功能。

其关键不在于把多个 USB 设备电气上简单并联,而在于通过描述符定义多个接口,并让 Host 分别识别这些接口。

二、复合设备的描述符结构

可以用下面的结构理解:

USB Device
    |
    └── Configuration
            |
            ├── Interface 0:HID Keyboard
            |       └── Interrupt IN
            |
            ├── Interface 1:HID Mouse
            |       └── Interrupt IN
            |
            └── CDC
                    ├── Communication Interface
                    └── Data Interface
                            ├── Bulk IN
                            └── Bulk OUT

这是一种概念示意。实际 CDC 描述符还会涉及类专用描述符和接口关联关系;端点配置也应遵循对应 USB 类规范。

三、操作系统如何区分这些功能?

Host 读取设备的配置描述符集合后,可以看到多个接口。

每个接口拥有自己的接口编号、类信息以及相应的端点配置。

操作系统据此识别各个接口,并根据自身驱动模型进行匹配。

例如:

  • HID 接口由 HID 驱动处理。
  • CDC 接口由相应的 CDC 驱动处理。

不同操作系统的具体驱动绑定和设备呈现方式可能不同,但基本思想都是通过接口和相应的类规范识别功能。

四、复合设备与多个独立 USB 设备有什么区别?

多个独立 USB 设备通常各自拥有独立的设备描述符和设备地址。

复合设备则通过同一个 USB 设备的配置描述符集合暴露多个接口功能。

因此,在抓包和设备管理器中判断设备结构时,不能只看功能数量,还需要查看设备描述符、配置描述符和接口描述符之间的关系。

五、开发复合设备时需要注意什么?

首先,确保 bNumInterfaces 与配置中实际声明的接口数量一致。

其次,检查接口编号、备用设置、端点地址、端点数量和描述符总长度是否正确。

此外,还要确保 HID 报告描述符长度与实际内容一致,CDC 通信接口与数据接口的关联信息正确。

如果某个接口没有被系统识别,建议先检查描述符是否自洽,再查看系统驱动绑定结果。

六、为什么建议逐步增加功能?

如果一开始就同时实现 HID 键盘、HID 鼠标和 CDC,出现问题时就很难快速判断是哪个接口导致的。

更稳妥的方式是:

  1. 先让单一 HID 接口正常工作。
  2. 增加第二个 HID 接口。
  3. 确认两个接口都能独立工作。
  4. 再加入 CDC。
  5. 最后进行多接口并发测试。

这种方式可以把问题逐步缩小,避免一次性引入太多变量。

七、本讲小结

复合设备的关键是通过一个 USB 设备的描述符体系暴露多个接口功能,再由 Host 分别识别和处理。

对于单片机开发者来说,理解接口、端点和驱动绑定之间的关系,比单纯记住某个 SDK 的配置选项更重要。

留给下一讲的问题

如果设备枚举失败、某个端点没有数据,或者系统只识别了部分接口,我们应该怎样定位问题?

下一讲,我们使用 USB 抓包工具 观察 Host 和 Device 之间的实际通信过程。


Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐