GD32F4上使用Cube HAL库实现USB虚拟串口调试详解
之前在项目中使用ST的芯片,为快速实现驱动,都是使用的stm32 cube直接创建项目工程,所以工程上都是基于HAL库开发的。最近在调试gd32f4xx芯片调试usb驱动,发现通过cube生成的工程无法在GD32上识别到USB设备,上电后出现:"设备描述符请求失败"的问题,所以,只能通过gd32的usb库进行移植,下面是记录基于stm32的HAL库工程去移植GD32提供的usb库过程:
第一部分:相关环境
第二部分:实现流程
1)打开cube,选择芯片型号:

选择调试模式,时钟源,配置好各总线时钟:



配置USB为从设备,因为板子硬件使用的是USB-HS口,所以在选择为USB-OTG_HS为从设备:
如果有使用到VBUS脚,就直接勾选:
在USB_DEVICE下选择使用虚拟串口:
同时,在选择对应的USB设备后,时钟配置界面也会相应的生效,需要进行调整,确保48MHZ时钟源,如下:
最后,在项目管理界面中填写目录路径,目录名称,选择打开工具,填写对应的堆栈大小(这里因用到USB库,需要调大):
选择需要添加库文件,是否分开源文件和头文件,再点击生成代码,完成编译即可。
从GD官网上下载标定固件库:
https://www.gd32mcu.com/cn/download?kw=GD32F4xx_Firmware&lan=cn
2)把USB库有ST的替换成GD32的
把工程中根据ST相关的USB库删除(包括工程中的源文件及头文件目录),同时把GD32跟USB相关的文件直接加入到工程中:
加进来后,肯定会报错误,包括工程中的睡眠模式相关函数pmu_to_deepsleepmode及微秒延时函数usb_udelay/usb_mdelay函数:
pmu_to_deepsleepmode是根usb进入休眠相关,可以直接注释掉。
usb_udelay:是us延时函数,直接自定义下,在函数里面加入几个__NOP();即可
usb_mdelay;是ms延时函数,直接用HAL_Delay代替
同时,usb_conf.h文件中也会报错,错误地方直接用下面方式代替:
其中,gd32f4xx_compat.h文件需要自定义,里面内容如下:
#ifndef GD32F4XX_COMPAT_H
#define GD32F4XX_COMPAT_H
/* bit operations */
#define REG32(addr) (*(volatile uint32_t *)(uint32_t)(addr))
#define REG16(addr) (*(volatile uint16_t *)(uint32_t)(addr))
#define REG8(addr) (*(volatile uint8_t *)(uint32_t)(addr))
#define BIT(x) ((uint32_t)((uint32_t)0x01U<<(x)))
#define BITS(start, end) ((0xFFFFFFFFUL << (start)) & (0xFFFFFFFFUL >> (31U - (uint32_t)(end))))
#define GET_BITS(regval, start, end) (((regval) & BITS((start),(end))) >> (start))
#endif
对与入口main.c文件中,按如下修改:
添加头文件:
#include "stm32f4xx_hal_pcd.h"
#include "stm32f4xx_ll_usb.h"
#include "cdc_acm_core.h"
定义关于USB的全局变量:
PCD_HandleTypeDef hpcd_USB_OTG_HS;
usb_core_driver cdc_acm;
定义初始化USB口引脚的函数,调用GD提供的usb初始化协议库:
void HAL_PCD_MspInit(PCD_HandleTypeDef* pcdHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(pcdHandle->Instance==USB_OTG_HS)
{
/* USER CODE BEGIN USB_OTG_HS_MspInit 0 */
/* USER CODE END USB_OTG_HS_MspInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USB_OTG_HS GPIO Configuration
PB13 ------> USB_OTG_HS_VBUS
PB14 ------> USB_OTG_HS_DM
PB15 ------> USB_OTG_HS_DP
*/
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_14|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF12_OTG_HS_FS;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_USB_OTG_HS_CLK_ENABLE();
/* Peripheral interrupt init */
HAL_NVIC_SetPriority(OTG_HS_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(OTG_HS_IRQn);
/* USER CODE BEGIN USB_OTG_HS_MspInit 1 */
/* USER CODE END USB_OTG_HS_MspInit 1 */
}
}
void HAL_PCD_MspDeInit(PCD_HandleTypeDef* pcdHandle)
{
if(pcdHandle->Instance==USB_OTG_HS)
{
/* USER CODE BEGIN USB_OTG_HS_MspDeInit 0 */
/* USER CODE END USB_OTG_HS_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USB_OTG_HS_CLK_DISABLE();
/**USB_OTG_HS GPIO Configuration
PB13 ------> USB_OTG_HS_VBUS
PB14 ------> USB_OTG_HS_DM
PB15 ------> USB_OTG_HS_DP
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15);
/* Peripheral interrupt Deinit*/
HAL_NVIC_DisableIRQ(OTG_HS_IRQn);
/* USER CODE BEGIN USB_OTG_HS_MspDeInit 1 */
/* USER CODE END USB_OTG_HS_MspDeInit 1 */
}
}
static void MX_USB_HS_Init(void)
{
hpcd_USB_OTG_HS.Instance = USB_OTG_HS;
hpcd_USB_OTG_HS.Init.dev_endpoints = 6;
hpcd_USB_OTG_HS.Init.speed = PCD_SPEED_FULL;
hpcd_USB_OTG_HS.Init.dma_enable = DISABLE;
hpcd_USB_OTG_HS.Init.phy_itface = USB_OTG_EMBEDDED_PHY;
hpcd_USB_OTG_HS.Init.Sof_enable = DISABLE;
hpcd_USB_OTG_HS.Init.low_power_enable = DISABLE;
hpcd_USB_OTG_HS.Init.lpm_enable = DISABLE;
hpcd_USB_OTG_HS.Init.vbus_sensing_enable = ENABLE;
hpcd_USB_OTG_HS.Init.use_dedicated_ep1 = DISABLE;
hpcd_USB_OTG_HS.Init.use_external_vbus = DISABLE;
if (HAL_PCD_Init(&hpcd_USB_OTG_HS) != HAL_OK)
{
Error_Handler( );
}
}
为实现USB模拟虚拟串口进行收发操作,在while循环中添加代码:
if (USBD_CONFIGURED == cdc_acm.dev.cur_status)
{
if (0U == cdc_acm_check_ready(&cdc_acm)) {
cdc_acm_data_receive(&cdc_acm);
} else {
cdc_acm_data_send(&cdc_acm);
}
}
记录在USB_HS中断函数中添加GD相关的中断处理函数:
以上步骤都完成后,重新进行编译成功后,烧录到硬件上查看电脑上的虚拟串口,如下图:
打开串口,进行收发操作,如图:
到此,完成所有文件的替换,成功实现HAL库实现USB虚拟串口调试。
作者:chensufei24