Mini-F0160实现USB转3路虚拟串口

描述

本节课程主要讲述如何通过 Mini-F0160 开发板实现 USB 转三路虚拟串口功能。

开发板 Mini-F0163
开发环境 MDK-Keil

Mini-F0160 开发板搭载 MM32F0160 ,产品内嵌 1 个 USB 控制器,内置 USB PHY,兼容 USB 2.0 全速规范,提供最高 12 Mbps 数据速率,支持设备模式,USB 控制器提供了最高 8 个双向端点。

本文源程序下载地址:

https://www.mindmotion.com.cn/download1.aspx?itemid=3816&typeid=5

 什么是 CDC 设备

CDC 类是 USB 通信设备类 (Communication Device Class)的简称。由 USB 组织定义的专门给各种通信设备使用的 USB 子类。

通常,CDC类由两个接口子类组成:

通信接口类(Communication Interface Class)

主要用于主机对设备进行管理和控制,它包含一个控制类型的端点和一个可选的中断类型端点。

该控制类型端点 0 一般用作请求,可以用于配置 USB 设备枚举虚拟串口的波特率、数据类型的设置,比如数据长度、停止位等。在虚拟串口应用中,该操作并不一定需要具体实现。因为主机与设备在物理上通过 USB 总线进行通信,与串口并没有关系,在虚拟化过程中,起决定性作用的是串口驱动,该驱动将每一条具体的虚拟串口操作对应到实际上的USB操作。同时,主机与设备之间的 USB 通信速率依然是标准的 USB2.0 Full-Speed(12Mbps)速度,并不受所谓的串口波特率影响,实际的速率取决于总线的实际使用率、驱动访问 USB 外设的有效速率(两边)以及外部环境对通信本身造成的干扰率等因素。

该中断类型端点可以用于异步事件通知,设备端可以通过该端点向主机发送内部时间等,如串口状态变化事件等。篇幅受限,本文不进行实现。

数据接口类(Data Interface Class)

主要用于主机和设备之间进行数据传输,包含输入(IN)端点和输出(OUT)端点。

输入(IN)端点:

用于从设备向主机发送数据。

输出(OUT)端点:

用于主机向从设备发送数据。

 多路虚拟串口的具体实现

多路虚拟串口功能可以通过组合设备(Composite Device)进行实现。组合设备是指具有多个接口,且接口间相互独立的USB设备。一个USB组合设备只有一个设备地址。在开发过程中,可以将不同的功能与不同的接口对应,来开发多功能的USB设备,描述符层次结构更清晰,出错容易排查。

设备描述符

设备描述符(Device Descriptor)是在设备连接时主机读取的第一个描述符,说明了 USB 设备的通用信息,提供关于设备、设备的配置以及任何设备所归属类的信息。主机在取得设备描述符后,就可以继续去获取设备的配置、接口和端点描述符等信息。

USB 设备只有一个设备描述符。在设备描述符中,可以使用 bDeviceClass = 0x00,  bDeviceSubClass = 0x00, dDeviceProtocol = 0x00 表示此类信息在接口描述符内给出;也可以使用【0xEF,0x02,0x01】表示当前为组合设备。下图为主机请求设备描述符,设备返回设备描述符报文:

串口串口

配置描述符

配置描述符(Configuration Descriptor)说明了一个特定配置的相关信息。当主机请求配置描述符时,返回的是所有相关的接口和端点描述符。

一个USB设备有一个或多个配置描述符。配置描述符描述了配置所提供的接口数量。每个接口可以独立操作。每种配置有一个或多个接口,而且每个接口有零个或多个端点。在一个配置中,接口不会共享一个端点,除非端点被相同接口的备用设置使用。没有这一限制、属于不同配置的接口可以共享端点。

配置描述符规定了设备的特征和能力。一般单个配置已经足够了,但在驱动程序的支持下,带有多应用或多电源选择的设备可支持多重配置。且每次只有一个配置被激活。每个配置需要一个配置描述符,其中含有关于设备电源使用及所支持接口数的信息。每个配置描述符都有附属描述符(subordinate descriptor),包括一个或多个接口描述符(Interface Descriptor)以及可选的端点描述符(Endpoint Descriptor)。

配置描述符如下:

串口串口

接口描述符

下图所示为标准的接口描述符定义。

串口

单个CDC类的描述符需要两个接口:通信接口描述符和数据接口描述符。这两个接口需要接口关联描述符(Interface Association Descriptor)进行绑定。

串口

接口关联描述符

IAD 接口关联描述符提供了一种功能:即把实现单个功能的多个 Interface 打包在一起。通过接口关联描述符打包在一起的若干 Interface 是同一个功能设备的 Interface,PC端只需要加载同一个驱动即可。

串口

通信(控制)接口描述符

该接口描述符需要包含功能描述符(Header,Call Management, ACM)、端点描述符。

串口

 功能描述符

Header 功能描述符

串口

Call Management 功能描述符

串口

ACM

串口

Union 功能描述符

串口

数据接口描述符

串口

端点描述符

下图所示为标准的端点描述符定义。

串口

本文中分配的端点如下:

串口

代码:

 

/* CDC 端点1 */
#define EPNUM_CDC_0_NOTIF   0x81
#define EPNUM_CDC_0_OUT     0x02
#define EPNUM_CDC_0_IN      0x82

/* CDC 端点2 */
#define EPNUM_CDC_1_NOTIF   0x83
#define EPNUM_CDC_1_OUT     0x04
#define EPNUM_CDC_1_IN      0x84

/* CDC 端点3 */
#define EPNUM_CDC_2_NOTIF   0x85
#define EPNUM_CDC_2_OUT     0x06
#define EPNUM_CDC_2_IN      0x86

 

配置描述符 / 接口描述符 / 端点描述符

 

uint8_t const desc_fs_configuration[] =
{
/* Config number, interface count, string index, total length, attribute, power in mA */
  TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),

/* 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. */
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),

/* 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. */
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),

/* 3nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. */
  TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_2, 4, EPNUM_CDC_2_NOTIF, 8, EPNUM_CDC_2_OUT, EPNUM_CDC_2_IN, 64),
};

 

字符串描述符

 

char const* string_desc_arr [] =
{
  (const char[]){0x09, 0x04},    // 0: Supported language: English (0x0409)
  "MindMotion",                    // 1: Manufacturer
  "MM32-3VCP",                    // 2: Product
  "20221229",                    // 3: Serials
  "CDC Virtual COM",            // 4: CDC Interface
};

 

CDC Task 接口

在该接口函数中,本文主要实现了各个串口的回环功能,即在任务处理中发送当前端点的接收字符。

 

void cdc_task(void)
{ 
  uint8_t itf;

  for (itf = 0; itf < CFG_TUD_CDC; itf++)
  {
    // connected() check for DTR bit
    // Most but not all terminal client set this when making connection
    // if ( tud_cdc_n_connected(itf) )
      if ( tud_cdc_n_available(itf) )
      {
        uint8_t buf[64];

        uint32_t count = tud_cdc_n_read(itf, buf, sizeof(buf));
        echo_serial_port(itf, buf, count);
      }
  }
}

 

 基本测试

如上,我们就完成三路虚拟串口的CDC功能,将程序下载到MCU中,插上USB线,然后在电脑的设备管理器的端口栏就可以找到对应的USB CDC枚举模拟串口设备。

串口串口

成功枚举,我们继续在Windows 和 Linux 环境下测试一下通信:

串口串口

测试成功。本文分享到此结束,谢谢!

审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分