你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32 USB如何配置多个CDC设备---5个CDC设备

[复制链接]
STMCU小助手 发布时间:2023-1-3 19:55
1. 背景
  • 由于项需求,在STM32F072中需实现5个CDC设备,折腾了很久分享出来,希望能帮助别人少踩一些坑.USB2.0全速,该款单片机支持8个输出和8个输入端点

2.1 它是什么?需要使用到什么?
  • 它是USB设备类型的一种,如U盘插入电脑时,电脑会知道其是U盘,是一个存储设备,那么它就属于USB MCU存储设备。USB协议中对设备进行了分类.它在stm32上叫虚拟串口设备,当将其链接电脑后,可以把它当成串口使用,如使用windows的串口工具打开它,设置波特率等等,这是我的理解。

  • 它需要两个接口,三个端点

  • InterFace 0:第一个接口,其包括一个端点,和Functional_Destriptcrs,该端点为控制接口(输入型端点(IN)),Functional_Destriptcrs则是一些描述符。先不管这个
  • InterFace 1:第二接口,其包括两个端点,endpoint In 和endpoint out端点,IN为stm32数据输出端点,OUT为stm32数据输入端点,随便提下,在STM32 HAL库中,USB的IN,OUT是相对于主机而言的,如:上诉的IN是指主机的输入,主机的输入(IN),对于设备来说就是OUT,数据的输出端点,IN OUT都是相对于主机而言
  • 由此可见,正常情况下,一个CDC需要三个端点,其中两个IN端点,一个OUT端点

3.配置过程3.1 配置流程
  • 在STM32CubeIDE的帮助下,生成一个CDC的代码,这里没什么坑,点几下就成功了,注意的是可能需要将Heap设置大一点
  • 修改设备描述符
  • 分配端点和修改配置描述符
  • 分配PMA端点缓存地址
  • 修改HAL库关于CDC部分函数接口的参数,以适配多CDC设备的情况


3.2 使用STM32CubeIDE生成一个CDC程序的代码
  • 根据下面的文件操作即可,文件会介绍USBCDC的知识,在PDF的最后会说怎么使用cubeIDE配置,很简单没什么坑(注意的是可能需要将Heap设置大一点)


3.3 分配端点和修改配置描述符
  • 此时问题来了,CDC要求3个端点,其中2个输入1个输出,而stm32F072只支持8个输入端点,8个输出端点,2x5>8,正常情况下是不够的,这里就需要将IN端口中的控制端口省略,也就是第一幅图中的Interface 0中的endpoint IN端点,不分配有效端点给它,在本款单片机中IN端点的有效范围(0x80-0x87),OUT(0x00-0x08)


  1. #define CDC_IN_EP                                   0x81U  /* CDC*/
  2. #define CDC_OUT_EP                                  0x01U  
  3. #define CDC_CMD_EP                                  0x88U  //无效端点

  4. #define CDC_IN_EP1                                   0x82U   /* CDC1*/
  5. #define CDC_OUT_EP1                                  0x02U  
  6. #define CDC_CMD_EP1                                  0x89U  //无效端点

  7. #define CDC_IN_EP2                                   0x83U   /* CDC2*/
  8. #define CDC_OUT_EP2                                  0x03U  
  9. #define CDC_CMD_EP2                                  0x8AU  //无效端点

  10. #define CDC_IN_EP3                                   0x84U   /* CDC3*/
  11. #define CDC_OUT_EP3                                  0x04U  
  12. #define CDC_CMD_EP3                                  0x8CU  //无效端点

  13. #define CDC_IN_EP4                                   0x85U   /* CDC4*/
  14. #define CDC_OUT_EP4                                  0x05U
  15. #define CDC_CMD_EP4                                  0x8BU  //无效端点
复制代码


  • 修改配置描述符号,这里面的内容就很多了,里面涉及到USB方方面面的属性和参数,其中USB_CDC_CONFIG_DESC_SIZ是该结构体的大小,记得修改,或者直接改为最大255。
  • 配置描述符的结构如下:

  1. 配置描述符
  2. {
  3.     配置描述符总概括(相当于预览:9字节)
  4.     IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC
  5.     {
  6.         接口描述符1
  7.         {
  8.             其他描述符(ACM等)
  9.             端点描述符(控制端点)
  10.         }
  11.         接口描述符2
  12.         {
  13.             端点描述符(IN)
  14.             端点描述符(OUT)
  15.         }
  16.     }

  17.     IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC1
  18.     {
  19.         接口描述符1
  20.         {
  21.             其他描述符(ACM等)
  22.             端点描述符(控制端点)
  23.         }
  24.         接口描述符2
  25.         {
  26.             端点描述符(IN)
  27.             端点描述符(OUT)
  28.         }
  29.     }

  30.     IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC2
  31.     {
  32.         接口描述符1
  33.         {
  34.             其他描述符(ACM等)
  35.             端点描述符(控制端点)
  36.         }
  37.         接口描述符2
  38.         {
  39.             端点描述符(IN)
  40.             端点描述符(OUT)
  41.         }
  42.     }

  43.     IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC3
  44.     {
  45.         接口描述符1
  46.         {
  47.             其他描述符(ACM等)
  48.             端点描述符(控制端点)
  49.         }
  50.         接口描述符2
  51.         {
  52.             端点描述符(IN)
  53.             端点描述符(OUT)
  54.         }
  55.     }

  56.     IAD描述符(标识接下来的接口属于一个设备,一个设备就一个IAD描述符)CDC4
  57.     {
  58.         接口描述符1
  59.         {
  60.             其他描述符(ACM等)
  61.             端点描述符(控制端点)
  62.         }
  63.         接口描述符2
  64.         {
  65.             端点描述符(IN)
  66.             端点描述符(OUT)
  67.         }
  68.     }
  69. }
