USB 系统架构:主机、设备、集线器,还有那个经典的拓扑结构

咱们做 USB 调试,第一件事就是搞清楚这个系统到底长什么样。你拿着分析仪,怼上总线,看到的是一堆 SOF、、DATA 包。但如果脑子里没有这张架构图,很容易被错综复杂的事务搞晕。

简单说,一个 USB 系统就是一台主机带着一堆设备,通过集线器像树杈一样分出去。我从一开始接触 USB 就被这个树形拓扑吸引,后来在产线上排查设备掉线问题时,这棵树帮了大忙。

主机:一切通信的起点

主机只有一个。没错,整个 USB 总线里,能发号施令的只有主机。设备永远是被动应答,哪怕是设备向主机传数据,也得先等主机发个 IN 。

核心记忆点:USB 是主机主导的总线。没有主机的许可,设备一个字都不能往外吐。

我把主机侧的几个模块拆开来说:

  1. USB 主机控制器 (Host Controller) —— 这是硬件层面的大脑。常见的类型有 EHCI(USB 2.0)、xHCI(USB 3.x,向下兼容)。xHCI 我个人觉得好用多了,因为它统一了所有速度等级的处理逻辑。
  2. 根集线器 (Root Hub) —— 集成在主机控制器内部的集线器。它是主机端的第一个分叉点,通常露出几个端口让你插设备。拆开电脑看看,那个贴在主板上的 USB 口,背后就是根集线器。
    我曾经遇到一个情况:两个 USB 口紧挨着,一个能用一个总掉线。量了也没发现 D+/D- 短路。最后发现是根集线器的那个端口供电滤波电容虚焊了。
  3. 系统软件栈 —— 包括 USB 核心驱动、各类设备类驱动(HID、Mass Storage 等)。分析仪抓包时看到的 SETUP 事务,很多就是这块软件发起的。

设备:从鼠标到硬盘,都是终端节点

设备种类太多了。但无论功能多花哨,它们的接口逻辑是统一的。每个设备内部至少有一个功能模块,通过端点 (Endpoint) 与主机交换数据。

设备的速度等级直接影响着分析仪抓包时的时钟频率设置。我刚开始调试时,就犯过错——拿 USB 2.0 的采样频率去抓 Full Speed 设备,结果包全乱了。

速度等级 信号速率 常见设备 抓包时注意
Low Speed 1.5 Mbps 鼠标、键盘 边沿触发,抗干扰弱
Full Speed 12 Mbps 老式 U 盘、音频 分析仪需支持宽范围频率
High Speed 480 Mbps 大部分 U 盘、摄像头 差分信号质量要求高
Super Speed 5 Gbps / 10 Gbps SSD 移动硬盘、高速采集卡 需要专门的 xHCI 分析仪

小提示:抓包配置时,我一般先查设备的 USB 描述符里的 bcdUSB 字段。如果版本是 2.00,就是 High Speed;是 2.10 或 3.00,就是 Super Speed。把这个搞错了,分析仪是抓不到有效包的。

集线器:占着供电,解决物理扩展

集线器是让 USB 拓扑成树的关键角色。你想想看,一个主机带 127 个设备,如果都像串行总线那样线性级联,延迟和信号衰减没法搞。集线器的出现,让每个下游端口都独立再生信号。

集线器内部结构其实就是一个中继器 + 事务转发器。它接收上游主机的包,然后选择性地转发给下游设备。同理,下游设备的应答也由集线器打包发回主机。

  • TT (Transaction Translator) —— 只在 USB 2.0 集线器里有。它的作用是让 Full/Low Speed 设备能挂在 High Speed 总线上。集线器把高速帧翻译成适合慢速设备的分段事务。
  • 端口状态管理 —— 每个端口都有复位、挂起、恢复、使能等状态。我调试时最常用的就是把集线器某个端口强制复位看看波形。

说到集线器的坑,我曾经遇到一个挺经典的问题:
产线上有一批设备,插在机箱前置 USB 口上偶尔掉线,拔插一下又好了。一开始怀疑线材,换了也一样。后来抓包发现,设备被识别后,主机每隔一段时间会发送 GET_PORT_STATUS 去查询集线器端口状态。结果那个前置集线器的返回值里,电源标志位忽高忽低。一顿查,是前置 USB 面板那个集线器的电源滤波电容用的太垃圾了。

拓扑结构:一棵最多七层的树

来,咱们把上面的拼起来。USB 的物理拓扑是层次化星型结构。根集线器是第一层,外接集线器是第二层,设备是叶子节点。但层数有限制:最多 7 层(包含主机本身和根集线器在内)。

为什么限制 7 层?因为每个集线器都会引入一定延迟,超过 7 层后,信号往返的时序就没法满足了。你想想看,设备对主机 的应答是有时间窗口的,每一级转发都会压紧这个窗口。

有人会问:那怎么接 127 个设备呢?你想想,一个集线器多个端口,每个端口又可以接集线器。只要不超过 7 层深度,横向扩展完全没问题。一个五口集线器接四个集线器,再每个接四个集线器……数学上很快就超过 127 了。

我把这个拓扑画成了一张图,你对着看会更清楚。

USB 层次化星型拓扑结构图 主机 (Host) 根集线器 (Root Hub) 集线器 1 集线器 2 设备 A 设备 B 设备 C 设备 D 设备 E 设备 F 特点:层级不超过 7 层(含主机),一个主机控制所有事务,集线器负责再生信号

说实话,物理拓扑配上逻辑地址(设备地址),才是分析仪抓包时理解事务流的关键。比如你看到一个 包的目标地址是 0x03,但不知道设备 0x03 挂在哪一层、经过哪几个集线器,那这个包的含义就差了点味道。

避坑提示:某些低成本集线器在级联超过 3 层后,会出现丢包或 CRC 错误。我曾经在百台设备压力测试中遇到过,根集线器下面挂了三个廉价集线器,第三级设备频频报错。最后发现是集线器内部的信号整形电路不过关。整改方案:限制级联深度,或者换用带独立晶振的工业级集线器。

设备枚举:树是怎么长出来的

新设备插上去,拓扑就发生变化了。主机是怎么知道多了一个分叉的呢?靠枚举过程。这个过程很有章法:

  1. 设备插入集线器端口 → 集线器检测到 D+/D- 上的电平变化 → 通知主机。
  2. 主机发送 GET_PORT_STATUS 确认端口变化 → 然后复位该端口(持续 10ms 以上的 SE0)。
  3. 复位后,设备处于默认地址 0。主机发送 SET_ADDRESS 给它分配一个唯一地址(比如 0x05)。
  4. 主机读取设备描述符、配置描述符……直到确认设备类型。
  5. 最后主机选择一种配置,设备进入配置状态,可以正常通信了。

调试时我常盯着这个枚举时序看。要是某个描述符读回的数据校验不对,或者设备对 SET_ADDRESS 没应答,系统就会认不出设备。

你可以在分析仪上这么验证:拔插一个 U 盘,抓取从插入到设备就绪的全部包。留意看主机是怎么连续发 GET_DESCRIPTOR 的。我见过有些加密 U 盘在枚举时故意拖延描述符响应的——这在普通逻辑里可能是个 bug,但人家是功能。

嗯,USB 系统架构说白了就这么多:一个主机,多个设备,通过集线器扩展开来,形成一棵最多 7 层的树。你掌握了这个骨架,再去理解分析仪抓到的各种事务和包结构,就有根了。