[STM32F3] 基于STM32F1的USB转多路串口(USB-Multiple-CDC)

[复制链接]
6008|15
 楼主| IversonCar 发表于 2015-9-24 16:43 | 显示全部楼层 |阅读模式
根据ST英文社区提供的资料,实现的USB转多路串口(USB-Multiple-CDC)例程,利用了STM32F103系列多端点的特性。而STM32F2/F4端点数量较少,不能实现USB-Multiple-CDC,但STM32F2/F4可以外加高速PHY芯片,实现USB2.0高速通讯。应该说F1和F2、F4使用场合不同,所以功能定位有所不同。


例程包下载地址:USB-Multiple-CDC  



注意事项:
1.工程包中含有驱动安装引导文件。
2.3CDC工程包,属于USB转多路串口(USB-Multiple-CDC),驱动的安装可参考“USB-Dual-CDC驱动安装说明书”。
3.采用带参数的宏实现3路串口的DMA发送,这个相对于ST官方的阻塞式发送,更具有实用性。


USB-Dual-CDC驱动安装说明书下载地址: USB-Dual-CDC驱动安装说明书
USB-Dual-CDC驱动安装说明书是之前USB-Dual-RS485产品的驱动安装说明书,可以参考这个安装步骤,3路的驱动,就是多安装1路而已。


三路串口的DMA发送代码部分预览如下:

  1. /* 带参数的宏功能(预编译展开): USB的IN端点 发送数据到PC主机 */
  2. #define EPx_IN_Callback(ENDPx, CDCx_Tx_State, VCPx_Rx_Buffer, VCPx_Rx_ptr_out, VCPx_Rx_length) {\
  3.     uint16_t USB_Tx_ptr;\
  4.     uint16_t USB_Tx_length;\
  5.     if (CDCx_Tx_State == 1) {\
  6.         USB_Tx_ptr = VCPx_Rx_ptr_out;\
  7.         if (VCPx_Rx_length == 0) {\
  8.             CDCx_Tx_State = 0;\
  9.             SetEPTxCount(ENDPx,0);\
  10.             SetEPTxValid(ENDPx);\
  11.         } else {\
  12.             if (VCPx_Rx_length > VIRTUAL_COM_PORT_DATA_SIZE) {\
  13.                 USB_Tx_length = VIRTUAL_COM_PORT_DATA_SIZE;\
  14.                 VCPx_Rx_ptr_out += VIRTUAL_COM_PORT_DATA_SIZE;\
  15.                 VCPx_Rx_length -= VIRTUAL_COM_PORT_DATA_SIZE;\
  16.             } else {\
  17.                 USB_Tx_length = VCPx_Rx_length;\
  18.                 VCPx_Rx_ptr_out += VCPx_Rx_length;\
  19.                 VCPx_Rx_length = 0;\
  20.             }\
  21.             USB_SIL_Write(ENDPx, &VCPx_Rx_Buffer[USB_Tx_ptr], USB_Tx_length);\
  22.             SetEPTxValid(ENDPx);\
  23.         }\
  24.     }\
  25. }


  26. /* 带参数的宏功能(预编译展开): USB的OUT端点 通过物理串口向外发送数据(阻塞方式) */
  27. #define EPx_OUT_Callback(ENDPx, USARTx, GPIOx, GPIO_Pin_x) {\
  28.     uint32_t i;\
  29.     uint16_t USB_Rx_Cnt;\
  30.     USB_Rx_Cnt = USB_SIL_Read(ENDPx | 0x00, USB_Rx_Buffer); \
  31.     GPIOx->BSRR = GPIO_Pin_x;\
  32.     for (i = 0; i < USB_Rx_Cnt; i++) {\
  33.         USARTx->DR = *(USB_Rx_Buffer + i);\
  34.         while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);\
  35.     }\
  36.     SetEPRxValid(ENDPx);\
  37.     while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);\
  38.     USART_ClearFlag(USARTx, USART_FLAG_TC);\
  39.     GPIOx->BRR = GPIO_Pin_x;\
  40. }

  41. /* 带参数的宏功能(预编译展开): USB的OUT端点 通过物理串口向外发送数据(DMA方式) */
  42. #define EPx_OUT_Callback_DMA(Flag_VCPx_Tx_Buf_Use, ENDPx, VCPx_Tx_Buffer1,VCPx_Tx_Buffer2,\
  43.     GPIOx, GPIO_Pin_x, DMA1_Channelx, VCPx_Tx_Buffer_Cnt, Flag_VCPx_Tx_Buf_Full) {\
  44.     uint16_t USB_Rx_Cnt;\
  45.     if(Flag_VCPx_Tx_Buf_Use == 0){\
  46.         USB_Rx_Cnt = GetEPRxCount(ENDPx & 0x7F);\
  47.         PMAToUserBufferCopy(&VCPx_Tx_Buffer1[0], GetEPRxAddr(ENDPx & 0x7F), USB_Rx_Cnt);\
  48.         SetEPRxValid(ENDPx);\
  49.         GPIOx->BSRR = GPIO_Pin_x;\
  50.         DMA1_Channelx->CNDTR = USB_Rx_Cnt;\
  51.         DMA_Cmd(DMA1_Channelx, ENABLE);\
  52.         Flag_VCPx_Tx_Buf_Use = 1;\
  53.         VCPx_Tx_Buffer_Cnt = 0;\
  54.     } else {\
  55.         USB_Rx_Cnt = GetEPRxCount(ENDPx & 0x7F);\
  56.         if(VCPx_Tx_Buffer_Cnt < (1024-128)){\
  57.           PMAToUserBufferCopy(&VCPx_Tx_Buffer2[VCPx_Tx_Buffer_Cnt], GetEPRxAddr(ENDPx & 0x7F), USB_Rx_Cnt);\
  58.           VCPx_Tx_Buffer_Cnt += USB_Rx_Cnt;\
  59.           SetEPRxValid(ENDPx);\
  60.         } else {\
  61.           PMAToUserBufferCopy(&VCPx_Tx_Buffer2[VCPx_Tx_Buffer_Cnt], GetEPRxAddr(ENDPx & 0x7F), USB_Rx_Cnt);\
  62.           VCPx_Tx_Buffer_Cnt += USB_Rx_Cnt;\
  63.           Flag_VCPx_Tx_Buf_Full = 1;\
  64.         }\
  65.     }\
  66. }



