问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

esp32 组成局域网 esp32配置

创作时间:
作者:
@小白创作中心

esp32 组成局域网 esp32配置

引用
51CTO
1.
https://blog.51cto.com/u_16213573/10201687

本文将详细介绍如何使用ESP32S3和TinyUSB库配置局域网。内容包括硬件准备、USB设备初始化、设备描述符配置、配置描述符配置、报告描述符配置、字符串描述符配置、发送和接收报告数据等多个步骤。

开发准备

硬件型号:ESP32S3
开发环境:ESP-IDF v4.4
开发平台:VS Code

如果在使用官方TinyUSB库时出现问题,可能是作者有使用个人TinyUSB库的原因,资源见文章底部

第一步:确保硬件支持TinyUSB库并已开启配置

如上图所示,开启TinyUSB、HID功能

如果未找到HID相关开启选项,可自行检查硬件是否支持,或者配置文件是否配对

第二步:初始化USB设备

ESP_LOGI(TAG, "USB initialization");
const tinyusb_config_t tusb_cfg = {};
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg));
ESP_LOGI(TAG, "USB initialization DONE");

如需手动配置,见以下步骤,否则跳过即可

typedef struct {
    tusb_desc_device_t *descriptor;    // 设备描述符结构体
    const char **string_descriptor;    // 字符串描述符
    const uint8_t *config_descriptor;  // 配置描述符数组
    bool external_phy;                 // 外部PHY,一般为false
} tinyusb_config_t;

设备描述符tusb_desc_device_t

typedef struct TU_ATTR_PACKED
{
  uint8_t  bLength            ;    // 设备描述符的字节数大小
  uint8_t  bDescriptorType    ;    // 描述符类型,设备描述符为0x01
  uint16_t bcdUSB             ;    // USB版本号
  uint8_t  bDeviceClass       ;    // USB分配的设备类代码,0x01~0xfe为标准设备类,0xff为厂商自定义类型
  uint8_t  bDeviceSubClass    ;    // USB分配的子类代码
  uint8_t  bDeviceProtocol    ;    // USB分配的设备协议代码
  uint8_t  bMaxPacketSize0    ;    // 端点0的最大信息包大小
  uint16_t idVendor           ;    // 制造商ID
  uint16_t idProduct          ;    // 产品ID
  uint16_t bcdDevice          ;    // 设备出厂编号
  uint8_t  iManufacturer      ;    // 制造商的字符串描述符索引
  uint8_t  iProduct           ;    // 产品的字符串描述符索引
  uint8_t  iSerialNumber      ;    // 设备序列号的字符串描述符索引
  uint8_t  bNumConfigurations ;    // 可能的配置数量
} tusb_desc_device_t;

TinyUSB官方默认配置如下所示:

tusb_desc_device_t descriptor_kconfig = {
    .bLength = sizeof(descriptor_kconfig),
    .bDescriptorType = TUSB_DESC_DEVICE,        // 0x01
    .bcdUSB = 0x0200,    // USB2.0                            
    .bDeviceClass = 0x00,
    .bDeviceSubClass = 0x00,
    .bDeviceProtocol = 0x00,
    .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,    // 64
    .idVendor = 0xCafe,
    .idProduct = USB_TUSB_PID,    // 0x4010
    .bcdDevice = 0x0100,
    .iManufacturer = 0x01,
    .iProduct = 0x02,
    .iSerialNumber = 0x03,
    .bNumConfigurations = 0x01
};

配置描述符config_descriptor数组

默认配置如下所示:

uint8_t const desc_configuration[] = {
    
    // 配置描述符
    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, TUSB_DESC_TOTAL_LEN, 0, 100),
    
    // 接口描述符、HID描述符、端点描述符
    TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, STRID_HID_INTERFACE, HID_PROTOCOL_NONE, sizeof(desc_hid_report), 0x01, 0x81, 64, 10)
};

TUD_CONFIG_DESCRIPTOR为宏定义,跳转之后见以下解析:

其中配置描述符解析说明如下:

固定长度9 -- 配置描述符
配置描述符 -- TUSB_DESC_CONFIGURATION -- 0x02
配置描述符信息总的大小,包括接口描述符、端点描述符等等 -- U16_TO_U8S_LE(TUSB_DESC_TOTAL_LEN) --> 9 + 9 + 9 + 7 + 7(双向通信)
接口数量 -- ITF_NUM_TOTAL --> 1
Set_Configuration命令需要的参数值 -- 1
配置字符串索引 -- 0
bit7=1 bit6:1--自供电 0--总线供电 bit5:1--远程唤起 0--不支持 bit[4:0]=0 -- TU_BIT(7) | 0
供电 -- (100)/2 == 50*2 = 100mA

9, TUSB_DESC_CONFIGURATION, U16_TO_U8S_LE(TUSB_DESC_TOTAL_LEN), ITF_NUM_TOTAL, 1, 0, TU_BIT(7) | 0, (100)/2,

如果是双向通信则按上述设置,如果仅是单向输入或输出的话,配置描述符信息总的大小需要变成9 + 9 + 9 + 7

TUD_HID_INOUT_DESCRIPTOR为宏定义,跳转之后见以下解析:

其中接口描述符解析说明如下:

