stm32 HAL配置usb全速 自定义HID类详解

目录

前言

[一. stm32 HID具体usb全速配置](#一. stm32 HID具体usb全速配置)

main.c

usbd_customhid.h

usbd_conf.h

usbd_desc.c

usbd_custom_hid_if.c

[二. PortHelper.exe交互和uart打印](#二. PortHelper.exe交互和uart打印)

[三. bus hound的枚举过程和数据发送记录](#三. bus hound的枚举过程和数据发送记录)

[四. USB枚举过程与传输数据具体解释](#四. USB枚举过程与传输数据具体解释)

[4.1 Bus Hound 抓包日志逐行 USB 通信解析(基于 USB 2.0 协议)](#4.1 Bus Hound 抓包日志逐行 USB 通信解析(基于 USB 2.0 协议))

[4.2、核心前提:USB 通信基础](#4.2、核心前提:USB 通信基础)

[4.3、逐行 USB 通信解析(按日志顺序)](#4.3、逐行 USB 通信解析(按日志顺序))

[1. 第 1 行:29.0 CTL 80 06 00 01 00 00 12 00 | GET DESCRIPTOR | 1.1.0](#1. 第 1 行:29.0 CTL 80 06 00 01 00 00 12 00 | GET DESCRIPTOR | 1.1.0)

[2. 第 2 行:29.0 IN 12 01 00 02 00 00 00 40 7f 04 4f 57 00 02 01 02 03 01|1.2.0](#2. 第 2 行:29.0 IN 12 01 00 02 00 00 00 40 7f 04 4f 57 00 02 01 02 03 01|1.2.0)

[3. 第 3 行:29.0 CTL 80 06 00 02 00 00 09 00 | GET DESCRIPTOR | 2.1.0](#3. 第 3 行:29.0 CTL 80 06 00 02 00 00 09 00 | GET DESCRIPTOR | 2.1.0)

[4. 第 4 行:29.0 IN 09 02 29 00 01 01 00 c0 32 | 2.2.0](#4. 第 4 行:29.0 IN 09 02 29 00 01 01 00 c0 32 | 2.2.0)

[5. 第 5 行:29.0 CTL 80 06 00 02 00 00 29 00 | GET DESCRIPTOR | 3.1.0](#5. 第 5 行:29.0 CTL 80 06 00 02 00 00 29 00 | GET DESCRIPTOR | 3.1.0)

[6. 第 6 行:29.0 IN 09 02 29 00 01 01 00 c0 32 09 04 00 00 02 03 00 00 00 09 21 11 01 00 01 22 22 00 07 05 81 03 02 00 05 07 05 01 03 02 00 05 | 3.2.0](#6. 第 6 行:29.0 IN 09 02 29 00 01 01 00 c0 32 09 04 00 00 02 03 00 00 00 09 21 11 01 00 01 22 22 00 07 05 81 03 02 00 05 07 05 01 03 02 00 05 | 3.2.0)

[7. 第 7 行:29.0 CTL 00 09 01 00 00 00 00 00 | SET CONFIG | 4.1.0](#7. 第 7 行:29.0 CTL 00 09 01 00 00 00 00 00 | SET CONFIG | 4.1.0)

[8. 第 8 行:29.0 CTL 21 0a 00 00 00 00 00 00 | SET IDLE | 5.1.0](#8. 第 8 行:29.0 CTL 21 0a 00 00 00 00 00 00 | SET IDLE | 5.1.0)

[9. 第 9 行:29.0 CTL 81 06 00 22 00 00 62 00 | GET DESCRIPTOR | 6.1.0](#9. 第 9 行:29.0 CTL 81 06 00 22 00 00 62 00 | GET DESCRIPTOR | 6.1.0)

[10. 第 10 行:29.0 IN 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 95 40 75 08 81 02 09 01 15 00 26 ff 00 95 40 75 08 91 02 c0 | 6.2.0](#10. 第 10 行:29.0 IN 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 95 40 75 08 81 02 09 01 15 00 26 ff 00 95 40 75 08 91 02 c0 | 6.2.0)

[11. 第 11 行:29.0 CTL 80 06 02 03 09 04 02 04 | GET DESCRIPTOR | 7.1.0](#11. 第 11 行:29.0 CTL 80 06 02 03 09 04 02 04 | GET DESCRIPTOR | 7.1.0)

[12. 第 12 行:29.0 IN 3a 03 53 00 54 00 4d 00 33 00 32 00 20 00 43 00 75 00 73 00 74 00 6f 00 6d 00 20 00 48 00 75 00 6d 00 61 00 6e 00 20 00 69 00 6e 00 74 00 65 00 72 00 66 00 61 00 63 00 65 00 | 7.2.0](#12. 第 12 行:29.0 IN 3a 03 53 00 54 00 4d 00 33 00 32 00 20 00 43 00 75 00 73 00 74 00 6f 00 6d 00 20 00 48 00 75 00 6d 00 61 00 6e 00 20 00 69 00 6e 00 74 00 65 00 72 00 66 00 61 00 63 00 65 00 | 7.2.0)

[13. 第 13 行:29.0 CTL 80 06 03 03 09 04 02 04 | GET DESCRIPTOR | 8.1.0](#13. 第 13 行:29.0 CTL 80 06 03 03 09 04 02 04 | GET DESCRIPTOR | 8.1.0)

[14. 第 14 行:29.0 IN 1a 03 36 00 44 00 38 00 42 00 34 00 31 00 36 00 43 00 35 00 34 00 35 00 36 00 | 8.2.0](#14. 第 14 行:29.0 IN 1a 03 36 00 44 00 38 00 42 00 34 00 31 00 36 00 43 00 35 00 34 00 35 00 36 00 | 8.2.0)

[15. 第 15-22 行:重复 GET DESCRIPTOR + SET IDLE](#15. 第 15-22 行:重复 GET DESCRIPTOR + SET IDLE)

这里开始数据传输​编辑

主机和USB设备枚举成功后:空闲的数据发送

[主机发送数据 + USB设备接收数据具体](#主机发送数据 + USB设备接收数据具体)

[USB设备发送数据 + 主机接收数据](#USB设备发送数据 + 主机接收数据)

[23. 第 23 行:29.1 OUT 00 01 02 03 ... 63 | 13.1.0](#23. 第 23 行:29.1 OUT 00 01 02 03 ... 63 | 13.1.0)

[24. 第 24 行:30 OUT 00 00 01 02 ... 63 | 14.1.0](#24. 第 24 行:30 OUT 00 00 01 02 ... 63 | 14.1.0)

[25. 第 25 行:29.1 IN 00 01 02 03 ... 63 | 15.1.0](#25. 第 25 行:29.1 IN 00 01 02 03 ... 63 | 15.1.0)

[26. 第 26 行:30 IN 00 00 01 02 ... 63 | 16.1.0](#26. 第 26 行:30 IN 00 00 01 02 ... 63 | 16.1.0)

[4.4、整体 USB 通信流程总结](#4.4、整体 USB 通信流程总结)

[五. 具体解释](#五. 具体解释)

可能为1:当成独立行打印

[可能为2:USB 控制传输的 "3 次重试" 协议机制](#可能为2:USB 控制传输的 “3 次重试” 协议机制)

[可能为3:设备 29(STM32 HID 设备)的 "初始化延迟"](#可能为3:设备 29(STM32 HID 设备)的 “初始化延迟”)

结论:


usb全速配置自定义HID设备枚举过程和数据传输详细介绍

前言

通过stm32cubemx配置usb自定义类型,传输64字节,使用Bus Hound,PortHelper,sscom软件进行usb的配置查看测试传输测试,介绍枚举过程和传输64字节数据,对比IN/OUT端点包长和对比中断传输轮询时间等。

一. stm32 HID具体usb全速配置

我使用stm32cubemx配置usb的全速传输,自定义类型;使用uart2打印调试

UART2接线:PA2 -> USART2_TX;PA3 -> USART2_RX

stm32cubemx含USB类的工程结构

main.c

我这里初始化串口2用来调试打印64字节数据

usbd_customhid.h

CUSTOM_HID_EPIN_SIZECUSTOM_HID_EPOUT_SIZE 定义了这些端点可以处理的最大数据包大小。在的代码中,如果将这些值设置为64字节,意味着这些端点被配置为可以一次性接收或发送最多64字节的数据。这是针对全速USB设备的标准中断端点最大包大小。**目前这里设置为2,**也就是说如果我发送64字节(HID规定最多64字节,中断传输),需要拆分32次才能发送或者接收完成。

下文第四章:枚举过程的第6行有详细描述。

usbd_conf.h

定义自定义 HID 设备接收「主机下发数据」的缓冲区长度为 64 字节。

USB 规范中:全速(FS)HID 设备的单报告最大长度为 64 字节,低速(LS)为 16 字节,高速(HS)为 512 字节。这里设为 64,说明设备是全速 USB 自定义 HID,缓冲区能容纳主机下发的完整输出报告。

指定自定义 HID 设备「报告描述符」的字节长度为 34 字节。

USB 主机枚举 HID 设备时,会主动读取设备的报告描述符以理解数据格式,这个宏必须和你实际编写的报告描述符的字节数完全一致,否则会导致设备枚举失败(主机无法解析描述符)。

定义自定义 HID 设备「全速模式下中断端点」的轮询间隔为 5ms。

  • 全速 USB 的帧周期是 1ms,bInterval=5表示主机每 5ms 轮询一次设备的中断端点;

  • 设备通过这个端点向主机上报「输入报告」(如传感器数据、按键状态);

  • 取值范围 1~255(帧),值越小轮询越频繁(实时性越好),但占用 USB 带宽越多。

usbd_desc.c

改了下pid和uid,正常是不用修改的,我这里拿两块f103测试,怕有影响

usbd_custom_hid_if.c

修改HID的报告描述符和usb回复事件;

cpp 复制代码
/* Private variables ---------------------------------------------------------*/
extern unsigned char USB_Recive_Buffer[64];//usb接收缓存
extern unsigned char USB_Recived_Count;//usb接收数据计数

/* USER CODE END PV */


/** Usb HID report descriptor. */
/** Usb HID report descriptor. */
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
  /* USER CODE BEGIN 0 */
  // ------------ 全局配置:定义厂商自定义HID设备的基础属性 ------------
  0x06, 0x00, 0xff,  // USAGE_PAGE (Vendor Defined Page 1) 
                     // 用途页:指定为厂商自定义(0xFF00),区别于标准HID(如鼠标/键盘的0x01)
  0x09, 0x01,        // USAGE (Vendor Usage 1) 
                     // 用途:厂商自定义用途ID=1,用于标识本设备的自定义功能
  0xa1, 0x01,        // COLLECTION (Application) 
                     // 集合类型(应用级):开始定义一个完整的HID应用逻辑,需以0xC0结束

  // ------------ 定义「输入报告」:设备 → 主机(如设备上报数据给电脑) ------------
  0x09, 0x01,        // USAGE (Vendor Usage 1) 
                     // 用途:关联到上述厂商自定义用途,标识该输入报告的用途
  0x15, 0x00,        // LOGICAL_MINIMUM (0) 
                     // 逻辑最小值:该报告中每个数据项的最小值为0
  0x26, 0xff, 0x00,  // LOGICAL_MAXIMUM (255) 
                     // 逻辑最大值:该报告中每个数据项的最大值为255(单字节无符号)
  0x75, 0x08,        // REPORT_SIZE (8) 
                     // 报告位宽:每个数据项的位数为8bit(1字节)
  0x95, 0x40,        // REPORT_COUNT (64) 
                     // 报告项数量:该输入报告包含64个上述8bit的数据项
                     // 输入报告总长度 = REPORT_SIZE × REPORT_COUNT = 8×64 = 512bit = 64字节
  0x81, 0x02,        // INPUT (Data,Var,Abs) 
                     // 输入报告属性:Data(数据型)、Var(可变值)、Abs(绝对值)
                     // 含义:设备主动向主机发送64字节的自定义数据,主机可通过中断端点读取

  // ------------ 定义「输出报告」:主机 → 设备(如电脑下发数据给设备) ------------
  0x09, 0x01,        // USAGE (Vendor Usage 1) 
                     // 用途:关联到上述厂商自定义用途,标识该输出报告的用途
  0x15, 0x00,        // LOGICAL_MINIMUM (0) 
                     // 逻辑最小值:该报告中每个数据项的最小值为0
  0x26, 0xff, 0x00,  // LOGICAL_MAXIMUM (255) 
                     // 逻辑最大值:该报告中每个数据项的最大值为255(单字节无符号)
  0x75, 0x08,        // REPORT_SIZE (8) 
                     // 报告位宽:每个数据项的位数为8bit(1字节)
  0x95, 0x40,        // REPORT_COUNT (64) 
                     // 报告项数量:该输出报告包含64个上述8bit的数据项
                     // 输出报告总长度 = 8×64 = 64字节(与USBD_CUSTOMHID_OUTREPORT_BUF_SIZE匹配)
  0x91, 0x02,        // OUTPUT (Data,Var,Abs) 
                     // 输出报告属性:Data(数据型)、Var(可变值)、Abs(绝对值)
                     // 含义:主机可通过中断端点向设备下发64字节的自定义数据,设备从缓冲区读取
  /* USER CODE END 0 */
  0xC0               // END_COLLECTION
                     // 结束应用级集合:与前面的0xA1 0x01配对,闭合HID逻辑定义
};

二. PortHelper.exe交互和uart打印

鼠标点击PortHelper软件(端点2 HID发送):

PC主机发送64字节-》stm32接收64字节 -》stm32回复64字节给PC主机

每1秒stm32配置串口自动打印:

stm32 -》给主机串口打印当前传输的64字节,传输后memset清空。

PortHelper勾选hex发送和hex显示,点击HID发送按钮1次(发64字节),PortHelper的接收窗口和sscom串口都显示对应的64字节数据

三. bus hound的枚举过程和数据发送记录

bus Hound记录usb枚举过程:以下是抓包数据,该数据对应下文的Bus Hound日志分析

bus Hound抓包的内容为下图:建议直接复制到记事本中,这样方便查看;

cpp 复制代码
Device  Phase  Data                                                                                                    Description                       Cmd.Phase.Ofs(rep)
------  -----  ------------------------------------------------------------------------------------------------------  --------------------------------  ------------------
  29.0  CTL    80 06 00 01  00 00 12 00                                                                                GET DESCRIPTOR                           1.1.0        
  29.0  IN     12 01 00 02  00 00 00 40  7f 04 4f 57  00 02 01 02  03 01                                               .......@..OW......                       1.2.0        
  29.0  CTL    80 06 00 02  00 00 09 00                                                                                GET DESCRIPTOR                           2.1.0        
  29.0  IN     09 02 29 00  01 01 00 c0  32                                                                            ..).....2                                2.2.0        
  29.0  CTL    80 06 00 02  00 00 29 00                                                                                GET DESCRIPTOR                           3.1.0        
  29.0  IN     09 02 29 00  01 01 00 c0  32 09 04 00  00 02 03 00  00 00 09 21  11 01 00 01  22 22 00 07  05 81 03 02  ..).....2..........!....""......         3.2.0        
               00 05 07 05  01 03 02 00  05                                                                            .........                                3.2.32       
  29.0  CTL    00 09 01 00  00 00 00 00                                                                                SET CONFIG                               4.1.0        
  29.0  CTL    21 0a 00 00  00 00 00 00                                                                                SET IDLE                                 5.1.0        
  29.0  CTL    81 06 00 22  00 00 62 00                                                                                GET DESCRIPTOR                           6.1.0        
  29.0  IN     06 00 ff 09  01 a1 01 09  01 15 00 26  ff 00 95 40  75 08 81 02  09 01 15 00  26 ff 00 95  40 75 08 91  ...........&...@u.......&...@u..         6.2.0        
               02 c0                                                                                                   ..                                       6.2.32       
  29.0  CTL    80 06 02 03  09 04 02 04                                                                                GET DESCRIPTOR                           7.1.0        
  29.0  IN     3a 03 53 00  54 00 4d 00  33 00 32 00  20 00 43 00  75 00 73 00  74 00 6f 00  6d 00 20 00  48 00 75 00  :.S.T.M.3.2. .C.u.s.t.o.m. .H.u.         7.2.0        
               6d 00 61 00  6e 00 20 00  69 00 6e 00  74 00 65 00  72 00 66 00  61 00 63 00  65 00                     m.a.n. .i.n.t.e.r.f.a.c.e.               7.2.32       
  29.0  CTL    80 06 03 03  09 04 02 04                                                                                GET DESCRIPTOR                           8.1.0        
  29.0  IN     1a 03 36 00  44 00 38 00  42 00 34 00  31 00 36 00  43 00 35 00  34 00 35 00  36 00                     ..6.D.8.B.4.1.6.C.5.4.5.6.               8.2.0        
  29.0  CTL    80 06 00 02  00 00 09 00                                                                                GET DESCRIPTOR                           9.1.0        
  29.0  IN     09 02 29 00  01 01 00 c0  32                                                                            ..).....2                                9.2.0        
  29.0  CTL    80 06 00 02  00 00 29 00                                                                                GET DESCRIPTOR                          10.1.0        
  29.0  IN     09 02 29 00  01 01 00 c0  32 09 04 00  00 02 03 00  00 00 09 21  11 01 00 01  22 22 00 07  05 81 03 02  ..).....2..........!....""......        10.2.0        
               00 05 07 05  01 03 02 00  05                                                                            .........                               10.2.32       
  29.0  CTL    21 0a 00 00  00 00 00 00                                                                                SET IDLE                                11.1.0        
  29.0  CTL    80 06 02 03  09 04 02 01                                                                                GET DESCRIPTOR                          12.1.0        
  29.0  IN     3a 03 53 00  54 00 4d 00  33 00 32 00  20 00 43 00  75 00 73 00  74 00 6f 00  6d 00 20 00  48 00 75 00  :.S.T.M.3.2. .C.u.s.t.o.m. .H.u.        12.2.0        
               6d 00 61 00  6e 00 20 00  69 00 6e 00  74 00 65 00  72 00 66 00  61 00 63 00  65 00                     m.a.n. .i.n.t.e.r.f.a.c.e.              12.2.32       
  29.1  OUT    00 01 02 03  04 05 06 07  08 09 10 11  12 13 14 15  16 17 18 19  20 21 22 23  24 25 26 27  28 29 30 31  .................... !"#$%&'()01        13.1.0        
               32 33 34 35  36 37 38 39  40 41 42 43  44 45 46 47  48 49 50 51  52 53 54 55  56 57 58 59  60 61 62 63  23456789@ABCDEFGHIPQRSTUVWXY`abc        13.1.32       
  30    OUT    00 00 01 02  03 04 05 06  07 08 09 10  11 12 13 14  15 16 17 18  19 20 21 22  23 24 25 26  27 28 29 30  ..................... !"#$%&'()0        14.1.0        
               31 32 33 34  35 36 37 38  39 40 41 42  43 44 45 46  47 48 49 50  51 52 53 54  55 56 57 58  59 60 61 62  123456789@ABCDEFGHIPQRSTUVWXY`ab        14.1.32       
               63                                                                                                      c                                       14.1.64       
  29.1  IN     00 01 02 03  04 05 06 07  08 09 10 11  12 13 14 15  16 17 18 19  20 21 22 23  24 25 26 27  28 29 30 31  .................... !"#$%&'()01        15.1.0        
               32 33 34 35  36 37 38 39  40 41 42 43  44 45 46 47  48 49 50 51  52 53 54 55  56 57 58 59  60 61 62 63  23456789@ABCDEFGHIPQRSTUVWXY`abc        15.1.32       
  30    IN     00 00 01 02  03 04 05 06  07 08 09 10  11 12 13 14  15 16 17 18  19 20 21 22  23 24 25 26  27 28 29 30  ..................... !"#$%&'()0        16.1.0        
               31 32 33 34  35 36 37 38  39 40 41 42  43 44 45 46  47 48 49 50  51 52 53 54  55 56 57 58  59 60 61 62  123456789@ABCDEFGHIPQRSTUVWXY`ab        16.1.32       
               63      

四. USB枚举过程与传输数据具体解释

4.1 Bus Hound 抓包日志逐行 USB 通信解析(基于 USB 2.0 协议)

以下解析严格遵循USB 枚举流程(设备描述符→配置描述符→类描述符→设置配置→数据传输),结合 USB 2.0 协议、HID 类规范及 Bus Hound 抓包字段定义,逐行拆解主机(PC)与 USB 设备的通信交互。

4.2、核心前提:USB 通信基础

  1. 传输类型 :日志中仅涉及控制传输(CTL)中断传输(IN/OUT,HID 设备默认)
    • CTL:控制传输的「Setup 阶段」,发送 8 字节请求包(Setup Packet),用于设备枚举、配置
    • IN:设备→主机的数据传输(如返回描述符、HID 输入报告)
    • OUT:主机→设备的数据传输(如发送 HID 输出报告)
  2. 端点含义Device列中.数字表示 USB 端点号(如 29.0 = 设备 29 的端点 0,所有 USB 设备的默认控制端点;29.1 = 设备 29 的端点 1)
  3. 小端格式:USB 多字节字段(如 wValue、wLength)均为小端(低字节在前),解析时需调换顺序(如 00 02→0x0200=512)

4.3、逐行 USB 通信解析(按日志顺序)

1. 第 1 行:29.0 CTL 80 06 00 01 00 00 12 00 | GET DESCRIPTOR | 1.1.0

  • 通信阶段 :主机向设备 29 的端点 0 发送「控制传输 Setup 包」,请求设备描述符(USB 枚举第一步)

  • 8 字节 Setup 包拆解 (对照 USB 2.0 规范 9.3 节):

    字节 字段名 十六进制 含义
    0 bmRequestType 80 数据方向:设备→主机;请求类型:标准请求;接收者:设备
    1 bRequest 06 请求类型:GET_DESCRIPTOR(获取描述符)
    2-3 wValue 00 01 描述符类型 = 设备描述符(0x01);描述符索引 = 0
    4-5 wIndex 00 00 语言 ID=0(默认,后续字符串描述符需指定语言)
    6-7 wLength 12 00 请求返回数据长度 = 0x0012=18 字节(设备描述符固定长度为 18 字节)

2. 第 2 行:29.0 IN 12 01 00 02 00 00 00 40 7f 04 4f 57 00 02 01 02 03 01|1.2.0

  • 通信阶段 :设备 29 通过端点 0 向主机返回设备描述符(响应上一步 GET_DESCRIPTOR 请求)

  • 18 字节设备描述符拆解 (对照 USB 2.0 规范 9.6.1 节):

    字节 字段名 十六进制 含义
    0 bLength 12 本描述符长度 = 18 字节(0x12)
    1 bDescriptorType 01 描述符类型 = 设备描述符(0x01)
    2-3 bcdUSB 00 02 支持 USB 协议版本 = USB 2.0(0x0200)
    4 bDeviceClass 00 设备类 = 由接口描述符指定(HID 设备需在接口层定义类)
    5 bDeviceSubClass 00 设备子类 = 由接口描述符指定
    6 bDeviceProtocol 00 设备协议 = 由接口描述符指定
    7 bMaxPacketSize0 40 端点 0 最大包长 = 64 字节(0x40,USB 2.0 全速设备最大值)
    8-9 idVendor 7f 04 厂商 ID(VID)=0x047F(自定义或测试 VID)
    10-11 idProduct 4f 57 产品 ID(PID)=0x574F(设备唯一标识)
    12-13 bcdDevice 00 02 设备版本号 = 2.00
    14 iManufacturer 01 厂商字符串索引 = 1(后续可通过索引 1 获取厂商名称)
    15 iProduct 02 产品字符串索引 = 2(后续可通过索引 2 获取产品名称)
    16 iSerialNumber 03 序列号字符串索引 = 3(后续可通过索引 3 获取序列号)
    17 bNumConfigurations 01 设备支持的配置数 = 1(仅 1 种工作配置)

3. 第 3 行:29.0 CTL 80 06 00 02 00 00 09 00 | GET DESCRIPTOR | 2.1.0

  • 通信阶段 :主机请求配置描述符头部(USB 枚举第二步:先获取配置描述符头部,确认总长度后再请求完整配置)
  • Setup 包核心字段
    • wValue=00 02:描述符类型 = 配置描述符(0x02)
    • wLength=09 00:请求返回 9 字节(配置描述符头部固定长度为 9 字节,含总长度字段)

4. 第 4 行:29.0 IN 09 02 29 00 01 01 00 c0 32 | 2.2.0

  • 通信阶段 :设备 29 返回配置描述符头部,告知主机完整配置的总长度

  • 9 字节配置描述符头部拆解 (对照 USB 2.0 规范 9.6.3 节):

    字节 字段名 十六进制 含义
    0 bLength 09 本描述符长度 = 9 字节(0x09)
    1 bDescriptorType 02 描述符类型 = 配置描述符(0x02)
    2-3 wTotalLength 29 00 完整配置的总长度 = 0x0029=41 字节(含配置、接口、HID、端点描述符)
    4 bNumInterfaces 01 本配置包含的接口数 = 1
    5 bConfigurationValue 01 配置值 = 1(后续 SET CONFIG 需指定此值激活配置)
    6 iConfiguration 00 配置字符串索引 = 0(无配置描述字符串)
    7 bmAttributes c0 供电模式 = 自供电(0xC0=11000000B,D6=1 表示自供电,D5=0 不支持远程唤醒)
    8 bMaxPower 32 设备最大功耗 = 100mA(0x32×2mA=64mA?此处 0x32 对应 64mA,USB 规范中单位为 2mA)

5. 第 5 行:29.0 CTL 80 06 00 02 00 00 29 00 | GET DESCRIPTOR | 3.1.0

  • 通信阶段 :主机请求完整配置描述符(基于上一步获取的 wTotalLength=41 字节,请求 0x29 字节数据)
  • Setup 包核心字段:wLength=29 00→0x0029=41 字节(覆盖配置、接口、HID、端点描述符)

6. 第 6 行:29.0 IN 09 02 29 00 01 01 00 c0 32 09 04 00 00 02 03 00 00 00 09 21 11 01 00 01 22 22 00 07 05 81 03 02 00 05 07 05 01 03 02 00 05 | 3.2.0

  • 通信阶段 :设备 29 返回完整配置描述符集合(含 1 个配置描述符 + 1 个接口描述符 + 1 个 HID 描述符 + 2 个端点描述符)
  • 子描述符拆解 (按顺序):
    1. 配置描述符(前 9 字节):与第 4 行完全一致(重复是因为完整配置需包含头部)

    2. 接口描述符 (第 9-17 字节,09 04 ... 00):

      字段名 十六进制 含义
      bLength 09 长度 = 9 字节
      bDescriptorType 04 类型 = 接口描述符(0x04)
      bInterfaceNumber 00 接口号 = 0
      bAlternateSetting 00 备用接口 = 0
      bNumEndpoints 02 端点数量 = 2(不含端点 0,含 1 个 IN 端点 + 1 个 OUT 端点)
      bInterfaceClass 03 接口类 = HID 类(0x03,USB HID 规范定义)
      bInterfaceSubClass 00 子类 = 0(通用 HID 设备)
      bInterfaceProtocol 00 协议 = 0(无特定协议)
      iInterface 00 接口字符串索引 = 0
    3. HID 描述符 (第 17-25 字节,09 21 ... 01):

      字段名 十六进制 含义
      bLength 09 长度 = 9 字节
      bDescriptorType 21 类型 = HID 描述符(0x21)
      bcdHID 11 01 支持 HID 协议版本 = 1.11(0x0111)
      bCountryCode 00 国家代码 = 0(通用)
      bNumDescriptors 01 下级描述符数量 = 1(仅报告描述符)
      bDescriptorType 22 下级描述符类型 = 报S告描述符(0x22)
      wDescriptorLength 22 00 报告描述符长度 = 0x0022=34 字节
    4. 端点描述符 1(IN 端点) (第 25-31 字节,07 05 ... 05):

      字段名 十六进制 含义
      bLength 07 长度 = 7 字节
      bDescriptorType 05 类型 = 端点描述符(0x05)
      bEndpointAddress 81 端点地址 = 0x81(IN 端点,端点号 1)
      bmAttributes 03 端点类型 = 中断传输(0x03)
      wMaxPacketSize 02 00 最大包长 = 2 字节
      bInterval 05 轮询间隔 = 5ms(中断传输的查询周期)
    5. 端点描述符 2(OUT 端点)(第 31-37 字节,07 05 ... 05):| bEndpointAddress| 01 | 端点地址 = 0x01(OUT 端点,端点号 1) || 其余字段与 IN 端点一致(中断传输,最大包长 2 字节,间隔 5ms) |

cpp 复制代码
  //端点包长2字节;5ms轮询
    29.0  IN     09 02 29 00  01 01 00 c0  32 09 04 00  00 02 03 00  00 00 09 21  11 01 00 01  22 22 00 07  05 81 03 02  ..).....2..........!....""......         3.2.0        
               00 05 07 05  01 03 02 00  05 



//端点包长64字节;1ms轮询
  40.0  IN     09 02 29 00  01 01 00 c0  32 09 04 00  00 02 03 00  00 00 09 21  11 01 00 01  22 22 00 07  05 81 03 40  ..).....2..........!...."".....@         8.2.0        
               00 01 07 05  01 03 40 00  01  

7. 第 7 行:29.0 CTL 00 09 01 00 00 00 00 00 | SET CONFIG | 4.1.0

  • 通信阶段:主机向设备 29 发送「设置配置请求」,激活配置(USB 枚举关键步骤:设备从默认状态进入配置状态)
  • Setup 包核心字段
    • bmRequestType=00:主机→设备;标准请求;设备接收
    • bRequest=09:SET_CONFIGURATION(设置配置)
    • wValue=01 00:配置值 = 1(对应第 4 行的 bConfigurationValue=1)
    • wLength=00 00:无数据阶段(仅 Setup+Status 阶段)

8. 第 8 行:29.0 CTL 21 0a 00 00 00 00 00 00 | SET IDLE | 5.1.0

  • 通信阶段:主机向 HID 设备发送「SET IDLE 请求」(HID 类请求,减少中断传输的无效数据)
  • Setup 包核心字段 (对照 HID 1.11 规范 7.2.4 节):
    • bmRequestType=21:主机→设备;类请求;接口接收
    • bRequest=0a:SET_IDLE(设置空闲)
    • wValue=00 00:空闲时长 = 0(表示设备仅在数据变化时发送中断 IN 报告,无变化时不发送)
    • wIndex=00 00:接口号 = 0(对应第 6 行的 bInterfaceNumber=0)

9. 第 9 行:29.0 CTL 81 06 00 22 00 00 62 00 | GET DESCRIPTOR | 6.1.0

  • 通信阶段 :主机请求HID 报告描述符(HID 设备必需:描述输入 / 输出报告的数据格式)
  • Setup 包核心字段
    • wValue=00 22:描述符类型 = 报告描述符(0x22)
    • wLength=62 00→0x0062=98 字节(请求报告描述符数据)

10. 第 10 行:29.0 IN 06 00 ff 09 01 a1 01 09 01 15 00 26 ff 00 95 40 75 08 81 02 09 01 15 00 26 ff 00 95 40 75 08 91 02 c0 | 6.2.0

  • 通信阶段 :设备 29 返回HID 报告描述符(定义 HID 报告的结构,如输入报告含 64 字节数据,输出报告含 64 字节数据)
  • 关键字段解析 (对照 HID 1.11 规范 6.2.1 节):
    • 06 00 ff:Usage Page = 厂商自定义(0xFF00,非标准 HID 用法)
    • 09 01:Usage = 自定义用法 1
    • a1 01:Collection = 应用集合(报告的逻辑分组)
    • 15 00:Logical Minimum=0
    • 26 ff 00:Logical Maximum=255
    • 95 40:Report Count=64(报告含 64 个数据项)
    • 75 08:Report Size=8(每个数据项 8 位 = 1 字节)
    • 81 02:Input = 输入报告(数据从设备到主机,可变长度)
    • 91 02:Output = 输出报告(数据从主机到设备,可变长度)
    • c0:End Collection = 结束集合

11. 第 11 行:29.0 CTL 80 06 02 03 09 04 02 04 | GET DESCRIPTOR | 7.1.0

  • 通信阶段 :主机请求字符串描述符(获取设备的人类可读名称,如产品名)
  • Setup 包核心字段
    • wValue=03 02:描述符类型 = 字符串描述符(0x03);字符串索引 = 2(对应第 2 行的 iProduct=2)
    • wIndex=04 09:语言 ID=0x0409(英文,USB 规范中语言 ID 定义)
    • wLength=02 04→0x0402=1026 字节(足够容纳长字符串)

12. 第 12 行:29.0 IN 3a 03 53 00 54 00 4d 00 33 00 32 00 20 00 43 00 75 00 73 00 74 00 6f 00 6d 00 20 00 48 00 75 00 6d 00 61 00 6e 00 20 00 69 00 6e 00 74 00 65 00 72 00 66 00 61 00 63 00 65 00 | 7.2.0

  • 通信阶段 :设备 29 返回字符串描述符(产品名)(Unicode 编码,每个字符 2 字节,低字节在前)
  • 字符串解析 (将十六进制转为 Unicode 字符串):
    • 53 00→'S',54 00→'T',4d 00→'M',33 00→'3',32 00→'2',20 00→' ',43 00→'C'...
    • 完整字符串:STM32 Custom Human Interface(STM32 自定义人机接口,确认设备 29 为 STM32 的 HID 调试接口)

13. 第 13 行:29.0 CTL 80 06 03 03 09 04 02 04 | GET DESCRIPTOR | 8.1.0

  • 通信阶段 :主机请求另一个字符串描述符(字符串索引 = 3,对应第 2 行的 iSerialNumber=3,序列号)

14. 第 14 行:29.0 IN 1a 03 36 00 44 00 38 00 42 00 34 00 31 00 36 00 43 00 35 00 34 00 35 00 36 00 | 8.2.0

  • 通信阶段 :设备 29 返回序列号字符串描述符(Unicode 编码)
  • 字符串解析
    • 36 00→'6',44 00→'D',38 00→'8',42 00→'B',34 00→'4',31 00→'1',36 00→'6',43 00→'C'...
    • 完整序列号:6D8B416C5456(设备唯一序列号)

15. 第 15-22 行:重复 GET DESCRIPTOR + SET IDLE

  • 通信阶段:主机重复请求配置描述符和设置 IDLE(可能是系统驱动重新确认设备配置,确保通信稳定性,属于正常重试逻辑)

这里开始数据传输

使用PortHelper 连接usb设备,参考上面截图一次性发送64字节,由于前面的端点包长我设置为2字节(最大64字节);这里为了方便下篇文章编写来区分(中断传输与SOF包之间的关系,下篇文章介绍);端点包长(接收和发送)都为2字节,我这里发送64字节,需要发送32次

根据前面配置后PC主机和USB之间的数据传输(空闲/主机发送/USB设备发送)

全速协议规定:每1ms发一次SOF包

前面设置了:告诉主机,我这个设备最多间隔5ms,发送PID IN包(中断传输)

主机和USB设备枚举成功后:空闲的数据发送
主机发送数据 + USB设备接收数据具体
USB设备发送数据 + 主机接收数据

23. 第 23 行:29.1 OUT 00 01 02 03 ... 63 | 13.1.0

  • 通信阶段 :主机通过设备 29 的端点 1(OUT 端点,0x01)发送 HID 输出报告(中断传输)
  • 数据含义:发送连续字节数据(0x00→0x63,共 64 字节),结合设备 29 为 STM32 HID 接口,是向 STM32 发送的控制指令

24. 第 24 行:30 OUT 00 00 01 02 ... 63 | 14.1.0

  • 通信阶段 :主机向设备 30(HID-compliant vendor-defined device,自定义 HID 设备)发送HID 输出报告
  • 数据含义:类似第 23 行,发送 0x00→0x63 的连续数据(64 字节),是与设备 30 的通信测试

25. 第 25 行:29.1 IN 00 01 02 03 ... 63 | 15.1.0

  • 通信阶段 :设备 29 通过端点 1(IN 端点,0x81)返回 HID 输入报告(中断传输,响应第 23 行的 OUT 数据)
  • 数据含义 :返回与主机发送完全一致的数据(0x00→0x63),属于数据回显(验证主机→设备→主机的通信链路正常,无数据丢失或错误)

26. 第 26 行:30 IN 00 00 01 02 ... 63 | 16.1.0

  • 通信阶段 :设备 30 返回HID 输入报告(响应第 24 行的 OUT 数据)
  • 数据含义:同样回显主机发送的 0x00→0x63 数据,确认设备 30 的通信链路正常

4.4、整体 USB 通信流程总结

  1. 枚举阶段(第 1-12 行):主机→设备 29:请求设备描述符→请求配置描述符头部→请求完整配置描述符→设置配置→请求 HID 报告描述符→设置 IDLE
  2. 确认阶段(第 13-22 行):重复请求配置和 IDLE,确保设备稳定
  3. 数据传输阶段(第 23-26 行):主机向设备 29/30 发送测试数据,设备回显,验证通信链路

核心结论:日志记录的是STM32 HID 设备(29)和自定义 HID 设备(30)的枚举与通信测试过程,无异常通信(所有请求均有正确响应,数据回显完整)。

五. 具体解释

前面的的第7 8 9行共3 个独立请求,"前 2 次重试无响应 + 第 3 次成功响应";这个问题;

可能为1:当成独立行打印

你看到的"PC 发了 3 次 USB 请求,STM32 才回 1 次"并不是芯片"漏回",而是 Bus Hound 把 "同一笔事务的重试" 也当成独立行打印出来了。

可能为2:USB 控制传输的 "3 次重试" 协议机制

USB 协议为保证控制传输的可靠性,明确规定了 **"请求 - 重试 - 响应" 的错误恢复逻辑 **,这是 "3 次发 1 次回" 的底层协议依据:当然这里3包数据都是不一样的,应该不算重发机制;

  1. 协议重试规则(来自摘要 1、6):

    • 控制传输(CTL 阶段)是 USB 中优先级最高的传输类型,用于设备配置、枚举等核心操作,必须保证可靠性;
    • 若主机发送控制请求(如 SET CONFIG、GET DESCRIPTOR)后,未在规定时间内收到设备的 ACK 握手包 / 数据响应 (可能因总线干扰、设备未就绪导致),主机会自动重试,最多重试 2 次,加上首次发送共 3 次
    • 仅当第 3 次请求仍无响应时,主机才会向上层软件报告 "传输失败"(如日志中设备 36 的 "Device Descriptor Request Failed",就是 3 次重试后仍失败的结果)。
  2. 日志中的重试痕迹对应:你观察到的 "3 次请求",本质是主机对同一控制请求的 3 次发送尝试(首次 + 2 次重试):

    • 例如日志中 "SET CONFIG(4.1.0)""SET IDLE(5.1.0)""GET DESCRIPTOR(6.1.0)" 这 3 个连续控制请求,可能存在前 2 个请求(SET CONFIG/SET IDLE)因设备未就绪而未响应,主机重试后,第 3 个请求(GET DESCRIPTOR)才触发设备回复 ------ 并非 3 个独立请求,而是 "前 2 次重试无响应 + 第 3 次成功响应" 的连贯过程。

可能为3:设备 29(STM32 HID 设备)的 "初始化延迟"

日志中设备 29 是 "USB Input Device"(本质是 STM32 芯片的 HID 调试接口,关联 STM32 STLink),这类设备在接收控制请求时,需完成硬件配置、接口初始化等操作,存在天然的处理延迟,导致前 2 次请求 "被忽略",第 3 次请求时才就绪:

  1. SET CONFIG 后的配置延迟:日志中 4.1.0 是 "SET CONFIG(设置配置)" 请求 ------ 主机通过该请求激活设备 29 的配置(如启用 HID 接口、初始化端点 1)。但 STM32 芯片在接收 SET CONFIG 后,需完成:

    • 接口寄存器配置(启用 HID 类协议);
    • 端点 1(中断端点)的缓冲区初始化;
    • 固件从 "默认状态" 切换到 "配置状态";这个过程通常需要1-2 个 USB 帧周期(1 帧 = 1ms),导致主机首次发送 SET CONFIG 时,设备仍在初始化,无法返回 ACK,主机会触发第 1 次重试;重试时设备仍未就绪,触发第 2 次重试;直到第 3 次请求(可能是后续的 GET DESCRIPTOR)时,设备配置完成,才会回复。
  2. HID 设备的 SET IDLE 就绪延迟:日志中 5.1.0 是 "SET IDLE(设置空闲)" 请求 ------ 这是 HID 类专属请求,用于让设备仅在数据变化时发送中断报告(减少无效传输)。但设备 29 需:

    • 解析 SET IDLE 的参数(wValue=00 00,表示 "无数据变化时不发送报告");
    • 配置 HID 报告的触发逻辑;这个过程同样存在延迟,导致 SET IDLE 的前 2 次请求无响应,直到第 3 次请求(GET DESCRIPTOR)时,HID 逻辑初始化完成,设备才能返回报告描述符(6.2.0 的 IN 数据)。

结论:

前 2 次重试无响应 + 第 3 次成功响应";这个问题:

实际上3次都有USB设备的应答ACK,这3包数据是独立发送的,不是一起发送的;

3包SETUP数据均有USB设备的ACK回复,之所以显示没有回复,是因为,USB设备接收到这几包数据后它只回复了ACK,并没有实际的数据量,所以Bus Hound它没有显示,并不是没有响应

均有USB设备的ACK回复

相关推荐
tianyue10011 小时前
STM32G431 ADC 多个channel 采集
stm32·单片机·嵌入式硬件
安生生申14 小时前
STM32 ESP8266连接ONENET
c语言·stm32·单片机·嵌入式硬件·esp8266
youcans_19 小时前
【动手学STM32G4】(3)STM32G431之定时器
stm32·单片机·嵌入式硬件·定时器
硬汉嵌入式19 小时前
ST最新推出的CMSIS-Driver,一套驱动完成对所有STM32系列的驱动支持
stm32·st·cmsis-driver
小李做物联网20 小时前
【单片机毕设】c24基于单片机stm32蓝牙温室大棚物联网毕业设计
stm32·单片机·嵌入式硬件·物联网
polarislove02142 天前
10.1 [ADC] 逐次逼近型ADC-嵌入式铁头山羊STM32笔记
笔记·stm32·嵌入式硬件
qq_672592752 天前
STM32超声测距离的测量精度评估
stm32·硬件架构·硬件工程
单片机系统设计2 天前
基于STM32的智能垃圾桶/语音分类/自动开盖/矩阵按键
stm32·矩阵·毕业设计·语音识别·智能垃圾桶
三品吉他手会点灯2 天前
STM32F103 学习笔记-21-串口通信(第3节)-STM32串口初始化结构体和固件库讲解
笔记·stm32·单片机·嵌入式硬件·学习