- 嵌入式
- 驱动开发
- 物联网
【免费下载链接】CherryUSB
CherryUSB is a tiny and beautiful, high performance and portable USB host and device stack for embedded system with USB IP
本文基于 CherryUSB 仓库的《基于现有 demo 快速验证》文档(docs/zh/quick_start/demo.rst)展开:先讲清"为什么先跑 demo",完整继承原文档罗列的各芯片平台官方 SDK demo 清单与 ESP32、STM32 两条实操路线,并结合仓库源码(glue 层、Kconfig、测试工程)补充每个步骤背后的实现依据,帮助你在动手移植前快速获得一次可运行的 USB 验证。
一、为什么推荐"先跑 Demo"
原文档开宗明义:在学习 USB 或 CherryUSB 源码之前,应优先基于现有 demo 做快速验证。理由很实际——跑通 demo 能提升对 USB 的兴趣、建立继续深入的信心;反过来,如果一上来就自己摸索写代码、或者先啃 USB 基本概念,最后"发现一点都看不懂,概念好多,根本记不住",往往会丧失继续学习 USB 的兴趣。因此官方建议的路径是:先跑通 demo → 再阅读概念 → 最后移植。
跑通 demo 后,你至少掌握三件事:
- 目标芯片的 USB IP(DWC2、FSDEV、MUSB、CHIPIDEA、EHCI/OHCI、XHCI 等)在 CherryUSB port 目录下的对应驱动文件如何接入;
usb_config.h配置模板(cherryusb_config_template.h)中哪些宏必须打开;- 设备端
usbd_initialize()/ 主机端usbh_initialize()的最小调用方式。
二、官方 SDK 支持的 Demo 平台清单
原文档以表格形式罗列了当前支持的 demo 仓库("Version"列表示该 demo 对应的 CherryUSB 版本与主干的相对关系)。以下表格完整继承原文档内容:
| 芯片平台 | USB IP | 对应 demo 仓库/SDK | CherryUSB 版本 |
|---|---|---|---|
| BouffaloLab(官方 SDK 支持) | FOTG210 | bouffalo_sdk | less than latest |
| HPMicro(官方 SDK 支持) | CHIPIDEA | hpm_sdk | less than latest |
| ESPressif(官方 SDK 支持) | DWC2 | cherryusb_esp32(ESP-Registry 组件) | less than latest |
| Phytium(官方 SDK 支持) | PUSB2/XHCI | phytium-free-rtos-sdk | equal to v1.4.0 |
| Essemi(官方 SDK 支持) | MUSB | cherryusb_es32 | less than latest |
| Artinchip(官方 SDK 支持) | AIC/EHCI/OHCI | luban-lite | less than latest |
| Kendryte K230(官方 SDK 支持) | DWC2 | Kendryte K230 RTOS 官方构建文档 | less than latest |
| SiFli(官方 SDK 支持) | MUSB | SiFli-SDK | less than latest |
| WCH | USBHS/USBFS/USBSS | cherryusb_wch、wch-support-cherryusb | greater than v1.6.1 |
| NXP MCX | CHIPIDEA/kinetis | cherryusb_mcx、RT-Thread bsp/nxp/mcx | less than latest |
| RP2040/RP2035(官方 SDK 即将支持) | RP2040 | pico-examples、pico-sdk | less than latest |
| ST | DWC2/FSDEV | cherryusb_stm32 | less than latest |
| Sophgo(官方 SDK 支持) | DWC2 | cvi_alios_open | equal to v0.7.0 |
| Bekencorp(官方 SDK 支持) | MUSB | bk_idk_ai | equal to v0.7.0 |
| Actionstech / Nuvoton / AllwinnerTech / ListenAI(官方 SDK 支持) | — | 未开源,需联系芯片厂商官方 | — |
表中仓库地址请以原文档 docs/zh/quick_start/demo.rst 中的链接为准,此处仅保留仓库名称。
从源码结构看,这套清单与 port/ 目录下的移植实现一一对应:DWC2 对应 port/dwc2/usb_dc_dwc2.c 与 port/dwc2/usb_hc_dwc2.c,FSDEV 对应 port/fsdev/usb_dc_fsdev.c,CHIPIDEA 对应 port/chipidea/usb_dc_chipidea.c,MUSB 对应 port/musb/usb_dc_musb.c 与 port/musb/usb_hc_musb.c,EHCI/OHCI 对应 port/ehci/ 与 port/ohci/,XHCI 对应 port/xhci/。如果你的芯片属于某类 USB IP,直接参考该目录下的 README 即可判断移植路径。
三、ESP32 系列:通过 ESP-Registry 组件安装 Demo
原文档指出,ESPressif 平台的 demo "默认采用组件库安装的形式"。仓库根目录的 idf_component.yml 即该组件的注册元信息:当前组件版本为 1.6.1,依赖idf: ">=4.4.1",支持的 targets 为 esp32s2、esp32s3、esp32p4、esp32s31——也就是说只有带 DWC2 IP 的 ESP32-S 系列/P4 才在这个组件的适配范围内。
原文档推荐 VSCode + ESP-IDF 环境,操作路径为:
Ctrl + Shift + P打开命令面板,选择ESP-IDF 欢迎界面,再选择Component manager;- 在组件管理器中搜索cherryusb并安装;
- 打开menuconfig,进入 CherryUSB 配置项,根据实际情况选择主机模式(
CHERRYUSB_HOST)或从机模式(CHERRYUSB_DEVICE)以及所需 class。
第 3 步对应仓库根目录的 Kconfig 文件:顶层开关为menuconfig CHERRYUSB,设备模式下还有CHERRYUSB_DEVICE及各 class 开关(如CHERRYUSB_DEVICE_CDC_ACM),Kconfig 中还内置了一组 demo template 开关(如cdc_acm_msc、winusbv1等),勾选后会直接编译 demo/ 目录下对应的 template 文件,方便"装上组件即可跑"。
组件内 Demo 工程长什么样
仓库自带两套 ESP32 验证工程,可直接对照阅读:
- 设备端 tests/espressif/device/main/main.c:直接 include
demo/cdc_acm_msc_template.c,在app_main中一行完成初始化——cdc_acm_msc_init(0, 0x60080000)(0x60080000为 ESP32-S3 的 DWC2 寄存器基址);其 sdkconfig.defaults 打开了CONFIG_CHERRYUSB、CONFIG_CHERRYUSB_DEVICE、CONFIG_CHERRYUSB_DEVICE_CDC_ACM/HID/MSC。 - 主机端 tests/espressif/host/main/main.c:include
demo/usb_host.c(内置 serial/HID/MSD 等 class 测试),初始化调用为usbh_initialize(0, 0x60080000, NULL),第三个参数event_handler可缺省为 NULL。
cdc_acm_msc_init的内部实现见 demo/cdc_acm_msc_template.c:先usbd_desc_register()注册描述符,再依次usbd_add_interface()/usbd_add_endpoint()挂接 CDC-ACM 与 MSC 接口,最后调用usbd_initialize(busid, reg_base, usbd_event_handler)。这正是后文"移植要点"中最后一步的标准形态。
四、STM32 系列:默认 Demo 工程与 Cache 处理
4.1 默认提供的 Demo 工程
原文档说明,ST 平台的默认 demo 涵盖F1/F4/H7,具体配置为:
- F103:使用 FSDEV IP;
- F429:主从共用 USB1(引脚 PB14/PB15),默认从机未开启 DMA 模式;
- H7:设备使用 USB0(引脚 PA11/PA12,未开 DMA);主机使用 USB1(引脚 PB14/PB15),需要做 nocache 处理。
demo 工程目录下提供stm32xxx.ioc文件,用 STM32CubeMX 双击打开、点击Generate Code即可生成工程。原文档特别加了一条 caution:
生成代码后,请使用
git reset将被覆盖的main.c和stm32xxx_it.c撤回,禁止被 CubeMX 覆盖。
F1/F4/H7 之间的差异可归纳为三点(原文档原话整理):
- USB IP 区别:F1 使用 FSDEV,F4/H7 使用 DWC2;
- DWC2 端口区别:USB0(PA11/PA12)与 USB1(PB14/PB15)。其中USB1 默认全速,可以外接 PHY 形成高速主机,并且带 DMA 功能;
- Cache 区别:F4 无 cache,H7 有 cache。
4.2 带 Cache 芯片(F7/H7)的 Nocache RAM 配置
对 STM32F7/H7 这类带 cache 的芯片,原文档给出的做法是把 USB 使用的 RAM 定位到 nocache 区域,代码示例为:
cpu_mpu_config(0, MPU_Normal_NonCache, 0x24070000, MPU_REGION_SIZE_64KB);对应的 Keil SCT 链接脚本修改:
LR_IROM1 0x08000000 0x00200000 { ; load region size_region ER_IROM1 0x08000000 0x00200000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) .ANY (+XO) } RW_IRAM2 0x24000000 0x00070000 { ; RW data .ANY (+RW +ZI) } USB_NOCACHERAM 0x24070000 0x00010000 { ; RW data *(.noncacheable) } }这两段配置的原理与仓库文档《芯片通用移植指南》的 cache 章节(docs/zh/quick_start/transplant.rst 中usb_cache锚点)完全一致:协议栈与 port 层不会对 cache 区 RAM 做 clean/invalidate,因此需要用USB_NOCACHE_RAM_SECTION宏(在 cherryusb_config_template.h 中默认定义为__attribute__((section(".noncacheable"))))把关键变量放进.noncacheable段,再配合 MPU 属性保证该物理区域真的非缓存——光改链接脚本不够,必须同时配置 MPU。上面cpu_mpu_config(0, MPU_Normal_NonCache, 0x24070000, 64KB)与 SCT 中USB_NOCACHERAM 0x24070000地址一致,正是"链接脚本段地址 + MPU 属性"双管齐下的示范。
在 STM32 glue 层也能看到 cache 的配套实现:port/dwc2/usb_glue_st.c 末尾在CONFIG_USB_DCACHE_ENABLE宏下提供了usb_dcache_clean/usb_dcache_invalidate/usb_dcache_flush三个包装函数(底层调用SCB_CleanDCache_by_Addr等 CMSIS 接口),供带 cache 且走 DMA 的路径使用。
五、USB Device 移植要点(以 STM32 为例)
以下 10 步完整继承原文档的 USB Device 移植流程,并在关键步骤补充源码依据。
- 使用 STM32CubeMX 创建工程,配置基本 RCC 和 UART(作为 log 输出使用)。
- 选择 USB IP:FSDEV IP 勾选USB;DWC2 IP 勾选USB_OTG_FS或USB_OTG_HS。开启 USB 中断即可,"其他配置对我们没用,代码中不会使用任何 ST 的 USB 库"。
- 配置 USB 时钟为 48MHz。
- 选择编译器并生成代码:这里选择 Keil,设置好 stack 和 heap(原文档建议"如果使用 MSC 可以推荐设置大点"),点击Generate Code。
- 添加 CherryUSB 必需要源码:
usbd_core.c+ IP 对应的dwc2/usb_dc_dwc2.c或fsdev/usb_dc_fsdev.c,以及想使用的 class 驱动;还可以把 demo/ 目录下对应的 class template 加入工程方便直接测试。 - 补齐头文件路径(建议把 common/class/core/port 的头文件目录全部加入 include path)。
- 复制配置模板:拷贝 cherryusb_config_template.h 到
Core/Inc目录下,命名为usb_config.h。 - FSDEV 专属配置:如果使用 FSDEV IP(V1.5.0 起还需添加
fsdev/usb_glue_st.c),必须在usb_config.h中定义:
#define CONFIG_USBDEV_FSDEV_PMA_ACCESS 2从源码看这个宏并非可有可无:port/fsdev/usb_dc_fsdev.c 和 port/fsdev/usb_glue_st.c 中都有#error "please define CONFIG_USBDEV_FSDEV_PMA_ACCESS in usb_config.h"的编译期检查,且 glue 文件还会校验CONFIG_USBDEV_FSDEV_PMA_ACCESS != PMA_ACCESS时报错——该值取决于芯片寄存器头文件中PMA_ACCESS的定义,常见取 1 或 2,不同芯片可能不同(模板头文件中也注明 "maybe 1 or 2, many chips may have a difference")。
- 编译器设置:推荐使用AC6,勾选Microlib,并实现
printf(重定向到 UART)方便查看 log。 - 中断与初始化接线。原文档注明:从 V1.5.0 开始,以下两个老步骤不再需要手工处理,因为
fsdev/usb_glue_st.c、dwc2/usb_glue_st.c中已经实现:- 拷贝
xxx_msp.c中HAL_PCD_MspInit的内容到usb_dc_low_level_init函数(屏蔽 ST 生成的 USB 初始化); - 在中断函数中调用
USBD_IRQHandler并传入busid。
- 拷贝
在 port/dwc2/usb_glue_st.c 中可以看到这套胶水层是如何代劳的:
usb_dc_low_level_init()(HAL_PCD_MODULE_ENABLED宏下)把reg_base指向g_usbdev_bus[busid],然后直接调用HAL_PCD_MspInit——即把 CubeMX 生成的 Msp 初始化(时钟、GPIO、NVIC)纳入协议栈调用链,无需用户再拷贝;- 文件末尾的
OTG_FS_IRQHandler()/OTG_HS_IRQHandler()直接按寄存器基址区分是 USB0 还是 USB1(0x40040000为 USB_OTG_HS 基址),记录对应busid后调用USBD_IRQHandler(busid); - 对 STM32F722/723/730/732/733 还会额外调用
usb_hsphy_init(25000000)初始化内部 HS PHY(使能 LDO、配置 PLL、TUNE、等待 2ms)。
FSDEV 侧的 port/fsdev/usb_glue_st.c 同理:usb_dc_low_level_init()内调用HAL_PCD_MspInit,USB_IRQHandler/USB_LP_IRQHandler统一转发到USBD_IRQHandler(0)。
- 如果芯片带 cache,按 4.2 节修改链接脚本与 MPU(参考 transplant 文档的
usb_cache章节)。 - 调用 template 初始化:注册描述符并调用
usbd_initialize,填入busid和 USB IP 的reg base;busid从 0 开始,不能超过CONFIG_USBDEV_MAX_BUS。对应声明见 core/usbd_core.h:
int usbd_initialize(uint8_t busid, uintptr_t reg_base, usbd_event_handler_t event_handler);usbd_initialize内部第一步就是USB_ASSERT_MSG(busid < CONFIG_USBDEV_MAX_BUS, "bus overflow\r\n")(见 core/usbd_core.c),所以CONFIG_USBDEV_MAX_BUS的默认值(模板中为 1)决定了最多能注册几路 USB 控制器。
六、USB Host 移植要点(以 STM32 DWC2 为例)
原文档指出:host 驱动只支持带 DMA 的 HS port(引脚 PB14/PB15),FS port(PA11/PA12)不做支持(原文原话:"没有 DMA 你玩什么主机")。这一点与 port/dwc2/usb_glue_st.c 中param_pb14_pb15参数表设置了host_rx_fifo_size/host_nperio_tx_fifo_size/host_perio_tx_fifo_size等主机专用 FIFO,而param_pa11_pa12(F1/F4 等平台)没有主机 FIFO 配置的结构完全吻合。
移植步骤(前 6 步与 Device 相同,此处列差异部分):
- 添加源码:
usbh_core.c、usbh_hub.c、usb_hc_dwc2.c、usb_glue_st.c,以及osal目录下对应操作系统的适配层文件(osal/ 下有 FreeRTOS、RT-Thread、Zephyr、NuttX、LiteOS、ThreadX、IDF 等实现),加上想使用的 host class 驱动;可加入demo/usb_host.c方便直接测试(内置 cdc/hid/msc 等 host 侧演示,参考 demo/usb_host.c)。 - 编译器设置:同 Device,推荐 AC6 + Microlib + 自定义
printf。 - 复制配置模板:
cherryusb_config_template.h→Core/Inc/usb_config.h。主机相关的关键宏在模板中集中定义为:
#define CONFIG_USBHOST_MAX_RHPORTS 1 #define CONFIG_USBHOST_MAX_EXTHUBS 1 #define CONFIG_USBHOST_MAX_EHPORTS 4 #define CONFIG_USBHOST_MAX_INTERFACES 8 #define CONFIG_USBHOST_MAX_ENDPOINTS 4 #define CONFIG_USBHOST_MAX_SERIAL_CLASS 4 #define CONFIG_USBHOST_MAX_HID_CLASS 4 #define CONFIG_USBHOST_MAX_MSC_CLASS 2这些宏决定主机栈能同时枚举的 hub 端口、接口与各 class 实例上限,裁剪协议栈内存的主要抓手。
- 低层初始化与中断:原文档注明从 V1.5.0 起无需手工拷贝
HAL_HCD_MspInit内容,也无需自己写中断转发,glue 层已实现。对照 port/dwc2/usb_glue_st.c 的usb_hc_low_level_init()(HAL_HCD_MODULE_ENABLED宏下):按reg_base是否为0x40040000区分 USB1/USB0,登记g_usb_dwc2_irq[1] = USBH_IRQHandler,随后调用HAL_HCD_MspInit完成时钟/GPIO/NVIC 配置。 - 链接脚本修改(参考 transplant 文档
usbh_link_script章节):主机栈需要在链接脚本中保留一个 section 存放 class 描述信息,否则链接会报__usbh_class_info_start__/__usbh_class_info_end__未定义。Keil 无需修改;GCC 需在 ld 文件的 flash 段追加:
. = ALIGN(4); __usbh_class_info_start__ = .; KEEP(*(.usbh_class_info)) __usbh_class_info_end__ = .;Segger Embedded Studio 则用define block cherryusb_usbh_class_info { section .usbh_class_info };等方式定义导出符号。 6.Cache 处理:带 cache 芯片参考usb_cache章节(同 Device 端做法)。 7.初始化并启动:调用usbh_initialize,填入busid、USB IP 的reg base和event_handler(可缺省为 NULL);busid从 0 开始,不能超过CONFIG_USBHOST_MAX_BUS。声明见 core/usbh_core.h:
int usbh_initialize(uint8_t busid, uintptr_t reg_base, usbh_event_handler_t event_handler);实现(core/usbh_core.c)中先USB_ASSERT_MSG(busid < CONFIG_USBHOST_MAX_BUS, "bus overflow\r\n"),event_handler为 NULL 时回落到内部的dummy_event_handler,之后创建 PSC 线程(模板中默认CONFIG_USBHOST_PSC_PRIO 0、CONFIG_USBHOST_PSC_STACKSIZE 2048)完成主机栈启动,即原文档最后一步"启动线程"。ESP32 主机 demo 中的usbh_initialize(0, 0x60080000, NULL)就是最小完整调用。
七、配置模板速查与延伸阅读
无论走哪条平台路线,usb_config.h(由 cherryusb_config_template.h 复制而来)都是核心入口。与本文 demo 路线直接相关的宏归纳如下:
| 宏 | 默认/取值 | 作用 |
|---|---|---|
CONFIG_USB_PRINTF | 默认printf(RT-Thread 下为rt_kprintf) | 协议栈日志输出重定向 |
CONFIG_USB_DBG_LEVEL | 默认USB_DBG_INFO | 日志等级 |
CONFIG_USB_ALIGN_SIZE | 4(开 dcache 时 32/64) | DMA/dcache 路径下的数据对齐 |
USB_NOCACHE_RAM_SECTION | .noncacheablesection | 带 cache 芯片的变量放置段 |
CONFIG_USBDEV_MAX_BUS/CONFIG_USBHOST_MAX_BUS | 默认 1 | 设备/主机控制器数量上限,busid不可超出 |
CONFIG_USBDEV_FSDEV_PMA_ACCESS | 1 或 2(芯片相关) | FSDEV IP 的 PMA 访问方式,未定义则编译报错 |
CONFIG_USB_DWC2_DMA_ENABLE | 注释(关闭) | DWC2 设备 DMA 模式;STM32 上仅 PB14/PB15 支持 |
CONFIG_USB_HS | 注释(关闭) | 高速模式;STM32 上仅 PB14/PB15 可 HS |
CONFIG_USBHOST_MAX_EHPORTS等 | 见上文 | 主机枚举资源裁剪 |
延伸阅读(均为仓库内相对路径):
- 通用移植全流程与链接脚本/cache 细节:docs/zh/quick_start/transplant.rst
- RT-Thread 环境下的快速上手:docs/zh/quick_start/rtthread.rst
- 各 USB IP 移植入口:port/(每个 IP 目录含 README)
- 可直接复制的设备/主机 class demo:demo/(如 demo/cdc_acm_msc_template.c、demo/usb_host.c)
- ESP32 验证工程:tests/espressif/
- 各平台实际接入示例:platform/(rtthread、zephyr、nuttx、lvgl、lwip、fatfs 等适配层)
八、小结
按原文档"先跑 demo"的思路落地,验证 CherryUSB 的标准动作是:先选一条有官方 SDK 支持的平台路线(ESP32 走组件管理器、STM32 走 CubeMX +.ioc+ glue 文件),用 demo 自带的 template 完成一次最小枚举/读写,再回到 core/、port/ 源码理解usbd_initialize/usbh_initialize的初始化链。V1.5.0 起usb_glue_*.c已经接管了 Msp 初始化和中断转发,移植者真正需要关心的只剩下:usb_config.h里的 IP 相关宏(如CONFIG_USBDEV_FSDEV_PMA_ACCESS)、带 cache 芯片的 nocache 段与 MPU 配置、以及主机模式的 class info 链接脚本——这三点也是原文档中专门标注 caution 与 note 的地方,跑 demo 时逐条对照验证即可。
- 嵌入式
- 驱动开发
- 物联网
【免费下载链接】CherryUSB
CherryUSB is a tiny and beautiful, high performance and portable USB host and device stack for embedded system with USB IP
相关推荐
基于现有 Demo 快速验证与移植 CherryUSB:从跑通第一个 USB 例程开始
基于现有 Demo 快速验证与移植 CherryUSB:从跑通第一个 USB 例程开始 CherryUSB 是一套小巧、高性能、可移植的嵌入式 USB 主机/设
嵌入式驱动开发物联网RT-Thread 与 CherryUSB 在 NRF5x 平台的 USB 设备控制器移植指南
RT Thread 与 CherryUSB 在 NRF5x 平台的 USB 设备控制器移植指南 本指南以 RT Thread 仓库中 CherryUSB 的 N
操作系统嵌入式物联网嵌入式OSRTOSRT-Thread CherryUSB 全速 USB 设备控制器(FSDEV)驱动移植指南
RT Thread CherryUSB 全速 USB 设备控制器(FSDEV)驱动移植指南 RT Thread 集成的 CherryUSB 协议栈为开发者提供了
操作系统嵌入式物联网嵌入式OSRTOS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考