CherryUSB主机枚举流程详解:从设备连接到驱动加载

【免费下载链接】CherryUSB CherryUSB is a tiny and portable USB Stack (device & host) for embedded system with USB IP 【免费下载链接】CherryUSB 项目地址: https://gitcode.com/gh_mirrors/ch/CherryUSB

CherryUSB是一个轻量级且可移植的USB协议栈(设备和主机模式),专为嵌入式系统设计。本文将详细解析CherryUSB主机枚举流程,帮助开发者理解从USB设备连接到驱动加载的完整过程,掌握嵌入式系统中USB设备的识别机制。

什么是USB主机枚举?

USB主机枚举是指USB主机检测到新设备连接后,通过一系列标准化步骤识别设备类型、配置设备参数并加载合适驱动程序的过程。这个过程就像给新认识的设备"办理入职手续",让主机知道如何与设备通信。

在CherryUSB中,这一核心功能由usbh_core.c文件实现,主要通过usbh_enumerate函数完成整个枚举流程。

枚举流程全景图

下图展示了一个典型的USB枚举过程数据包交互序列,包含了从设备检测到配置完成的完整通信过程:

USB枚举过程数据包交互

图:USB枚举过程中的控制传输序列,显示了设备描述符请求、地址分配和配置选择等关键步骤

枚举流程的七个关键步骤

1. 设备连接检测

当USB设备插入主机端口时,主机控制器首先检测到物理连接。CherryUSB通过根集线器(Root Hub)监控端口状态变化,在检测到设备插入后触发枚举流程。

2. 配置端点0

枚举过程首先需要通过端点0(控制端点)与设备通信。CherryUSB在usbh_enumerate函数中初始化端点0,根据设备速度设置默认的最大数据包大小(MPS):

// 代码片段来自core/usbh_core.c
ep->wMaxPacketSize = usbh_get_default_mps(hport->speed);

低速设备默认MPS为8字节,全速为64字节,高速为512字节。

3. 获取设备描述符

主机发送GET_DESCRIPTOR请求获取设备描述符,首先读取前8字节以获取基本信息:

// 代码片段来自core/usbh_core.c
setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_DEVICE;
setup->bRequest = USB_REQUEST_GET_DESCRIPTOR;
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_DEVICE << 8) | 0);
setup->wIndex = 0;
setup->wLength = 8;

设备描述符包含了设备的USB版本、厂商ID(VID)、产品ID(PID)等关键信息,这些信息会被解析并存储在hport->device_desc结构体中。

4. 设置设备地址

成功获取设备描述符后,主机会为设备分配一个唯一地址(1-127之间):

// 代码片段来自core/usbh_core.c
dev_addr = usbh_allocate_devaddr(&hport->bus->devgen);
setup->bRequest = USB_REQUEST_SET_ADDRESS;
setup->wValue = dev_addr;

地址分配通过usbh_allocate_devaddr函数实现,使用位图管理已分配地址,确保地址唯一性。

5. 获取完整配置描述符

设备获得地址后,主机会请求完整的配置描述符,包括接口和端点信息:

// 代码片段来自core/usbh_core.c
setup->wValue = (uint16_t)((USB_DESCRIPTOR_TYPE_CONFIGURATION << 8) | config_index);
setup->wLength = wTotalLength;

配置描述符解析由parse_config_descriptor函数完成,将接口和端点信息存储在hport->config结构体中,为后续驱动匹配做准备。

6. 获取字符串描述符(可选)

如果设备支持,主机可以进一步请求字符串描述符,获取厂商名称、产品名称和序列号等可读性信息:

// 代码片段来自core/usbh_core.c
ret = usbh_get_string_desc(hport, USB_STRING_MFC_INDEX, string_buffer, 128);

这些信息通常用于调试和用户界面显示,增强用户体验。

7. 设置配置并加载驱动

枚举的最后一步是选择设备配置,并为每个接口加载合适的驱动:

// 代码片段来自core/usbh_core.c
setup->bRequest = USB_REQUEST_SET_CONFIGURATION;
setup->wValue = config_value;

CherryUSB通过usbh_find_class_driver函数根据接口的类、子类和协议信息匹配合适的驱动程序,并调用驱动的连接函数完成初始化。

枚举过程中的关键数据结构

CherryUSB使用多个关键数据结构存储枚举过程中的信息:

  • struct usbh_hubport:表示USB集线器的一个端口,包含设备描述符、配置信息和端点信息
  • struct usb_device_descriptor:存储设备级描述符信息
  • struct usb_configuration_descriptor:存储配置描述符信息
  • struct usbh_class_driver:表示一个USB类驱动,包含驱动名称和操作函数

这些结构在usbh_core.h中定义,构成了CherryUSB主机模式的核心数据模型。

常见枚举问题及解决方法

枚举过程中可能遇到各种问题,以下是一些常见情况及解决方法:

  1. 设备无响应:检查USB物理连接,确保设备供电正常
  2. 描述符请求失败:可能是端点0配置错误,检查ep0_request_buffer大小
  3. 地址分配失败:检查CONFIG_USBHOST_MAX_BUS配置,确保地址空间足够
  4. 驱动匹配失败:确认设备类驱动已正确注册,检查类、子类和协议值是否匹配

CherryUSB提供了详细的日志输出(通过USB_LOG_*宏),可帮助开发者定位枚举过程中的问题。

总结

USB主机枚举是嵌入式系统中USB通信的基础,理解这一过程对于开发USB相关应用至关重要。CherryUSB通过清晰的模块化设计,将复杂的枚举流程封装在usbh_core.c中,提供了高效可靠的枚举实现。

通过本文的解析,希望能帮助开发者深入理解CherryUSB的枚举机制,为USB设备开发和调试提供有力支持。如需进一步了解,可以参考项目中的示例代码和官方文档。

【免费下载链接】CherryUSB CherryUSB is a tiny and portable USB Stack (device & host) for embedded system with USB IP 【免费下载链接】CherryUSB 项目地址: https://gitcode.com/gh_mirrors/ch/CherryUSB

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