复制代码

  • 配置描述符如下,下面有些字段需要修改的,都用casojie标记了,CTRL+F搜索casojie就可以方便显示;


  1. __ALIGN_BEGIN uint8_t USBD_CDC_CfgFSDesc[USB_CDC_CONFIG_DESC_SIZ] __ALIGN_END =
  2. {
  3.   /*Configuration Descriptor*/
  4.   0x09,   /* bLength: Configuration Descriptor size */
  5.   USB_DESC_TYPE_CONFIGURATION,      /* bDescriptorType: Configuration */
  6.   USB_CDC_CONFIG_DESC_SIZ,                /* wTotalLength:no of returned bytes */
  7.   0x00,
  8.   0x0A,   /* bNumInterfaces: 10 interface *///总接口大小,5个CDC*2=10=0x0A casojie
  9.   0x01,   /* bConfigurationValue: Configuration value */
  10.   0x00,   /* iConfiguration: Index of string descriptor describing the configuration */
  11.   0xC0,   /* bmAttributes: self powered */
  12.   0x32,   /* MaxPower 0 mA */

  13.   /*------------------------CDC0--------------------------------------------------8+9+5+5+7+9+7+7-*/
  14.   // // // IAD  Interface Association Descriptor //IAD描述符需要添加 casojie
  15.   // 0x08,  // bLength: Interface Descriptor size //标识IAD描述符的长度,基本都是8,casojie
  16.   // 0x0B,      // bDescriptorType: IAD            //不用管
  17.   // 0x00,  // bFirstInterface                      //第一个接口的序号
  18.   // 0x02,  // bInterfaceCount                      //本IDA的接口数量
  19.   // 0x02,  // bFunctionClass: CDC                  //表明该IAD是一个CDC设备
  20.   // 0x02,  // bFunctionSubClass                    //不用管
  21.   // 0x01,  // bFunctionProtocol                    //控制协议等其他我也不懂,默认就行
  22.   // 0x02,  // iFunction   

  23. /*Interface Descriptor */
  24.   0x09,   /* bLength: Interface Descriptor size */
  25.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
  26.   /* Interface descriptor type */
  27.   0x00,   /* bInterfaceNumber: Number of Interface */   //接口编号,从0开始 casojie
  28.   0x00,   /* bAlternateSetting: Alternate setting */
  29.   0x01,   /* bNumEndpoints: One endpoints used */       //接口内有多少个端点被使用 1个 casojie
  30.   0x02,   /* bInterfaceClass: Communication Interface Class */
  31.   0x02,   /* bInterfaceSubClass: Abstract Control Model */
  32.   0x01,   /* bInterfaceProtocol: Common AT commands */
  33.   0x00,   /* iInterface: */

  34.   // /*Header Functional Descriptor*/
  35.   // 0x05,   /* bLength: Endpoint Descriptor size */
  36.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  37.   // 0x00,   /* bDescriptorSubtype: Header Func Desc */
  38.   // 0x10,   /* bcdCDC: spec release number */
  39.   // 0x01,

  40.   // /*Call Management Functional Descriptor*/
  41.   // 0x05,   /* bFunctionLength */
  42.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  43.   // 0x01,   /* bDescriptorSubtype: Call Management Func Desc */
  44.   // 0x00,   /* bmCapabilities: D0+D1 */
  45.   // 0x01,   /* bDataInterface: 1 */

  46.   /*ACM Functional Descriptor*/
  47.   0x04,   /* bFunctionLength */
  48.   0x24,   /* bDescriptorType: CS_INTERFACE */
  49.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
  50.   0x0F,   /* bmCapabilities */

  51.   /*Union Functional Descriptor*/
  52.   0x05,   /* bFunctionLength */
  53.   0x24,   /* bDescriptorType: CS_INTERFACE */
  54.   0x06,   /* bDescriptorSubtype: Union func desc */
  55.   0x00,   /* bMasterInterface: Communication class interface */ //联合描述符,与IAD功能类似,标识哪两个接口是属于一个设备的casojie
  56.   0x01,   /* bSlaveInterface0: Data Class Interface */  //与上面一样,上面是0,这里是1,标识0号,1号接口是属于一个CDC设备的 casojie

  57.   /*Endpoint 2 Descriptor*/
  58.   0x07,                           /* bLength: Endpoint Descriptor size *///控制端点描述符,虽然端点号是无效的,但是这个描述符不可省略
  59.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
  60.   CDC_CMD_EP,                     /* bEndpointAddress */
  61.   0x03,                           /* bmAttributes: Interrupt */
  62.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
  63.   HIBYTE(CDC_CMD_PACKET_SIZE),
  64.   0x10,                           /* bInterval: */
  65.   /*---------------------------------------------------------------------------*/

  66.   /*Data class interface descriptor*/   //第二个接口描述符 casojie
  67.   0x09,   /* bLength: Endpoint Descriptor size */
  68.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
  69.   0x01,   /* bInterfaceNumber: Number of Interface */   //接口的序号,上一个接口是0,那这里就是1 casojie
  70.   0x00,   /* bAlternateSetting: Alternate setting */
  71.   0x02,   /* bNumEndpoints: Two endpoints used */       //标识此接口有两个端点(IN)(OUT) casojie
  72.   0x0A,   /* bInterfaceClass: CDC */
  73.   0x00,   /* bInterfaceSubClass: */
  74.   0x00,   /* bInterfaceProtocol: */
  75.   0x00,   /* iInterface: */

  76.   /*Endpoint OUT Descriptor*/                       //OUT端点
  77.   0x07,   /* bLength: Endpoint Descriptor size */
  78.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  79.   CDC_OUT_EP,                        /* bEndpointAddress */
  80.   0x02,                              /* bmAttributes: Bulk */
  81.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  82.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  83.   0x00,                              /* bInterval: ignore for Bulk transfer */

  84.   /*Endpoint IN Descriptor*/                        //IN端点
  85.   0x07,   /* bLength: Endpoint Descriptor size */
  86.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  87.   CDC_IN_EP,                         /* bEndpointAddress */
  88.   0x02,                              /* bmAttributes: Bulk */
  89.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  90.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  91.   0x00,                               /* bInterval: ignore for Bulk transfer */

  92.   /*---------------------------------------------------------------------------*/
  93.   // IAD  Interface Association Descriptor       //这里就是CDC1了,重复CDC0的配置过程,注意有些字段的序号 casojie
  94.   // 0x08,  // bLength: Interface Descriptor size
  95.   // 0x0B,      // bDescriptorType: IAD
  96.   // 0x02,  // bFirstInterface                  //太多了,写不下去了,意思和第一个IDA一样的
  97.   // 0x02,  // bInterfaceCount
  98.   // 0x02,  // bFunctionClass: CDC
  99.   // 0x02,  // bFunctionSubClass
  100.   // 0x01,  // bFunctionProtocol
  101.   // 0x02,  // iFunction

  102. /*Interface Descriptor */
  103.   0x09,   /* bLength: Interface Descriptor size */
  104.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
  105.   /* Interface descriptor type */
  106.   0x02,   /* bInterfaceNumber: Number of Interface */
  107.   0x00,   /* bAlternateSetting: Alternate setting */
  108.   0x01,   /* bNumEndpoints: One endpoints used */
  109.   0x02,   /* bInterfaceClass: Communication Interface Class */
  110.   0x02,   /* bInterfaceSubClass: Abstract Control Model */
  111.   0x01,   /* bInterfaceProtocol: Common AT commands */
  112.   0x00,   /* iInterface: */

  113.   // /*Header Functional Descriptor*/
  114.   // 0x05,   /* bLength: Endpoint Descriptor size */
  115.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  116.   // 0x00,   /* bDescriptorSubtype: Header Func Desc */
  117.   // 0x10,   /* bcdCDC: spec release number */
  118.   // 0x01,

  119.   // /*Call Management Functional Descriptor*/
  120.   // 0x05,   /* bFunctionLength */
  121.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  122.   // 0x01,   /* bDescriptorSubtype: Call Management Func Desc */
  123.   // 0x00,   /* bmCapabilities: D0+D1 */
  124.   // 0x01,   /* bDataInterface: 1 */

  125.   /*ACM Functional Descriptor*/
  126.   0x04,   /* bFunctionLength */
  127.   0x24,   /* bDescriptorType: CS_INTERFACE */
  128.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
  129.   0x0F,   /* bmCapabilities */

  130.   /*Union Functional Descriptor*/
  131.   0x05,   /* bFunctionLength */
  132.   0x24,   /* bDescriptorType: CS_INTERFACE */
  133.   0x06,   /* bDescriptorSubtype: Union func desc */
  134.   0x02,   /* bMasterInterface: Communication class interface */
  135.   0x03,   /* bSlaveInterface0: Data Class Interface */

  136.   // /*Endpoint 2 Descriptor*/
  137.   0x07,                           /* bLength: Endpoint Descriptor size */
  138.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
  139.   CDC_CMD_EP1,                     /* bEndpointAddress */
  140.   0x03,                           /* bmAttributes: Interrupt */
  141.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
  142.   HIBYTE(CDC_CMD_PACKET_SIZE),
  143.   0x10,                           /* bInterval: */
  144.   /*---------------------------------------------------------------------------*/

  145.   /*Data class interface descriptor*/
  146.   0x09,   /* bLength: Endpoint Descriptor size */
  147.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
  148.   0x03,   /* bInterfaceNumber: Number of Interface */
  149.   0x00,   /* bAlternateSetting: Alternate setting */
  150.   0x02,   /* bNumEndpoints: Two endpoints used */
  151.   0x0A,   /* bInterfaceClass: CDC */
  152.   0x00,   /* bInterfaceSubClass: */
  153.   0x00,   /* bInterfaceProtocol: */
  154.   0x00,   /* iInterface: */

  155.   /*Endpoint OUT Descriptor*/
  156.   0x07,   /* bLength: Endpoint Descriptor size */
  157.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  158.   CDC_OUT_EP1,                        /* bEndpointAddress */
  159.   0x02,                              /* bmAttributes: Bulk */
  160.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  161.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  162.   0x00,                              /* bInterval: ignore for Bulk transfer */

  163.   /*Endpoint IN Descriptor*/
  164.   0x07,   /* bLength: Endpoint Descriptor size */
  165.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  166.   CDC_IN_EP1,                         /* bEndpointAddress */
  167.   0x02,                              /* bmAttributes: Bulk */
  168.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  169.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  170.   0x00,                               /* bInterval: ignore for Bulk transfer */
  171.   /*---------------------------------------------------------------------------*/
  172.   // IAD  Interface Association Descriptor
  173.   // 0x08,  // bLength: Interface Descriptor size
  174.   // 0x0B,      // bDescriptorType: IAD
  175.   // 0x04,  // bFirstInterface
  176.   // 0x02,  // bInterfaceCount
  177.   // 0x02,  // bFunctionClass: CDC
  178.   // 0x02,  // bFunctionSubClass
  179.   // 0x01,  // bFunctionProtocol
  180.   // 0x02,  // iFunction

  181. /*Interface Descriptor */
  182.   0x09,   /* bLength: Interface Descriptor size */
  183.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
  184.   /* Interface descriptor type */
  185.   0x04,   /* bInterfaceNumber: Number of Interface */
  186.   0x00,   /* bAlternateSetting: Alternate setting */
  187.   0x01,   /* bNumEndpoints: One endpoints used */
  188.   0x02,   /* bInterfaceClass: Communication Interface Class */
  189.   0x02,   /* bInterfaceSubClass: Abstract Control Model */
  190.   0x01,   /* bInterfaceProtocol: Common AT commands */
  191.   0x00,   /* iInterface: */

  192.   // /*Header Functional Descriptor*/
  193.   // 0x05,   /* bLength: Endpoint Descriptor size */
  194.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  195.   // 0x00,   /* bDescriptorSubtype: Header Func Desc */
  196.   // 0x10,   /* bcdCDC: spec release number */
  197.   // 0x01,

  198.   // /*Call Management Functional Descriptor*/
  199.   // 0x05,   /* bFunctionLength */
  200.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  201.   // 0x01,   /* bDescriptorSubtype: Call Management Func Desc */
  202.   // 0x00,   /* bmCapabilities: D0+D1 */
  203.   // 0x01,   /* bDataInterface: 1 */

  204.   /*ACM Functional Descriptor*/
  205.   0x04,   /* bFunctionLength */
  206.   0x24,   /* bDescriptorType: CS_INTERFACE */
  207.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
  208.   0x0F,   /* bmCapabilities */

  209.   /*Union Functional Descriptor*/
  210.   0x05,   /* bFunctionLength */
  211.   0x24,   /* bDescriptorType: CS_INTERFACE */
  212.   0x06,   /* bDescriptorSubtype: Union func desc */
  213.   0x04,   /* bMasterInterface: Communication class interface */
  214.   0x05,   /* bSlaveInterface0: Data Class Interface */

  215.   // /*Endpoint 2 Descriptor*/
  216.   0x07,                           /* bLength: Endpoint Descriptor size */
  217.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
  218.   CDC_CMD_EP2,                     /* bEndpointAddress */
  219.   0x03,                           /* bmAttributes: Interrupt */
  220.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
  221.   HIBYTE(CDC_CMD_PACKET_SIZE),
  222.   0x10,                           /* bInterval: */
  223.   /*---------------------------------------------------------------------------*/

  224.   /*Data class interface descriptor*/
  225.   0x09,   /* bLength: Endpoint Descriptor size */
  226.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
  227.   0x05,   /* bInterfaceNumber: Number of Interface */
  228.   0x00,   /* bAlternateSetting: Alternate setting */
  229.   0x02,   /* bNumEndpoints: Two endpoints used */
  230.   0x0A,   /* bInterfaceClass: CDC */
  231.   0x00,   /* bInterfaceSubClass: */
  232.   0x00,   /* bInterfaceProtocol: */
  233.   0x00,   /* iInterface: */

  234.   /*Endpoint OUT Descriptor*/
  235.   0x07,   /* bLength: Endpoint Descriptor size */
  236.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  237.   CDC_OUT_EP2,                        /* bEndpointAddress */
  238.   0x02,                              /* bmAttributes: Bulk */
  239.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  240.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  241.   0x00,                              /* bInterval: ignore for Bulk transfer */

  242.   /*Endpoint IN Descriptor*/
  243.   0x07,   /* bLength: Endpoint Descriptor size */
  244.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  245.   CDC_IN_EP2,                         /* bEndpointAddress */
  246.   0x02,                              /* bmAttributes: Bulk */
  247.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  248.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  249.   0x00,                               /* bInterval: ignore for Bulk transfer */

  250.   /*---------------------------------------------------------------------------*/
  251.   // IAD  Interface Association Descriptor
  252.   // 0x08,  // bLength: Interface Descriptor size
  253.   // 0x0B,      // bDescriptorType: IAD
  254.   // 0x06,  // bFirstInterface
  255.   // 0x02,  // bInterfaceCount
  256.   // 0x02,  // bFunctionClass: CDC
  257.   // 0x02,  // bFunctionSubClass
  258.   // 0x01,  // bFunctionProtocol
  259.   // 0x02,  // iFunction

  260. /*Interface Descriptor */
  261.   0x09,   /* bLength: Interface Descriptor size */
  262.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
  263.   /* Interface descriptor type */
  264.   0x06,   /* bInterfaceNumber: Number of Interface */
  265.   0x00,   /* bAlternateSetting: Alternate setting */
  266.   0x01,   /* bNumEndpoints: One endpoints used */
  267.   0x02,   /* bInterfaceClass: Communication Interface Class */
  268.   0x02,   /* bInterfaceSubClass: Abstract Control Model */
  269.   0x01,   /* bInterfaceProtocol: Common AT commands */
  270.   0x00,   /* iInterface: */

  271.   // /*Header Functional Descriptor*/
  272.   // 0x05,   /* bLength: Endpoint Descriptor size */
  273.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  274.   // 0x00,   /* bDescriptorSubtype: Header Func Desc */
  275.   // 0x10,   /* bcdCDC: spec release number */
  276.   // 0x01,

  277.   // /*Call Management Functional Descriptor*/
  278.   // 0x05,   /* bFunctionLength */
  279.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  280.   // 0x01,   /* bDescriptorSubtype: Call Management Func Desc */
  281.   // 0x00,   /* bmCapabilities: D0+D1 */
  282.   // 0x01,   /* bDataInterface: 1 */

  283.   /*ACM Functional Descriptor*/
  284.   0x04,   /* bFunctionLength */
  285.   0x24,   /* bDescriptorType: CS_INTERFACE */
  286.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
  287.   0x0F,   /* bmCapabilities */

  288.   /*Union Functional Descriptor*/
  289.   0x05,   /* bFunctionLength */
  290.   0x24,   /* bDescriptorType: CS_INTERFACE */
  291.   0x06,   /* bDescriptorSubtype: Union func desc */
  292.   0x06,   /* bMasterInterface: Communication class interface */
  293.   0x07,   /* bSlaveInterface0: Data Class Interface */

  294.   /*Endpoint 2 Descriptor*/
  295.   0x07,                           /* bLength: Endpoint Descriptor size */
  296.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
  297.   CDC_CMD_EP3,                     /* bEndpointAddress */
  298.   0x03,                           /* bmAttributes: Interrupt */
  299.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
  300.   HIBYTE(CDC_CMD_PACKET_SIZE),
  301.   0x10,                           /* bInterval: */
  302.   /*---------------------------------------------------------------------------*/

  303.   /*Data class interface descriptor*/
  304.   0x09,   /* bLength: Endpoint Descriptor size */
  305.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
  306.   0x07,   /* bInterfaceNumber: Number of Interface */
  307.   0x00,   /* bAlternateSetting: Alternate setting */
  308.   0x02,   /* bNumEndpoints: Two endpoints used */
  309.   0x0A,   /* bInterfaceClass: CDC */
  310.   0x00,   /* bInterfaceSubClass: */
  311.   0x00,   /* bInterfaceProtocol: */
  312.   0x00,   /* iInterface: */

  313.   /*Endpoint OUT Descriptor*/
  314.   0x07,   /* bLength: Endpoint Descriptor size */
  315.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  316.   CDC_OUT_EP3,                        /* bEndpointAddress */
  317.   0x02,                              /* bmAttributes: Bulk */
  318.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  319.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  320.   0x00,                              /* bInterval: ignore for Bulk transfer */

  321.   /*Endpoint IN Descriptor*/
  322.   0x07,   /* bLength: Endpoint Descriptor size */
  323.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  324.   CDC_IN_EP3,                         /* bEndpointAddress */
  325.   0x02,                              /* bmAttributes: Bulk */
  326.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  327.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  328.   0x00,                               /* bInterval: ignore for Bulk transfer */

  329. //   /*---------------------------------------------------------------------------*/
  330. //   // IAD  Interface Association Descriptor
  331. //   // 0x08,   // bLength: Interface Descriptor size
  332. //   // 0x0B,       // bDescriptorType: IAD
  333. //   // 0x08,   // bFirstInterface
  334. //   // 0x02,   // bInterfaceCount
  335. //   // 0x02,   // bFunctionClass: CDC
  336. //   // 0x02,   // bFunctionSubClass
  337. //   // 0x01,   // bFunctionProtocol
  338. //   // 0x02,   // iFunction

  339. /*Interface Descriptor */
  340.   0x09,   /* bLength: Interface Descriptor size */
  341.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
  342.   /* Interface descriptor type */
  343.   0x08,   /* bInterfaceNumber: Number of Interface */
  344.   0x00,   /* bAlternateSetting: Alternate setting */
  345.   0x01,   /* bNumEndpoints: One endpoints used */
  346.   0x02,   /* bInterfaceClass: Communication Interface Class */
  347.   0x02,   /* bInterfaceSubClass: Abstract Control Model */
  348.   0x01,   /* bInterfaceProtocol: Common AT commands */
  349.   0x00,   /* iInterface: */

  350.   // /*Header Functional Descriptor*/
  351.   // 0x05,   /* bLength: Endpoint Descriptor size */
  352.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  353.   // 0x00,   /* bDescriptorSubtype: Header Func Desc */
  354.   // 0x10,   /* bcdCDC: spec release number */
  355.   // 0x01,

  356.   // /*Call Management Functional Descriptor*/
  357.   // 0x05,   /* bFunctionLength */
  358.   // 0x24,   /* bDescriptorType: CS_INTERFACE */
  359.   // 0x01,   /* bDescriptorSubtype: Call Management Func Desc */
  360.   // 0x00,   /* bmCapabilities: D0+D1 */
  361.   // 0x01,   /* bDataInterface: 1 */

  362.   /*ACM Functional Descriptor*/
  363.   0x04,   /* bFunctionLength */
  364.   0x24,   /* bDescriptorType: CS_INTERFACE */
  365.   0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
  366.   0x0F,   /* bmCapabilities */

  367.   /*Union Functional Descriptor*/
  368.   0x05,   /* bFunctionLength */
  369.   0x24,   /* bDescriptorType: CS_INTERFACE */
  370.   0x06,   /* bDescriptorSubtype: Union func desc */
  371.   0x08,   /* bMasterInterface: Communication class interface */
  372.   0x09,   /* bSlaveInterface0: Data Class Interface */

  373.   /*Endpoint 2 Descriptor*/
  374.   0x07,                           /* bLength: Endpoint Descriptor size */
  375.   USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
  376.   CDC_CMD_EP4,                     /* bEndpointAddress */
  377.   0x03,                           /* bmAttributes: Interrupt */
  378.   LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
  379.   HIBYTE(CDC_CMD_PACKET_SIZE),
  380.   0x10,                           /* bInterval: */
  381.   /*---------------------------------------------------------------------------*/
  382.   /*
  383.   /*Data class interface descriptor*/
  384.   0x09,   /* bLength: Endpoint Descriptor size */
  385.   USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
  386.   0x09,   /* bInterfaceNumber: Number of Interface */
  387.   0x00,   /* bAlternateSetting: Alternate setting */
  388.   0x02,   /* bNumEndpoints: Two endpoints used */
  389.   0x0A,   /* bInterfaceClass: CDC */
  390.   0x00,   /* bInterfaceSubClass: */
  391.   0x00,   /* bInterfaceProtocol: */
  392.   0x00,   /* iInterface: */

  393.   /*Endpoint OUT Descriptor*/
  394.   0x07,   /* bLength: Endpoint Descriptor size */
  395.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  396.   CDC_OUT_EP4,                        /* bEndpointAddress */
  397.   0x02,                              /* bmAttributes: Bulk */
  398.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  399.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  400.   0x00,                              /* bInterval: ignore for Bulk transfer */

  401.   /*Endpoint IN Descriptor*/
  402.   0x07,   /* bLength: Endpoint Descriptor size */
  403.   USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  404.   CDC_IN_EP4,                         /* bEndpointAddress */
  405.   0x02,                              /* bmAttributes: Bulk */
  406.   LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  407.   HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  408.   0x00                               /* bInterval: ignore for Bulk transfer */
  409. }
