379|1

403

帖子

0

TA的资源

一粒金砂(高级)

【兆易GD32H759I-EVAL】--12.USB虚拟串口 [复制链接]

本帖最后由 dirty 于 2024-6-12 09:13 编辑

      开发板MCU集成有两个USBFS/HS接口,可用作USB设备/USB主机/OTG设备。本篇讲述USBHS1 被 USB 主机枚举为一个 USB 虚拟串口,可通过USB口回传数据。

一.硬件原理与准备

      开发板硬件USB原理图如下图1。这里使用到CN3 USB_HS1接口,跳线帽JP65、JP70打到USB引脚端。从官网可下载虚拟串口驱动并安装如下图2.

2_USB原理图.jpg
图1:USB原理
1_USB驱动安装_1.jpg
图2:USB虚拟串口驱动

 

二.代码准备

      虚拟串口 CDC 例程遵循了 USB 通信类相关子协议,可以将 USB 虚拟成 COM 口,可以像普通的串口一样进行操作。官方提供了USBFS固件库实现 USB 的数据通信。USBFS 固件库分为应用层和驱动层,用户层用户可以修改,驱动层包括 USB 主机或设备驱动和 USB 底层驱动。

1.关于CDC库。可以参阅下官方“GD32 USBFS&USBHS 固件库使用指南”文档,做更深入全面了解。

      在GD32H7xx_Firmware_Library\GD32H7xx_usbhs_library\device\class\cdc下是CDC设备功能代码。包含了USBD_VID 和USBD_PID的定义、CDC 相关的描述符项。

      CDC 本身包含两个接口,一个命令接口、一个数据接口,命令接口相关描述符如下:

3_CDC命令接口描述符.jpg
图3:CDC命令接口描述符

      CDC 设备类接口函数如下,这里主要关注后三个

4_CDC 设备类接口函数.jpg
图4:CDC 设备类接口函数

      CDC 设备类请求类如下:

5_CDC 设备类请求.jpg
图5:CDC 设备类请求

      CDC 用户接口函数如下,这个是我们应用需要的。

6_CDC 用户接口函数.jpg
图6:CDC 用户接口函数

2.打开CDC_ACM工程,在Options里配置宏USE_USB_HS使用高速USB;配置USE_USBHS1,以使用USB_HS1。

7_USBHS1宏使能.jpg
图7:USB宏定义

3.配置USB时钟

void usb_rcu_config(void)
{
    pmu_usb_regulator_enable();
    pmu_usb_voltage_detector_enable();
    while (pmu_flag_get(PMU_FLAG_USB33RF) != SET) {
    }

#ifdef USE_USB_FS

#ifndef USE_IRC48M

#ifdef USE_USBHS0
    rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_PLL0R);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
    rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_PLL0R);
#endif /* USE_USBHS1 */

#else
    /* enable IRC48M clock */
    rcu_osci_on(RCU_IRC48M);

    /* wait till IRC48M is ready */
    while (SUCCESS != rcu_osci_stab_wait(RCU_IRC48M)) {
    }

#ifdef USE_USBHS0
    rcu_usb48m_clock_config(IDX_USBHS0, RCU_USB48MSRC_IRC48M);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
    rcu_usb48m_clock_config(IDX_USBHS1, RCU_USB48MSRC_IRC48M);
#endif /* USE_USBHS1 */

#endif /* USE_IRC48M */

#endif /* USE_USB_FS */

#ifdef USE_USBHS0
    rcu_periph_clock_enable(RCU_USBHS0);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
    rcu_periph_clock_enable(RCU_USBHS1);
#endif /* USE_USBHS1 */

#ifdef USE_ULPI_PHY
    rcu_periph_clock_enable(RCU_ULPI);
#endif /* USE_ULPI_PHY */
}

4.配置USB delay定时器。这里使用到Timer2,在gd32h7xx_it.c里有其定时中断函数TIMER2_IRQHandler。

void usb_timer_init (void)
{
    /* configure the priority group to 2 bits */
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

    /* enable the TIM2 global interrupt */
    nvic_irq_enable((uint8_t)TIMER2_IRQn, 1U, 0U);

    rcu_periph_clock_enable(RCU_TIMER2);
}

5.初始化cdc参数。这里使用USBHS1 usb外设,选用高速USB_SPEED_HIGH,通过结构体指针,初始化后将cdc_acm赋值带出。

