STM32H5 的 USBD Classic 驱动 CDC 移植核心是 “复用 HID 工程框架 + 替换 CDC 相关文件 + 解决接口注册与驱动适配”,可避开 USBX 的 OS 依赖,实现裸机环境下的虚拟串口通信。移植关键在于补全缺失的驱动文件、屏蔽 USB PD 干扰、正确配置 PMA 与描述符、注册 CDC 接口,按步骤操作即可解决枚举失败、驱动安装报错、HardFault 等常见问题。
1. 核心概述
1.1 移植背景与目标
- 痛点:STM32CubeMX 6.9.1 对 STM32H5 仅默认支持 USBX(依赖 Threadx OS),缺乏裸机 Classic USB CDC 例程;
- 资源基础:STM32H5 的 Classic USB HID 例程(GitHub 开源)可作为移植框架,需替换为 CDC 类相关文件;
- 移植目标:实现裸机 Classic USB CDC 功能,设备枚举为虚拟串口,支持双向通信,兼容 Windows 默认驱动。
1.2 必备资源清单
- 基础工程:GitHub 仓库
<a class="article-link" target="_blank" href="https://www.eefocus.com/e/1605630.html">stm32</a>h5-classic-coremw-apps(含 HID 例程);
- 依赖库:STM32CubeH5 HAL 库(含 Drivers 文件夹)、
stm32_mw_<a class="article-link" target="_blank" href="https://www.eefocus.com/tag/usb/">usb</a>_device(USB Device Library);
- 参考例程:STM32U5 的 Classic USB CDC 例程(用于替换描述符与接口文件)。
2. 移植前准备
- 下载并解压
stm32h5-classic-coremw-apps,补全缺失文件:
- 拷贝 STM32CubeH5 的
Drivers文件夹(含 BSP、CMSIS、HAL_Driver)到工程目录;
- 下载
stm32_mw_usb_device,拷贝Core和Class/CDC文件夹到Middlewares/ST/STM32_USB_Device_Library;
- 编译原始 HID 工程,验证基础环境:确保 HID 设备能正常枚举(鼠标功能可用),排除硬件与 HAL 库问题。
3. 详细移植步骤(按优先级排序)
3.1 屏蔽 USB PD 功能(避免干扰)
USB PD 与 Classic USB 无耦合,仅因 Type-C 接口协议要求存在,裸机移植需移除:
-
删除工程中STM32_USBPD_Library文件夹;
-
屏蔽main.c和usb_device.c中所有 USB PD 相关代码,简化主函数:
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_USB_Device_Init();
while(1) {}
}
-
在MX_USB_Device_Init()中添加USBD_Start(原由 PD 功能调用,移除后手动添加):
void MX_USB_Device_Init(void)
{
// 初始化USB设备库、添加类
if (USBD_Init(&hUsbDeviceFS, &CDC_Desc) != USBD_OK)
Error_Handler();
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK)
Error_Handler();
// 手动添加USBD启动(原由USB PD调用)
HAL_PWREx_EnableVddUSB();
USBD_Start(&hUsbDeviceFS);
}
3.2 替换 CDC 相关文件
- 移除 HID 相关文件:
usbd_hid.c及对应头文件;
- 添加 CDC 核心文件:从
stm32_mw_usb_device/Class/CDC/Src拷贝usbd_cdc.c和usbd_cdc.h到工程;
- 添加接口模板文件:拷贝
usbd_cdc_if_template.c和usbd_cdc_if_template.h到工程(提供 CDC 收发回调接口)。
3.3 配置 PMA(数据包存储区)
CDC 与 HID 的端点资源不同,需修改usbd_conf.c的 PMA 配置(替换原 HID 的 PMA 设置):
/* USER CODE BEGIN EndPoint_Configuration */
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, 0x00, PCD_SNG_BUF, 0x20); // 控制端点IN
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, 0x80, PCD_SNG_BUF, 0x40); // 控制端点OUT
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CDC_IN_EP, PCD_SNG_BUF, 0x60); // CDC IN端点
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CDC_OUT_EP, PCD_SNG_BUF, 0x80); // CDC OUT端点
HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CDC_CMD_EP, PCD_SNG_BUF, 0x100); // CDC命令端点
/* USER CODE END EndPoint_Configuration */
3.4 替换 CDC 描述符
- 从 STM32U5 的 CDC 例程中拷贝
usbd_desc.c和usbd_desc.h,替换工程中原 HID 的描述符文件;
- 修改
usb_device.c中描述符引用:将&HID_Desc改为&CDC_Desc(与新描述符结构体名称一致)。
3.5 注册 CDC 接口并初始化
-
在MX_USB_Device_Init()中添加 CDC 接口注册(关键步骤,否则会触发 HardFault):
if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_CDC_Template_fops) != USBD_OK)
Error_Handler();
-
在usbd_cdc_if_template.c的TEMPLATE_Init()中添加缓冲区初始化:
static int8_t TEMPLATE_Init(void)
{
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBuffer, 0);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBuffer);
return 0;
}
3.6 解决驱动安装报错(Code 10)
- 调整工程
icf文件(IAR)或ld文件(GCC)的堆大小,建议设置为0x1000(避免内存不足);
- 确保
usbd_cdc_if_template.c中的回调函数(TEMPLATE_Init、TEMPLATE_Receive)正确实现,无语法错误。
4. 移植验证:CDC 通信测试
- 编译工程并下载到 STM32H5 开发板(如 NUCLEO-H563Z);
- 连接 USB Type-C 线到 PC,设备管理器应识别 “USB Serial Device (COMx)”,无黄色感叹号;
- 使用串口助手测试:
- 发送数据(如 “666666”),设备应回显相同数据;
- 测试不同长度数据(≤64 字节),验证通信稳定性。
5. 避坑关键要点
- 驱动文件缺失:确保
Drivers和STM32_USB_Device_Library文件完整,否则编译报错 “missing rule to make file”;
- USB PD 干扰:未屏蔽 PD 功能会导致
USBD_Start未调用,设备无法枚举;
- PMA 配置错误:CDC 端点地址与 PMA 缓冲区地址不匹配,会导致数据收发失败;
- 接口未注册:遗漏
USBD_CDC_RegisterInterface,会触发 HardFault;
- 堆大小不足:默认堆太小会导致驱动安装失败(Code 10),需扩大堆空间;
- 描述符不匹配:未替换 CDC 描述符,会导致枚举为未知设备。
STM32H5 USBD Classic 驱动 CDC 移植的核心是 “复用 HID 框架 + 替换 CDC 组件 + 解决接口与资源适配”,关键步骤包括补全驱动文件、屏蔽 PD 干扰、配置 PMA、替换描述符、注册接口。按流程操作可快速实现裸机 CDC 功能,满足虚拟串口通信需求,无需依赖 USBX 操作系统。 |