复制代码


  • 为什么上面有些描述符被注释掉了?
  • 配置5个CDC如果描述符都写上了,这个结构体就超过了255个字节大小,超过了USB2.0最大配置描述符长度
  • 在我的项目中,IAD和联合描述符(/Union Functional Descriptor/)功能一样,我这里注释IAD描述符,不会影响USB,但在windows平台下,它认的是IAD描述符,这个时候就可以注释联合描述符,打开IAD描述符,总之,省略一些非必要描述,减少长度
  • 这里的坑很多很多,需要很耐心,配错一个字段,千奇百怪的问题就来了

3.4 配置PMA---USB硬件缓存
  • 这里又有坑了,我把我知道的都说出
3.4.1 PMA是啥?
  • 此部分感谢一个大佬的帖子,理解来源与它
  • 这个PMA的作用就是USB设备模块用来实现MCU与主机进行数据通信的一个专门的数据缓冲区,我们称之为USB硬件缓冲区。说得具体点就是USB模块把来自主机的数据接收进来后先放到PMA,然后再被拷贝到用户数据缓存区;或者MCU要发送到主机的数据,先从用户数据缓存区拷贝**MA,再通过USB模块负责发送给主机。


3.4.2 5个CDC的PMA怎么配置?
  • 啥也不说,先上代码


  1. u_int16_t ep_addR=0x70; //起始分配地址: 这里是大坑 casojie
  2. u_int8_t ep_addr_size=64;
  3. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;   //此端点是用于USB枚举和基本的通信使用,默认就有,且不可省去
  4. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;
  5. /* USER CODE END EndPoint_Configuration */
  6. //CDC0 每个端点都分配了64B
  7. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;
  8. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;

  9. //CDC1                                                                                                //+5
  10. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP1, PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;  //192 258
  11. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP1 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;    //272 2A8

  12. //CDC2
  13. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP2 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size; //0x270
  14. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP2 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;//0x2C0

  15. //CDC3
  16. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP3, PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;  //192 258 0x1E0
  17. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP3 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;

  18. //CDC4
  19. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP4, PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;  
  20. HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP4 , PCD_SNG_BUF, ep_addR);ep_addR+=ep_addr_size;
