GD32F4上使用Cube HAL库实现USB虚拟串口调试详解

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

  • 硬件芯片:GD32F425xx
  • 工具:STM32 Cube
  • 第二部分:实现流程

  • 先通过stm32 cube生成一份基础工程,按以下步骤:
    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

    物联沃分享整理
    物联沃-IOTWORD物联网 » GD32F4上使用Cube HAL库实现USB虚拟串口调试详解

    发表回复