固定长度9 -- 接口描述符
接口描述符 -- TUSB_DESC_INTERFACE --> 0x04
接口0 (接口从0开始) -- 0
接口索引值 -- 0
端点个数(端点0不可用)-- 2
3 = HID -- TUSB_CLASS_HID --> 0x03
接口子类型:01为Boot Device,键鼠在BIOS下就启动 -- 0
接口协议:00--None 01--Keyboard 02--Mouse -- 0
描述该接口的字符串索引 -- STRID_HID_INTERFACE

9, TUSB_DESC_INTERFACE, 0, 0, 2, TUSB_CLASS_HID, (uint8_t)((0) ? HID_SUBCLASS_BOOT : 0), 0, STRID_HID_INTERFACE,

其中HID描述符解析说明如下:

固定长度9 -- HID描述符
HID描述符 -- HID_DESC_TYPE_HID --> 0x21
HID专属版本号 -- 0x0111
国家代码 -- 0
附属类描述字的数目1个 -- 1
描述字类型:报告 -- HID_DESC_TYPE_REPORT --> 0x22
HID报告描述字总字节数 -- sizeof(desc_hid_report)

9, HID_DESC_TYPE_HID, U16_TO_U8S_LE(0x0110), 0, 1, HID_DESC_TYPE_REPORT, U16_TO_U8S_LE(sizeof(desc_hid_report)),

其中端点描述符解析说明如下:

固定长度7 -- 端点描述符 -- 输入端点
端点描述符 -- TUSB_DESC_ENDPOINT
bit[7]:1--IN--设备到主机 0--OUT--主机到设备 -- 0x81
传输类型 -- TUSB_XFER_INTERRUPT(中断)
端点最大信息包尺寸 -- 最大64 -- 0x40
轮询间隔 -- 10

7, TUSB_DESC_ENDPOINT, 0x81, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(0x40), 10,

如果需要将HID设备设置为双向通信,则需要加上输出端点,如下所示:

固定长度7 -- 端点描述符 -- 输出端点
端点描述符 -- TUSB_DESC_ENDPOINT
bit[7]:1--IN--设备到主机 0--OUT--主机到设备 -- 0x01
传输类型 -- TUSB_XFER_INTERRUPT(中断)
端点最大信息包尺寸 -- 最大64 -- 0x40
轮询间隔 -- 10

7, TUSB_DESC_ENDPOINT, 0x01, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(0x40), 10

到这里,描述符config_descriptor数组基本配置完成了!

配置报告描述符desc_hid_report(重点!!!)

这里作者使用的是TinyUSB官方的HID通用输入输出设备模板,如需自定义报告描述符,可适用于HID Descriptor Tool官方生成工具,资源在文章底部

uint8_t const desc_hid_report[] = {
    TUD_HID_REPORT_DESC_GENERIC_INOUT(63, HID_REPORT_ID(3))
};

上述代码中,63表示一次最大发送报告数量,HID_REPORT_ID(3)表示HID通用设备的报告ID为3。

需要注意的是,不同类型的设备报告ID必要不同!,因为在发送和接收报告数据时,需要通过报告ID来辨别是哪个类型的设备,如下所示:

uint8_t const desc_hid_report[] = {
    TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD)),    // 1
    TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(REPORT_ID_MOUSE)),    // 2
    TUD_HID_REPORT_DESC_GENERIC_INOUT(63, HID_REPORT_ID(3))
};

这是因为默认第0字节会存放报告ID,占位一个字节,例如:端点最大信息包尺寸为64,那么一次最大发送报告数量应该为63;端点最大信息包尺寸为32,那么一次最大发送报告数量应该为31。

配置字符串描述符string_descriptor

tusb_desc_strarray_device_t string_descriptor= {
    // array of pointer to string descriptors
    (char[]){0x09, 0x04}, // 0: 支持语言:英语 (0x0409)
    "TinyUSB",            // 1: 制造商
    "TinyUSB Device",     // 2: 产品
    "123456",             // 3: 串行、芯片ID
    "TinyUSB HID"         // 4: HID
};

这些都可以自定义,不一定要按照上面的配置

关于语言的配置,一般都用英语,如需配置其他语言,可下载文档:Universal Serial Bus (USB),自行参阅

到这里,USB HID设备基本配置初始完成!

第三步:发送和接收报告数据

发送报告数据

tud_hid_report函数发送报告

// 检查接口是否可用
if (tud_hid_ready())
{    
    uint8_t report_data[63] = {1, 2, 3, 4};
    
    // 3 -- 报告ID
    // 发送的报告数组
    // 发送的长度
    tud_hid_report(3, report_data, 63);
}

其中发送的长度为报告描述符中一次最大发送报告数量,即63,必须设置正确,否则使用调试工具无法在HID设备上抓取报告数据,只能在USB总线上抓取!!

注意在抓取数据时,必须先打开HID设备(例如PortHelper),才能抓取到数据):

上图中,03表示报告ID,后面数据为用户发送报告数据,调试工具为Bus Hound,资源见文章底部

接收报告数据

需要重定向接收报告回调函数,在HID接收到报告数据时,则触发该回调函数

void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
{
    /*
    (void) itf;              // 一般都为0
    (void) report_id;        // 报告ID
    (void) report_type;      // 报告类型
    (void) buffer;           // 接收报告数组
    (void) bufsize;          // 接收报告长度
    */
    // 处理代码
}

总结

以上为作者自己在开发过程中一些见解,如有错误还请各位大佬多多指点,我是陈师傅,我们下章再见!

资源下载https://pan.baidu.com/s/1x2iweOhID6AAAPnns8qLzA?pwd=2b39

本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号