复制代码


  • PMA图(我理解的)

  • 在PMA的开头部分,是用于记录信息的,这些信息就是:端点缓存区的起始地址:说这简单点,里面写了端点0的缓存区的起始地址是X,端点1的缓冲区起始地址是Y等等
  • 由此可见,当使用的端点数量比较多时,信息记录区索要的空间就比较大,反之,就小,需要动态调整
  • 由大佬的帖子可知,记录一个端点的起始地址信息需要8字节,那么我们五个CDC,则5x2(IN,OUT)=10,再加上0x80 ,0x00端点,一共12个.则12*8=76字节
  • 因此,端点(0x00)分配的地址需要往后偏移,默认的不行,如这次需要76字节的大小,换成16进制,0x4C,我设置了0x70>0x4C,默认的太小了,会导致部分信息记录区被端点0的数据覆盖,而导致部分端点无法使用.


4.修改USB初始化代码,新增对新端点的初始化

  1. static uint8_t  USBD_CDC_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
  2. {
  3.   uint8_t ret = 0U;
  4.   USBD_CDC_HandleTypeDef   *hcdc;

  5.   if (pdev->dev_speed == USBD_SPEED_HIGH)
  6.   {
  7.     /* Open EP IN */
  8.     USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK,
  9.                    CDC_DATA_HS_IN_PACKET_SIZE);

  10.     pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;

  11.     /* Open EP OUT */
  12.     USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,
  13.                    CDC_DATA_HS_OUT_PACKET_SIZE);

  14.     pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;

  15.   }
  16.   else
  17.   {
  18.     /* Open EP IN */
  19.      USBD_LL_OpenEP(pdev, CDC_IN_EP, USBD_EP_TYPE_BULK,
  20.                    CDC_DATA_FS_IN_PACKET_SIZE);

  21.      pdev->ep_in[CDC_IN_EP & 0xFU].is_used = 1U;

  22.     /* Open EP OUT */
  23.      USBD_LL_OpenEP(pdev, CDC_OUT_EP, USBD_EP_TYPE_BULK,
  24.                    CDC_DATA_FS_OUT_PACKET_SIZE);

  25.      pdev->ep_out[CDC_OUT_EP & 0xFU].is_used = 1U;


  26.         /* Open EP IN */
  27.      USBD_LL_OpenEP(pdev, CDC_IN_EP1, USBD_EP_TYPE_BULK,
  28.                    CDC_DATA_FS_IN_PACKET_SIZE);

  29.      pdev->ep_in[CDC_IN_EP1 & 0xFU].is_used = 1U;

  30.     /* Open EP OUT */
  31.      USBD_LL_OpenEP(pdev, CDC_OUT_EP1, USBD_EP_TYPE_BULK,
  32.                    CDC_DATA_FS_OUT_PACKET_SIZE);

  33.      pdev->ep_out[CDC_OUT_EP1 & 0xFU].is_used = 1U;



  34. //--------------------------------------------------------------------
  35.        /* Open EP IN */
  36.      USBD_LL_OpenEP(pdev, CDC_IN_EP2, USBD_EP_TYPE_BULK,
  37.                    CDC_DATA_FS_IN_PACKET_SIZE);

  38.     pdev->ep_in[CDC_IN_EP2 & 0xFU].is_used = 1U;

  39.     /* Open EP OUT */
  40.     USBD_LL_OpenEP(pdev, CDC_OUT_EP2, USBD_EP_TYPE_BULK,
  41.                    CDC_DATA_FS_OUT_PACKET_SIZE);

  42.     pdev->ep_out[CDC_OUT_EP2 & 0xFU].is_used = 1U;


  43.    //-------------------------5---------------------
  44.            /* Open EP IN */
  45.     USBD_LL_OpenEP(pdev, CDC_IN_EP3, USBD_EP_TYPE_BULK,
  46.                    CDC_DATA_FS_IN_PACKET_SIZE);

  47.     pdev->ep_in[CDC_IN_EP3 & 0xFU].is_used = 1U;

  48.     /* Open EP OUT */
  49.     USBD_LL_OpenEP(pdev, CDC_OUT_EP3, USBD_EP_TYPE_BULK,
  50.                    CDC_DATA_FS_OUT_PACKET_SIZE);

  51.     pdev->ep_out[CDC_OUT_EP3 & 0xFU].is_used = 1U;

  52.     //-------------------------5---------------------

  53.            /* Open EP IN */
  54.     USBD_LL_OpenEP(pdev, CDC_IN_EP4, USBD_EP_TYPE_BULK,
  55.                    CDC_DATA_FS_IN_PACKET_SIZE);

  56.     pdev->ep_in[CDC_IN_EP4 & 0xFU].is_used = 1U;

  57.     /* Open EP OUT */
  58.     USBD_LL_OpenEP(pdev, CDC_OUT_EP4, USBD_EP_TYPE_BULK,
  59.                    CDC_DATA_FS_OUT_PACKET_SIZE);

  60.     pdev->ep_out[CDC_OUT_EP4 & 0xFU].is_used = 1U;

  61.   }
  62.   /* Open Command IN EP *///控制端口无效,不要取消注释
  63. //  USBD_LL_OpenEP(pdev, CDC_CMD_EP, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
  64. //  pdev->ep_in[CDC_CMD_EP & 0xFU].is_used = 1U;


  65. //   USBD_LL_OpenEP(pdev, CDC_CMD_EP1, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
  66. //   pdev->ep_in[CDC_CMD_EP1 & 0xFU].is_used = 1U;


  67. //     USBD_LL_OpenEP(pdev, CDC_CMD_EP2, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
  68. //   pdev->ep_in[CDC_CMD_EP2 & 0xFU].is_used = 1U;


  69.   //   USBD_LL_OpenEP(pdev, CDC_CMD_EP3, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);
  70.   // pdev->ep_in[CDC_CMD_EP3 & 0xFU].is_used = 1U;

  71.   pdev->pClassData = USBD_malloc(sizeof(USBD_CDC_HandleTypeDef));

  72.   if (pdev->pClassData == NULL)
  73.   {
  74.     ret = 1U;
  75.   }
  76.   else
  77.   {
  78.     hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;

  79.     /* Init  physical Interface components */
  80.     ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Init();

  81.     /* Init Xfer states */
  82.     hcdc->TxState = 0U;
  83.     hcdc->RxState = 0U;

  84.     if (pdev->dev_speed == USBD_SPEED_HIGH)
  85.     {
  86.       /* Prepare Out endpoint to receive next packet */
  87.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer,
  88.                              CDC_DATA_HS_OUT_PACKET_SIZE);
  89.     }
  90.     else
  91.     {
  92.       /* Prepare Out endpoint to receive next packet */
  93.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP, hcdc->RxBuffer,
  94.                              CDC_DATA_FS_OUT_PACKET_SIZE);

  95.                                    /* Prepare Out endpoint to receive next packet */
  96.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP1, hcdc->RxBuffer,
  97.                              CDC_DATA_FS_OUT_PACKET_SIZE);

  98.                                    /* Prepare Out endpoint to receive next packet */
  99.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP2, hcdc->RxBuffer,
  100.                              CDC_DATA_FS_OUT_PACKET_SIZE);

  101.                                    /* Prepare Out endpoint to receive next packet */
  102.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP3, hcdc->RxBuffer,
  103.                              CDC_DATA_FS_OUT_PACKET_SIZE);

  104.                                                              /* Prepare Out endpoint to receive next packet */
  105.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP4, hcdc->RxBuffer,
  106.                              CDC_DATA_FS_OUT_PACKET_SIZE);

  107.       USBD_LL_PrepareReceive(pdev, CDC_OUT_EP5, hcdc->RxBuffer,
  108.                             CDC_DATA_FS_OUT_PACKET_SIZE);
  109.     }
  110.   }
  111.   return ret;
  112. }