mmuuss586 发表于 2015-9-24 17:52 | 显示全部楼层

不错,谢谢分享;
yklstudent 发表于 2015-9-24 21:19 | 显示全部楼层
马人口,xiexie楼主的资料
gejigeji521 发表于 2015-9-24 22:18 | 显示全部楼层
根据ST英文社区提供的资料,实现的USB转多路串口(USB-Multiple-CDC)例程,利用了STM32F103系列多端点的特性。
竟然可以这样,需要什么转接器吗
0406445 发表于 2015-10-4 00:39 | 显示全部楼层
大神,连接挂了,可以直接给我吗,我的邮箱:564386237@qq.com
ticomi 发表于 2015-10-4 08:37 | 显示全部楼层
理解了USB的端点功能后,很容易实现这样的功能,不建议直接要代码。如果不明白USB的底层问题,即便是实现了功能,也很难修改为自己需要的功能,所以最好还是理解USB后再看代码会很好。
0406445 发表于 2015-10-4 17:18 | 显示全部楼层
ticomi 发表于 2015-10-4 08:37
理解了USB的端点功能后,很容易实现这样的功能,不建议直接要代码。如果不明白USB的底层问题,即便是实现了 ...

我的是F302的,想实现usb虚拟多串口,多添加了接口部分,但是每次都是蓝屏,在想是不是电脑驱动问题,用IAD的话,不知道linux支不支持,请问有什么好的方法介绍下
我配置好接口描述符部分后,比如是双串口,那是不是还要初始化端点的部分才可以枚举?
ticomi 发表于 2015-10-7 09:16 | 显示全部楼层
0406445 发表于 2015-10-4 17:18
我的是F302的,想实现usb虚拟多串口,多添加了接口部分,但是每次都是蓝屏,在想是不是电脑驱动问题,用I ...

具体实现不是一句话可以说的清楚的,我在使用多端点时也是多次试验才最终成功的。这个还是要看下USB的协议内容后参照协议去实现了。
0406445 发表于 2015-10-7 20:31 | 显示全部楼层
ticomi 发表于 2015-10-7 09:16
具体实现不是一句话可以说的清楚的,我在使用多端点时也是多次试验才最终成功的。这个还是要看下USB的协 ...

