2. USB系统架构:主机、设备与集线器的角色

USB系统说白了就是一个主从结构的通信网络。主机说了算,设备听指令,集线器负责把总线扩展出去。这个架构从USB 1.0一直沿用到现在,基本没变过。

我刚开始做USB驱动时,总觉得这个架构太简单了——不就一个主控带一堆设备嘛。后来踩了几个坑才明白,这套看似简单的架构里藏着不少设计智慧。

2.1 主机(Host)——总线的掌控者

主机是整个USB系统的核心。它负责管理总线上的所有事务,包括设备枚举、数据传输、电源管理等。在PC上,主机就是USB主控制器(Host Controller)加上根集线器(Root Hub)。

主机的关键职责有这些:

  • 检测设备插拔——通过集线器端口状态变化来发现设备
  • 分配地址——每个设备在枚举时获得唯一地址(1-127)
  • 调度传输——按帧/微帧为单位,安排所有传输事务
  • 管理电源——控制端口供电,处理挂起/唤醒

关键概念:USB总线上的所有传输都由主机发起。设备从不主动发送数据,只能被动响应主机的请求。这一点和I2C、SPI很像,但USB的调度机制要复杂得多。

我记得第一次调试一个USB摄像头时,发现图像数据总是丢帧。查了半天,原来是主机的帧调度出了问题——等时传输的带宽预留不够。嗯,从那以后我养成了习惯:做USB项目先算带宽预算。

2.2 设备(Device)——功能的提供者

设备就是挂在USB总线上的各种外设。键盘、鼠标、U盘、摄像头、打印机……它们都遵循同样的设备框架。

每个USB设备都包含以下逻辑结构:

层级 说明 我见过的坑
设备层 描述设备整体信息(VID/PID、版本等) 有些山寨设备VID/PID乱填,导致驱动加载失败
配置层 定义设备的工作模式(如高功耗/低功耗) 配置描述符里的bMaxPower写错,主机直接拒绝
接口层 代表一个功能单元(如音频、HID) 复合设备接口顺序搞反,驱动认不出
端点层 数据传输的终点,每个端点有方向、类型 端点0以外的端点描述符漏了,枚举到一半卡死

设备通过描述符向主机报告自己的身份和能力。主机在枚举阶段逐层读取这些描述符,然后加载对应的驱动程序。

个人经验:调试设备枚举问题时,我习惯用逻辑分析仪抓取主机发起的GET_DESCRIPTOR请求。看看主机读到了什么、设备返回了什么,问题往往一目了然。比单纯看驱动日志高效得多。

2.3 集线器(Hub)——总线的扩展器

集线器负责把USB总线扩展出更多端口。每个USB系统中至少有一个根集线器(集成在主控制器里),外部还可以级联集线器。

集线器的工作说白了就是两件事:

  • 信号中继——把上游的信号整形、放大后转发到下游端口
  • 端口管理——检测设备插拔、控制电源、处理复位和挂起

集线器本身也是一个USB设备,有自己的地址和端点。主机通过集线器类请求来管理它,比如读取端口状态、设置端口特性等。

避坑指南:我曾经在一个项目中用了劣质集线器,导致高速设备(USB 2.0)只能跑全速(12 Mbps)。查了三天才发现是集线器的信号质量太差,眼图都闭合了。从那以后,我选集线器芯片只认TI、Microchip、Cypress这几家。

2.4 通信模型——谁跟谁说话?

USB的通信模型是主机-设备的点对点关系。集线器只是透明转发,不参与数据内容的理解。

一次典型的USB传输过程是这样的:

  1. 主机软件(驱动)准备好数据,提交给主控制器
  2. 主控制器按调度把数据打包成事务(Transaction)
  3. 事务通过集线器转发到目标设备
  4. 设备解析事务,执行操作,返回响应
  5. 响应原路返回给主机软件

你想想看,这个模型和网络通信很像——主机是服务器,设备是客户端。但USB的实时性要求更高,所以引入了帧的概念来保证确定性。

2.5 系统架构总览

下面这张图展示了USB系统的完整架构。我建议你把它记在脑子里,后面所有调试和分析都离不开这个框架。

USB系统架构总览 主机(Host) USB主控制器(HC) 根集线器(Root Hub) 主机软件(驱动/API) 集线器(Hub) 信号中继 端口管理 电源控制 设备 A U盘(大容量存储) 端点0 + 端点1/2 设备 B 鼠标(HID) 端点0 + 中断端点 设备 C 摄像头(视频类) 端点0 + 等时端点 说明:主机通过集线器管理多个设备,每个设备有唯一地址。集线器可级联,但最多7层。 所有传输由主机发起,设备只响应。集线器对数据内容透明。

2.6 三种角色的协作关系

主机、设备、集线器三者配合,构成了完整的USB系统。它们的协作可以总结为:

  • 主机制定规则、发起通信、管理资源
  • 设备遵守规则、响应请求、提供功能
  • 集线器扩展总线、透明转发、管理端口

这个架构的好处是:设备不需要知道总线上还有谁,集线器不需要理解数据内容,主机掌控一切。说白了就是集中管理、分布执行。

调试要点:遇到USB通信问题时,先判断是哪个角色出了问题。主机问题看驱动日志和主控制器状态;设备问题抓描述符和端点配置;集线器问题查端口状态和信号质量。分而治之,效率最高。

我记得有一次调试一个USB集线器,下游设备总是间歇性断开。用USB分析仪抓包发现,集线器在设备枚举完成后没有正确转发SOF包。换了一颗集线器芯片就好了——嗯,有时候硬件问题就是这么直接。

好了,USB系统架构就讲到这里。理解了这个框架,后面讲枚举、传输、协议栈的时候,你就能知道每个环节发生在哪个角色身上。这是整个USB调试的基础,值得花时间吃透。