复制代码


5.修改HAL默认USB CDC相关接口函数
  • 现在是多CDC的状况了,但默认的HAL库的函数均只是针对一个CDC的情况,我们需要将端口的参数引出来
  • USBD_CDC_DataOut:USB接收函数回调,修改提供端口参数
  • CDC_Receive_FS(uint8_t *Buf, uint32_t *Len):USB CDC接收函数
  • CDC_Transmit_FS(uint8_t* Buf, uint16_t Len):USB CDC发送函数
  • USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
  • USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev)

  • 先说说这几个函数的关系:CDC_Transmit_FS---调用--->USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
  • USBD_CDC_DataOut(数据接收回调)---调用--->CDC_Receive_FS

CDC_Receive_FS(uint8_t *Buf, uint32_t *Len)修改为CDC_Receive_FS(uint8_t* Buf, uint32_t *Len,uint8_t epnum): 此后所有OUT端点来的数据都将进入此函数,可通过参数epnum区分

  1. static uint8_t  USBD_CDC_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
  2. {
  3.   USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;

  4.   /* Get the received data length */
  5.   hcdc->RxLength = USBD_LL_GetRxDataSize(pdev, epnum);
  6.   /* USB data will be immediately processed, this allow next USB traffic being
  7.   NAKed till the end of the application Xfer */
  8.   // printf("USBD_CDC_DataOut.1294:Len:%d :EP:%02X\n",hcdc->RxLength,epnum);
  9.   if (pdev->pClassData != NULL)
  10.   {
  11.     ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength,epnum);//此处修改,加入端点,相关的函数声明也跟这这样改
  12.     return USBD_OK;
  13.   }

  14.   else
  15.   {
  16.     return USBD_FAIL;
  17.   }
  18. }
