资讯动态

USB枚举、协商、传输:以USB相机为例看识别与格式协商

发布时间:2026/10/16 6:21:58 来源:尧图企业网站定制
USB枚举、协商、传输以USB相机为例看识别与格式协商概述主机能够枚举一颗从未见过的芯片并非因为主机预先识别了该芯片而是因为设备按 USB 规范用描述符描述自身。描述符说明设备的身份与接口数量Probe/Commit 协商确定输出格式。1. 基础协议分层、双方角色与通信方式要理解这套过程先分清两层规范它们叠加在一起职责不同层规范负责内容总线层USBUniversal Serial Bus通用串行总线电气连接、寻址、数据包的收发、四种传输类型设备类层UVCUSB Video ClassUSB 视频类摄像头的描述符格式、控制请求、数据格式UVC 建立在 USB 之上。USB 只负责把字节送到某个端点不关心这些字节承载的是视频还是其他内容UVC 才规定摄像头的描述符格式与可用的控制请求。双方的角色分工是理解后续流程的前提主机PC 上的操作系统与驱动发起所有请求、为设备分配地址、决定加载哪个驱动、决定取数据的时机。设备MCU 加摄像头固件只负责应答。设备不能主动向主机发送数据视频数据同样由主机发起读取主机查询端点是否有数据设备才返回数据。设备侧要能完成应答以下三项都是必需的前提作用USB 设备控制器含 PHY 物理层电气层收发D 上拉端点 FIFO设备协议栈解析标准请求管理地址、端点与状态机一份自描述的描述符表设备身份的唯一信息源USB 定义了四种传输类型本文涉及前三种第四种是视频流的可替代方案传输类型用在哪特点控制传输Control固定使用 EP0枚举、协商、读状态每条请求都保证送达并回执批量传输Bulk视频数据不丢包但带宽与时延不保证中断传输InterruptUVC 的事件通知周期轮询延迟有上限等时传输Isochronous视频数据的另一种选择保带宽与时延出错不重传端点endpoint是设备内部的数据出入口每个端点有地址和方向。主机的每一次通信都发往设备上的某个端点不针对设备的某个功能。枚举与协商都经由 0 号端点EP0视频数据使用独立的端点。设备侧只要按同样格式应答描述符更换芯片后主机同样能够识别。以下从设备插入开始依次描述这八个步骤。2. 枚举流程关键信息集中在第 5 步设备插入后主机会按固定顺序执行八个步骤整体分为两段前段识别设备并分配地址后段读回全部能力并登记进系统。后半段读回全部能力登记为设备前半段先识别设备再分配地址主机复位 速度协商GET_DESCRIPTORDEVICE 8 字节GET_DESCRIPTORDEVICE 18 字节SET_ADDRESS分配地址GET_DESCRIPTORCONFIGURATIONGET_DESCRIPTORSTRINGSET_CONFIGURATION端点使能按接口类代码加载驱动并注册设备前两步为什么要分两次读取设备描述符因为主机尚不知道该设备的端点能够接收多大的数据包首次只读取 8 字节以取得bMaxPacketSize0再读取完整的 18 字节。这八个步骤中主机与设备各自的动作步主机侧设备侧1检测到接入复位设备协商是全速还是高速接受复位2读取 8 字节设备描述符返回设备描述符的前 8 字节3读取完整 18 字节返回完整设备描述符含 VID / PID / 配置数量4分配一个新地址记录地址此后仅以该地址应答5读取配置描述符集合返回全部能力即第 3 节所列结构6读取字符串描述符返回厂商 / 产品 / 序列号等文本7选定配置按配置内容使能各端点8按接口类代码加载驱动将设备注册进系统此后等待主机协商输出格式第 5 步是全部信息的来源。一次GET_DESCRIPTOR(CONFIGURATION)取回整个配置描述符集合configuration descriptor set按固定顺序排列Configuration ├── IADInterface Association Descriptor接口关联描述符 ├── VC 接口 一串 CS_INTERFACE 描述符 中断端点 └── VS 接口 若干 format 描述符 若干 frame 描述符 数据端点主机侧看到的设备能力全部来自这一次读取的字节。这批字节的结构是固定的下文以 UVC 摄像头为例说明。3. UVC 的描述符命名的三个层次与 IAD 关联UVC 设备的标准结构是一对接口一个 VideoControlVC视频控制接口负责控制加一个 VideoStreamingVS视频流接口负责数据。接口类代码bInterfaceClass固定为0x0E子类0x01为 VC、0x02为 VS。主机读到0x0E即判定这是摄像头加载系统自带的 UVC 驱动。一对 VC 与 VS 构成一个功能function由IAD将两个接口关联并声明为一个整体否则系统会将它们视为两个互不相关的设备。当一台设备要提供多路视频时就在一个 configuration 下放置多组IAD VC VS。由此形成命名的三个层次。左侧是设备声明的结构右侧是主机据此建立的结构主机侧视图设备声明的结构描述符中的三层显示设备名各注册为一个摄像头设备级iProduct 2ImgData Camera功能 1IAD iFunction 6Img Camera功能 2IAD iFunction 7Data Camera接口 0 1VC 与 VSiInterface 6接口 2 3VC 与 VSiInterface 7设备树ImgData Camera摄像头列表Img CameraData Camera固件中的字符串表就是这三层的原始形式节点中的下标数字对应这张表的行号staticconstchar*ustring[]{Language,/* 0 语言 ID */Vendor Co.,Ltd,/* 1 iManufacturer */ImgData Camera,/* 2 iProduct ← 设备级 */serialId,/* 3 iSerialNumber */Configuration,/* 4 iConfiguration */Interface,/* 5 */Img Camera,/* 6 功能 1 的 iFunction / iInterface */Data Camera/* 7 功能 2 的 iFunction / iInterface */};设备描述符中iProduct 2第一组 IAD/VC/VS 的iFunction与iInterface为 6第二组为 7。这几个字段本身都是字符串描述符的索引号。将这份字节按层级展开就是主机在第 5 步读取到的结构Configuration 1 ├─ IAD #1 iFunction 6 → Img Camera │ ├─ Interface 0VC class 0x0E / subclass 0x01 │ │ ├─ CS_INTERFACE : Header │ │ ├─ CS_INTERFACE : Input Terminal 相机终端 │ │ ├─ CS_INTERFACE : Processing Unit │ │ ├─ CS_INTERFACE : Output Terminal │ │ └─ Endpoint 0x87 中断传输 IN │ └─ Interface 1VS class 0x0E / subclass 0x02 iInterface 6 │ ├─ VS Input Header │ ├─ Format 1..6 未压缩NV12 / YUY2 / Y16 / Y8 / RGB888 / RGB565 │ │ └─ 每种格式包含若干 Frame 描述符 │ ├─ Format 7 MJPEG │ │ └─ 若干 Frame 描述符 │ └─ Endpoint 0x81 批量传输 IN └─ IAD #2 iFunction 7 → Data Camera ├─ Interface 2VC class 0x0E / subclass 0x01 │ ├─ CS_INTERFACE : Header / Terminal / Unit … │ └─ Endpoint 0x88 中断传输 IN └─ Interface 3VS class 0x0E / subclass 0x02 iInterface 7 ├─ VS Input Header ├─ Format 1 未压缩 │ └─ 6 组 Frame每组 数据帧 高度多 2 行的信息帧 └─ Endpoint 0x82 批量传输 INCS_INTERFACE是类特定接口描述符class-specific interface descriptorVC 内部的终端与处理单元都由它定义。接口编号在固件中写作USB_DYNAMIC由协议栈在枚举时分配因此上文的 0/1/2/3 是典型结果而非硬编码值。主机据此建立的设备树同一台设备会同时出现在两个位置设备管理器 ├─ 通用串行总线控制器 │ └─ USB 复合设备 │ └─ Vendor Co.,Ltd ImgData Camera ← iProduct设备级只有一个 └─ 摄像头Imaging Devices ├─ Img Camera ← 功能 1 的 iFunction └─ Data Camera ← 功能 2 的 iFunction两个位置描述的是同一份数据区别只在于主机把它放在设备树的哪一层。两个功能承载的数据形态不同这是分成两路的原因功能 1Img Camera功能 2Data Camera内容图像帧结构化数据帧格式数6 种未压缩 1 种压缩MJPEG1 种未压缩帧组织每种格式若干组独立的图像帧参数成对数据帧 高度多 2 行的信息帧尺寸图像分辨率6 档640×512、384×288、256×192、160×120、320×240、512×384第二路的 6 档尺寸各自成对信息帧始终比同档的数据帧多 2 行对应「传感器矩阵 元信息帧头 / 量程 / 时间戳」这种数据的常见组织方式。4. 枚举完成识别能力由 Probe/Commit 协商确定描述符已向主机提供格式清单但主机尚未选定使用其中哪一项帧率也未确定。这一步要用 UVC 的类特定控制请求class-specific request再协商一轮全程同样经由 EP0。这种请求由 UVC 定义只是借用了 USB 的控制传输设备侧硬件输出通路设备侧 UVC Class 处理USB EP0主机 UVC 驱动设备侧硬件输出通路设备侧 UVC Class 处理USB EP0主机 UVC 驱动GET_CUR(VS_PROBE) 读取候选格式与帧参数1返回该格式支持的分辨率 / 帧率区间2SET_CUR(VS_PROBE) 探测3校验 payload 能否承载4SET_CUR(VS_COMMIT) 确定5commit 回调6以 bFormatIndex / bFrameIndex / dwFrameInterval 初始化输出通路7数据端点开始传输数据8VS_PROBE用于探测VS_COMMIT用于确定。关键在于最后三步Commit 之前硬件通路尚未启动。回调取得bFormatIndex、bFrameIndex、dwFrameInterval三个下标组成一份帧参数才去初始化封装硬件与输出接口。因此相机已插入但未打开预览时设备不会向数据端点发送像素。协商完成后即与 EP0 无关像素经由独立的 Bulk IN 或 Isochronous IN 端点传输由主机按期读取。此后主机侧负责接收设备侧按协商结果输出。5. 三个最容易混淆的地方以下三处名称相近实际调试时最容易误判端点号 ≠ 内部通道号。0x81、0x82是 USB 端点地址设备固件内部可能另有「通道 1/2/3」编号两套编号之间没有数值对应关系仅表示固件在配置中把某路内部通道映射到了某个端点。设备名不是摄像头名称。设备树读取iProduct摄像头列表读取各 function 的iFunction两者本就是不同的字段因此同一台设备会出现在两个位置。IAD 不可省略。缺少 IAD 时VC 与 VS 会被视为两个独立接口Windows 下常表现为「识别到 USB Video 设备但无法打开」因为 UVC 驱动需要依靠配对关系才能确定控制接口与数据接口属于同一路视频。一句话USB 的即插即用建立在设备按规范描述自身的基础上。主机发起请求、设备应答这一交互贯穿三个阶段枚举时交换描述符确定身份协商时用 Probe/Commit 确定格式开始传输后设备向端点输出数据。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