关于USB的一些笔记理解感悟

最近工作中使用到了USB,也进行了一些浅显的学习,记录一下

一、USB底层

1.物理层

  • 使用两根线进行进行通信,分别为D+、D-,差分电压幅度为0.4V左右
  • 底层调制方式使用NRZI(Non-Return to Zero Inverted)编码 + 位填充
  • USB1.1理论全速为800KB/S ,USB2.0理论全速为35MB/S左右

2.端点

  • USB所有通信都是通过端点进行的,不同的芯片可能具有不同的端点数量,但是至少具有端点0
    • 控制端点:所有设备必须存在控制端点,只能是端点0. 用来作为设备的枚举、配置、基础命令等,支持双向通信
    • 同步端点:同步端点以实时性优先,固定带宽,无错误重传。通常是为音频、视频等设计的(数据量大、时间敏感、允许错误)
    • 中断断点:并不会真正的产生中断,而是由主机定期询问设备是否有数据,这个时间间隔通常是1ms。通常是为键盘鼠标等准备的。(时间敏感、数据量小、不允许错误)
    • 批量端点:是一种可靠传输,大块数据专用,保证数据正确,单次传输量大,但是只有在总线空闲时才进行传输。常用来做U盘、打印机等(时间不敏感、数据量大、不允许出错)

3. 组包方式

3.1 包类型

包类型 组成 作用 示例
Token包 SYNC + PID + ADDR + ENDP + CRC5 声明传输方向/目标地址 IN(0x69) + 设备地址 + 端点号
Data包 SYNC + PID + DATA + CRC16 携带实际数据 DATA0 + 64字节负载 + CRC
Handshake包 SYNC + PID 确认状态(ACK/NAK/STALL) ACK(0xD2)

3.2 传输类型组包方式

不同传输类型有独特的组包逻辑:

  • 控制传输
    • Setup阶段
    • Data阶段
    • Status阶段
  • 批量传输
    • 单事务组包
    • 错误恢复
  • 中断传输
    • 组包方式类似批量传输
  • 同步传输
    • 精简组包

二、枚举流程

  • 设备插入检测
    • 物理层触发:主机检测VBUS电压变化(如从0V升到5V)
  • 端口复位(Reset)
    • 主机发出持续10ms的SE0信号(D+/D-同时拉低)
    • 设备进入默认状态(地址=0,端点0激活)
  • 首次控制传输(地址0)
    主机通过端点0发起以下请求:
    • GetDescriptor(设备描述符):设备返回18字节基本描述符(含bcdUSB字段标识USB版本)
    • SetAddress(新地址):主机分配唯一地址(1~127),设备后续使用该地址通信
  • 深度描述符读取
    主机用新地址获取更多信息:
    • GetDescriptor(配置描述符):设备返回配置集合(含接口/端点描述符)
    • GetDescriptor(字符串描述符):获取厂商/产品名字等文本信息
  • 设备配置
    • 主机发送SetConfiguration(配置值)
    • 设备启用指定配置(激活所有端点)
  • 驱动加载
    • 主机根据设备类(bDeviceClass)加载对应驱动

三、感悟

USB协议上给人的感觉很复杂,但是好在基本上所有的协议都是标准化的;
但是市面上存在各种品牌的处理器,是不是每个处理器的USB设备的实现都不同呢?

  • 并不是,虽然市面上的处理器型号不同,但是如果端点通信是OK的,理论上就可以实现所有的USB设备功能
  • 并且,不同的处理器,其USB的IP可能是一样的,这就意味着驱动层适配不用关心芯片,只用关心IP

在我看来,USB协议复杂的地方并不在于底层,而在于class层,因为class种类太多了,想要知道每一种USB的协议细节本身就比较困难
但是好在有开源大神做好了相关的工作,比如cherryUSB和tinyusb,这两个开源项目适配了很多芯片的USB IP,并且写了很多class的demo

posted @ 2025-07-02 16:34  shumei52  阅读(39)  评论(0)    收藏  举报