复制代码


  • CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)该为CDC_Transmit_FS(uint8_t* Buf, uint16_t Len,uint8_t epnum):只是增加一个参数,函数体不用动


  1. uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len,uint8_t epnum)
  2. {
  3.   uint8_t result = USBD_OK;
  4.   /* USER CODE BEGIN 7 */
  5.   USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS_CDC.pClassData;
  6.   if (hcdc->TxState != 0){
  7.     return USBD_BUSY;
  8.   }
  9.   USBD_CDC_SetTxBuffer(&hUsbDeviceFS_CDC, Buf, Len);
  10.   result = USBD_CDC_TransmitPacket(&hUsbDeviceFS_CDC,epnum);    //将epnum的端点传到这个函数,这个函数也需要改
  11.   /* USER CODE END 7 */
  12.   return result;
  13. }
复制代码


  • USBD_CDC_TransmitPacket的修改
  1. uint8_t  USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev,uint8_t epnum)
  2. {
  3.   USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;

  4.   if (pdev->pClassData != NULL)
  5.   {
  6.     if (hcdc->TxState == 0U)
  7.     {
  8.       /* Tx Transfer in progress */
  9.       hcdc->TxState = 1U;

  10.       /* Update the packet total length */
  11.       pdev->ep_in[epnum & 0xFU].total_length = hcdc->TxLength;//将原本的CDC_IN_EP更改为我们传入的端点
  12.       /* Transmit next packet */
  13.       USBD_LL_Transmit(pdev, epnum, hcdc->TxBuffer,
  14.                        (uint16_t)hcdc->TxLength);//此处也是

  15.       return USBD_OK;
  16.     }
  17.     else
  18.     {
  19.       return USBD_BUSY;
  20.     }
  21.   }
  22.   else
  23.   {
  24.     return USBD_FAIL;
  25.   }
  26. }