void usb_para_init(usb_core_driver *udev, uint32_t usb_periph, uint32_t usb_speed)
{
    usb_core_basic *usb_basic = &udev->bp;

    /* configure USB default transfer mode as FIFO mode */
    usb_basic->transfer_mode = (uint8_t)USB_USE_FIFO;

    /* USB default speed is full-speed */
    usb_basic->core_speed = (uint8_t)USB_SPEED_FULL;

    /* USB basic register address setting */
    switch(usb_periph){
    case USBHS0:
        usb_basic->base_reg = (uint32_t)USBHS0_REG_BASE;
        break;
    case USBHS1:
        usb_basic->base_reg = (uint32_t)USBHS1_REG_BASE;
        break;
    default:
        break;
    }

    /* set the host channel numbers */
    usb_basic->num_pipe = USBHS_MAX_CHANNEL_COUNT;

    /* set the device endpoint numbers */
    usb_basic->num_ep = USBHS_MAX_EP_COUNT;

    if (USB_SPEED_HIGH == usb_speed) {
#ifdef USB_EXTERNAL_ULPI_PHY_ENABLED
        usb_basic->phy_itf = USB_ULPI_PHY_EXTERNAL;
#endif /* USB_EXTERNAL_ULPI_PHY_ENABLED */

#ifdef USB_EMBEDDED_HS_PHY_ENABLED
        usb_basic->phy_itf = USB_EMBEDDED_PHY_HS;
#endif /* USB_EMBEDDED_HS_PHY_ENABLED */
    } else if (USB_SPEED_FULL == usb_speed) {
#ifdef USB_EMBEDDED_FS_PHY_ENABLED
        usb_basic->phy_itf = USB_EMBEDDED_PHY_FS;
#endif /* USB_EMBEDDED_FS_PHY_ENABLED */
    } else {
        /* no operation */
    }

#ifdef USB_INTERNAL_DMA_ENABLED
    usb_basic->transfer_mode = USB_USE_DMA;
#endif /* USB_INTERNAL_DMA_ENABLED */

    usb_basic->sof_enable = (uint8_t)USB_SOF_OUTPUT;
    usb_basic->low_power = (uint8_t)USB_LOW_POWER;

#if (1U == LPM_ENABLED)
    usb_basic->lpm_enable = 1U;
#endif /* LPM_ENABLED */
}

6.初始化USB设备模式,并加载驱动。这里使用到了前面初始化的cdc_acm,初始化usb描述符和USB内核。这里面引用到了CDC库。

void usbd_init(usb_core_driver *udev, usb_desc *desc, usb_class_core *class_core)
{
    udev->dev.desc = desc;

    /* class callbacks */
    udev->dev.class_core = class_core;

    /* create serial string */
    serial_string_get(udev->dev.desc->strings[STR_IDX_SERIAL]);

    /* configure USB capabilities */
    (void)usb_basic_init(&udev->bp, &udev->regs);

    /* initializes the USB core*/
    (void)usb_core_init(udev->bp, &udev->regs);

    /* set device disconnect */
    usbd_disconnect(udev);

    /* initializes device mode */
    (void)usb_devcore_init(udev);

    /* set device connect */
    usbd_connect(udev);

    udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
}

7.配置USB中断。宏定义使用USE_USBHS1。在gd32h7xx_it.c里有其中断函数USBHS1_IRQHandler,USBHS1_WKUP_IRQHandler,USBHS1_EP1_OUT_IRQHandler。

/*!
    \brief      configure USB interrupt
    \param[in]  none
    \param[out] none
    \retval     none
*/
void usb_intr_config(void)
{
    nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

#ifdef USE_USBHS0
    nvic_irq_enable((uint8_t)USBHS0_IRQn, 3U, 0U);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
    nvic_irq_enable((uint8_t)USBHS1_IRQn, 3U, 0U);
#endif /* USE_USBHS0 */

    /* enable the power module clock */
    rcu_periph_clock_enable(RCU_PMU);

#ifdef USE_USBHS0
    /* USB wakeup EXTI line configuration */
    exti_interrupt_flag_clear(EXTI_31);
    exti_init(EXTI_31, EXTI_INTERRUPT, EXTI_TRIG_RISING);
    exti_interrupt_enable(EXTI_31);

    nvic_irq_enable((uint8_t)USBHS0_WKUP_IRQn, 1U, 0U);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
    /* USB wakeup EXTI line configuration */
    exti_interrupt_flag_clear(EXTI_32);
    exti_init(EXTI_32, EXTI_INTERRUPT, EXTI_TRIG_RISING);
    exti_interrupt_enable(EXTI_32);

    nvic_irq_enable((uint8_t)USBHS1_WKUP_IRQn, 1U, 0U);
#endif /* USE_USBHS1 */

#ifdef USB_DEDICATED_EP1_ENABLED

#ifdef USE_USBHS0
    nvic_irq_enable((uint8_t)USBHS0_EP1_OUT_IRQn, 1U, 0U);
    nvic_irq_enable((uint8_t)USBHS0_EP1_IN_IRQn, 1U, 0U);
#endif /* USE_USBHS0 */

#ifdef USE_USBHS1
    nvic_irq_enable((uint8_t)USBHS1_EP1_OUT_IRQn, 1U, 0U);
    nvic_irq_enable((uint8_t)USBHS1_EP1_IN_IRQn, 1U, 0U);
#endif /* USE_USBHS1 */

#endif /* USB_DEDICATED_EP1_ENABLED */
}

8.main函数实现USB虚拟串口接收完全后回显。

int main(void)
{
/*
//USB HS1 CDC初始化
......
*/
 while (1) 
	{
        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);
            }
        }
    }

}

 

三.测验

      编译烧录后,复位运行,可以在设备管理器找到虚拟串口。用串口工具打开,发送一串字符,在接收区会接收到一串相同的字符。如下图

8_USB虚拟串口测试.jpg
图8:USB虚拟串口测试

 

 

      至此,实现USB 虚拟串口功能。

 

最新回复

USB虚拟串口可能增加系统的功耗 这个功耗可以测试一下     详情 回复 发表于 2024-6-14 07:36

回复
举报

6122

帖子

0

TA的资源

五彩晶圆(高级)

USB虚拟串口可能增加系统的功耗

这个功耗可以测试一下

 


回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表