多谢回复,能给个思路吗,就描述符上的就好
ticomi 发表于 2015-10-8 08:16 | 显示全部楼层
0406445 发表于 2015-10-7 20:31
多谢回复,能给个思路吗,就描述符上的就好
  1. /* USB HID&MSC device Configuration Descriptor */
  2. static uint8 USBD_CfgDesc[USB_HIDMSC_CONFIG_DESC_SIZ] =
  3. {
  4.   0x09,     //bLength: Configuration Descriptor size
  5.   USB_CONFIGURATION_DESCRIPTOR_TYPE,    //bDescriptorType: Configuration
  6.   USB_HIDMSC_CONFIG_DESC_SIZ,           //wTotalLength: Bytes returned
  7.   0x00,
  8.   0x02,         //bNumInterfaces: 1 interface
  9.   0x01,         //bConfigurationValue: Configuration value
  10.   0x00,         //iConfiguration: Index of string descriptor describing the configuration
  11.   0xC0,         //bmAttributes: bus powered and NOT Support Remote Wake-up
  12.   0x00,         //MaxPower 0 mA: this current is used for detecting Vbus
  13.   
  14.   
  15.   /** Mass Storage interface (09)**/
  16.   0x09,         //bLength: Interface Descriptor size
  17.   0x04,         //bDescriptorType:
  18.   0x00,         //bInterfaceNumber: Number of Interface
  19.   0x00,         //bAlternateSetting: Alternate setting
  20.   0x02,         //bNumEndpoints*/
  21.   0x08,         //bInterfaceClass: MSC Class
  22.   0x06,         //bInterfaceSubClass : SCSI transparent
  23.   0x50,         //nInterfaceProtocol
  24.   0x05,         //iInterface:
  25.   /** Mass Storage IN Endpoints (18) **/
  26.   0x07,         //Endpoint descriptor length = 7
  27.   0x05,         //Endpoint descriptor type
  28.   MSC_IN_EP,    //Endpoint address (IN, address 1)
  29.   0x02,         //Bulk endpoint type
  30.   LOBYTE(MSC_MAX_PACKET),
  31.   HIBYTE(MSC_MAX_PACKET),
  32.   0x00,         //Polling interval in milliseconds
  33.   /** Mass Storage OUT Endpoints (25) **/
  34.   0x07,         //Endpoint descriptor length = 7
  35.   0x05,         //Endpoint descriptor type
  36.   MSC_OUT_EP,   //Endpoint address (OUT, address 1)
  37.   0x02,         //Bulk endpoint type
  38.   LOBYTE(MSC_MAX_PACKET),
  39.   HIBYTE(MSC_MAX_PACKET),
  40.   0x00,         //Polling interval in milliseconds
  41.   
  42.   
  43.   /* Descriptor of Custom HID interface (32)*/
  44.   0x09,         //bLength: Interface Descriptor size
  45.   0x04,         //bDescriptorType: Interface descriptor type
  46.   0x01,         //bInterfaceNumber: Number of Interface
  47.   0x00,         //bAlternateSetting: Alternate setting
  48.   0x02,         //bNumEndpoints
  49.   0x03,         //bInterfaceClass: HID
  50.   0x00,         //bInterfaceSubClass : 1=BOOT, 0=no boot
  51.   0x00,         //nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse
  52.   0,            //iInterface: Index of string descriptor
  53.   /** Descriptor of Custom HID (41) **/
  54.   0x09,         //bLength: HID Descriptor size
  55.   HID_DESCRIPTOR_TYPE, //bDescriptorType: HID
  56.   0x10,         //bcdHID: HID Class Spec release number
  57.   0x01,
  58.   0x00,         //bCountryCode: Hardware target country
  59.   0x01,         //bNumDescriptors: Number of HID class descriptors to follow
  60.   0x22,         //bDescriptorType
  61.   HID_REPORT_DESC_SIZE,//wItemLength: Total length of Report descriptor
  62.   0x00,
  63.   /** Descriptor of IN endpoint(50) **/
  64.   0x07,         //bLength: Endpoint Descriptor size
  65.   0x05,         //bDescriptorType:  
  66.   HID_IN_EP,    //bEndpointAddress: Endpoint Address (IN)
  67.   0x03,         //bmAttributes: Interrupt endpoint
  68.   HID_IN_PACKET,//wMaxPacketSize: 64 Byte max
  69.   0x00,
  70.   0x01,         //bInterval: Polling Interval (1 ms)
  71.   /** Descriptor of OUT endpoint (57) **/
  72.   0x07,             //bLength: Endpoint Descriptor size
  73.   0x05,             //bDescriptorType:
  74.   HID_OUT_EP,       //bEndpointAddress: Endpoint Address (IN)
  75.   0x03,             //bmAttributes: Interrupt endpoint
  76.   HID_OUT_PACKET,   //wMaxPacketSize: 64 Byte max
  77.   0x00,
  78.   0x01,             //bInterval: Polling Interval (1 ms)
  79. };
android2 发表于 2015-10-8 11:05 | 显示全部楼层
USB-Multiple-CDC  ,USB-Dual-CDC驱动安装说明书,这两个链接好像失效了啊
huangqi412 发表于 2015-10-8 12:20 | 显示全部楼层
0406445 发表于 2015-10-4 17:18
我的是F302的,想实现usb虚拟多串口,多添加了接口部分,但是每次都是蓝屏,在想是不是电脑驱动问题,用I ...

单片机USB转多串口,似乎都是用IAD描述符。网上好多现成F103代码
0406445 发表于 2015-10-8 14:05 | 显示全部楼层
ticomi 发表于 2015-10-8 14:14 | 显示全部楼层
0406445 发表于 2015-10-8 14:05
大神,有cdc类的吗,

没有,起始可以参考这个写个出来的,我现在也不使用这个了,而是采用新的复合设备方式,一样的思路!
0406445 发表于 2015-10-8 15:08 | 显示全部楼层
huangqi412 发表于 2015-10-8 12:20
单片机USB转多串口,似乎都是用IAD描述符。网上好多现成F103代码

对啊,都是IAD的,我想linux应该是不支持IAD的
lxs_14 发表于 2019-11-11 22:29 | 显示全部楼层
楼主,连接挂了,可以直接给我吗,我的邮箱:103819240@qq.com ,谢谢
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

344

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部