复制代码



该函数的作用:当端口接收一包数据后,需要执行此函数来接收下一包数据,简单的说:告诉主机我可以接收下一包数据了

  1. uint8_t  USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev,uint8_t epnum)
  2. {
  3.   USBD_CDC_HandleTypeDef   *hcdc = (USBD_CDC_HandleTypeDef *) pdev->pClassData;

  4.   /* Suspend or Resume USB Out process */
  5.   if (pdev->pClassData != NULL)
  6.   {
  7.     if (pdev->dev_speed == USBD_SPEED_HIGH)
  8.     {
  9.       /* Prepare Out endpoint to receive next packet */
  10.       USBD_LL_PrepareReceive(pdev,
  11.                              CDC_OUT_EP,
  12.                              hcdc->RxBuffer,
  13.                              CDC_DATA_HS_OUT_PACKET_SIZE);
  14.     }
  15.     else
  16.     {
  17.       /* Prepare Out endpoint to receive next packet */
  18.       USBD_LL_PrepareReceive(pdev,
  19.                              epnum,
  20.                              hcdc->RxBuffer,
  21.                              CDC_DATA_FS_OUT_PACKET_SIZE);
  22.     }
  23.     return USBD_OK;
  24.   }
  25.   else
  26.   {
  27.     return USBD_FAIL;
  28.   }
  29. }
复制代码

对以后而言,我们就使用CDC_Receive_FS(uint8_t* Buf, uint32_t *Len,uint8_t epnum)和CDC_Transmit_FS(uint8_t* Buf, uint16_t Len,uint8_t epnum) 向CDCx发送数据,就填写CDCx的IN端口 * 接收CDCx数据时,CDC_Receive_FS函数会传入该数据来源(OUT)端口,就可知道哪个CDCx了

6.后续
  • 此时就完成了,不过不排除有些深层的问题。
  • 如:当五个CDC同时在Read时,其中一个close,有可能会导致其他四个都无法再Read出数据,需要重新Open,但在电脑的深度depin系统上并没有这个问题,在项目中的板子上就有,希望大佬们提供下线索。感激不尽


转载自:casojie
收藏 评论0 发布时间:2023-1-3 19:55

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版