其实很简单搞了好久,怪ST呗,既没做到可读性增强,又搞到复杂了.目的先做一个CDC+MSC复合,就像STLink V2-1一样.
首先生成一个CDC工程并测试.


再用同样方法生成MSC,但是不要覆盖当前工程.因为木有分区和很多逻辑没实现,所以借助工具看看.

开始合并了,把CDC内容挪过来.



新建两个文件.


添加文件到Keil.

Keil的Include还要设置.然后编译测试,当然这个时候是不能用的.

修改CDC所用EP.

修改MSC所用EP.

编辑我们的复合头文件.复合用IAD.大概都是写在一起.
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_COMPOSITE_H
#define __USBD_COMPOSITE_H
#ifdef __cplusplus
 extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include  "usbd_msc.h"
#include  "usbd_cdc.h"
#include "usbd_storage_if.h"
#include "usbd_cdc_if.h"
#define WBVAL(x) (x & 0xFF),((x >> 8) & 0xFF)
#define DBVAL(x) (x & 0xFF),((x >> 8) & 0xFF),((x >> 16) & 0xFF),((x >> 24) & 0xFF)
#define USBD_IAD_DESC_SIZE           0x08
#define USBD_IAD_DESCRIPTOR_TYPE     0x0B
#define USBD_CDC_FIRST_INTERFACE     0          /* CDC FirstInterface */
#define USBD_CDC_INTERFACE_NUM       2          /* CDC Interface NUM */
#define USBD_CDC_CMD_INTERFACE       0
#define USBD_CDC_DATA_INTERFACE      1
#define USBD_MSC_FIRST_INTERFACE     2          /* MSC FirstInterface */
#define USBD_MSC_INTERFACE_NUM       1          /* MSC Interface NUM */
#define USBD_MSC_INTERFACE           2
#define MSC_INDATA_NUM              (MSC_EPIN_ADDR & 0x0F)
#define MSC_OUTDATA_NUM             (MSC_EPOUT_ADDR & 0x0F)
#define CDC_INDATA_NUM              (CDC_IN_EP & 0x0F)
#define CDC_OUTDATA_NUM             (CDC_OUT_EP & 0x0F)
#define CDC_OUTCMD_NUM              (CDC_CMD_EP & 0x0F)
#define USBD_COMPOSITE_DESC_SIZE    (9  + 58 + 8 +  32 + 8)
extern USBD_ClassTypeDef    USBD_COMPOSITE;
/**
  * @}
  */
/**
  * @}
  */
#ifdef __cplusplus
}
#endif
#endif  /* __USBD_MSC_H */
/**
  * @}
  */
/*****************************END OF FILE****/
然后写对应C文件,分别初始化各种.
#include "usbd_composite.h"
#include "usbd_cdc.h"
#include "usbd_msc.h"
static USBD_CDC_HandleTypeDef *pCDCData;
static USBD_MSC_BOT_HandleTypeDef *pMSCData;
static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev,
                            uint8_t cfgidx);
static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev,
                              uint8_t cfgidx);
static uint8_t  USBD_Composite_EP0_RxReady(USBD_HandleTypeDef *pdev);
static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev,
                             USBD_SetupReqTypedef *req);
static uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev,
                              uint8_t epnum);
static uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev,
                               uint8_t epnum);
static uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length);
static uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);
USBD_ClassTypeDef  USBD_COMPOSITE =
{
  USBD_Composite_Init,
  USBD_Composite_DeInit,
  USBD_Composite_Setup,
  NULL, /*EP0_TxSent*/
  USBD_Composite_EP0_RxReady,
  USBD_Composite_DataIn,
  USBD_Composite_DataOut,
  NULL,
  NULL,
  NULL,
  NULL,
  USBD_Composite_GetFSCfgDesc,
  NULL,
  USBD_Composite_GetDeviceQualifierDescriptor,
};
/* USB composite device Configuration Descriptor */
/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
__ALIGN_BEGIN uint8_t USBD_Composite_CfgFSDesc[USBD_COMPOSITE_DESC_SIZE]  __ALIGN_END =
{
  0x09,   /* bLength: Configuation Descriptor size */
  USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */
  WBVAL(USBD_COMPOSITE_DESC_SIZE),
  USBD_MAX_NUM_INTERFACES ,  /* bNumInterfaces: */
  0x01,   /* bConfigurationValue: */
  0x04,   /* iConfiguration: */
  0xC0,   /* bmAttributes: */
  0x96,   /* MaxPower 300 mA */
  /****************************CDC************************************/
  /* Interface Association Descriptor */
  USBD_IAD_DESC_SIZE,               // bLength
  USBD_IAD_DESCRIPTOR_TYPE,         // bDescriptorType
  USBD_CDC_FIRST_INTERFACE,         // bFirstInterface
  USBD_CDC_INTERFACE_NUM,           // bInterfaceCount
  0x02,                             // bFunctionClass
  0x02,                             // bFunctionSubClass
  0x01,                             // bInterfaceProtocol
  0x04,                             // iFunction
  /*Interface Descriptor */
  0x09,   /* bLength: Interface Descriptor size */
  USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: Interface */
  /* Interface descriptor type */
  USBD_CDC_CMD_INTERFACE,   /* bInterfaceNumber: Number of Interface */
  0x00,   /* bAlternateSetting: Alternate setting */
  0x01,   /* bNumEndpoints: One endpoints used */
  0x02,   /* bInterfaceClass: Communication Interface Class */
  0x02,   /* bInterfaceSubClass: Abstract Control Model */
  0x01,   /* bInterfaceProtocol: Common AT commands */
  0x01,   /* iInterface: */
  /*Header Functional Descriptor*/
  0x05,   /* bLength: Endpoint Descriptor size */
  0x24,   /* bDescriptorType: CS_INTERFACE */
  0x00,   /* bDescriptorSubtype: Header Func Desc */
  0x10,   /* bcdCDC: spec release number */
  0x01,
  /*Call Management Functional Descriptor*/
  0x05,   /* bFunctionLength */
  0x24,   /* bDescriptorType: CS_INTERFACE */
  0x01,   /* bDescriptorSubtype: Call Management Func Desc */
  0x00,   /* bmCapabilities: D0+D1 */
  0x01,   /* bDataInterface: 1 */
  /*ACM Functional Descriptor*/
  0x04,   /* bFunctionLength */
  0x24,   /* bDescriptorType: CS_INTERFACE */
  0x02,   /* bDescriptorSubtype: Abstract Control Management desc */
  0x02,   /* bmCapabilities */
  /*Union Functional Descriptor*/
  0x05,   /* bFunctionLength */
  0x24,   /* bDescriptorType: CS_INTERFACE */
  0x06,   /* bDescriptorSubtype: Union func desc */
  USBD_CDC_CMD_INTERFACE,   /* bMasterInterface: Communication class interface */
  USBD_CDC_DATA_INTERFACE,   /* bSlaveInterface0: Data Class Interface */
  /*Endpoint 2 Descriptor*/
  0x07,                           /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_ENDPOINT,   /* bDescriptorType: Endpoint */
  CDC_CMD_EP,                     /* bEndpointAddress */
  0x03,                           /* bmAttributes: Interrupt */
  LOBYTE(CDC_CMD_PACKET_SIZE),     /* wMaxPacketSize: */
  HIBYTE(CDC_CMD_PACKET_SIZE),
  0x01,                           /* bInterval: */
  /*Data class interface descriptor*/
  0x09,   /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
  USBD_CDC_DATA_INTERFACE,   /* bInterfaceNumber: Number of Interface */
  0x00,   /* bAlternateSetting: Alternate setting */
  0x02,   /* bNumEndpoints: Two endpoints used */
  0x0A,   /* bInterfaceClass: CDC */
  0x02,   /* bInterfaceSubClass: */
  0x00,   /* bInterfaceProtocol: */
  0x01,   /* iInterface: */
  /*Endpoint OUT Descriptor*/
  0x07,   /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  CDC_OUT_EP,                        /* bEndpointAddress */
  0x02,                              /* bmAttributes: Bulk */
  LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  0x01,                              /* bInterval: ignore for Bulk transfer */
  /*Endpoint IN Descriptor*/
  0x07,   /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */
  CDC_IN_EP,                         /* bEndpointAddress */
  0x02,                              /* bmAttributes: Bulk */
  LOBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */
  HIBYTE(CDC_DATA_FS_MAX_PACKET_SIZE),
  0x01,                               /* bInterval: ignore for Bulk transfer */
 /****************************MSC************************************/
  /* Interface Association Descriptor */
  USBD_IAD_DESC_SIZE,                        // bLength
  USBD_IAD_DESCRIPTOR_TYPE,                  // bDescriptorType
  USBD_MSC_FIRST_INTERFACE,                  // bFirstInterface
  USBD_MSC_INTERFACE_NUM,                    // bInterfaceCount
  0x08,                                      // bFunctionClass
  0x06,                                      // bFunctionSubClass
  0x50,                                      // bInterfaceProtocol
  0x05,
  /********************  Mass Storage interface ********************/
  0x09,   /* bLength: Interface Descriptor size */
  USB_DESC_TYPE_INTERFACE,   /* bDescriptorType: */
  USBD_MSC_INTERFACE,   /* bInterfaceNumber: Number of Interface */
  0x00,   /* bAlternateSetting: Alternate setting */
  0x02,   /* bNumEndpoints*/
  0x08,   /* bInterfaceClass: MSC Class */
  0x06,   /* bInterfaceSubClass : SCSI transparent*/
  0x50,   /* nInterfaceProtocol */
  0x05,          /* iInterface: */
  /********************  Mass Storage Endpoints ********************/
  0x07,   /*Endpoint descriptor length = 7*/
  0x05,   /*Endpoint descriptor type */
  MSC_EPIN_ADDR,   /*Endpoint address (IN, address 1) */
  0x02,   /*Bulk endpoint type */
  LOBYTE(MSC_MAX_FS_PACKET),
  HIBYTE(MSC_MAX_FS_PACKET),
  0x01,   /*Polling interval in milliseconds */
  0x07,   /*Endpoint descriptor length = 7 */
  0x05,   /*Endpoint descriptor type */
  MSC_EPOUT_ADDR,   /*Endpoint address (OUT, address 1) */
  0x02,   /*Bulk endpoint type */
  LOBYTE(MSC_MAX_FS_PACKET),
  HIBYTE(MSC_MAX_FS_PACKET),
  0x01,     /*Polling interval in milliseconds*/
};
/* USB Standard Device Descriptor */
__ALIGN_BEGIN  uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC]  __ALIGN_END =
{
  USB_LEN_DEV_QUALIFIER_DESC,
  USB_DESC_TYPE_DEVICE_QUALIFIER,
  0x00,
  0x02,
  0x00,
  0x00,
  0x00,
  0x40,
  0x01,
  0x00,
};
/**
  * @brief  USBD_Composite_Init
  *         Initialize the Composite interface
  * @param  pdev: device instance
  * @param  cfgidx: Configuration index
  * @retval status
  */
static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev,
                            uint8_t cfgidx)
{
  uint8_t res = 0;
  pdev->pUserData =  &USBD_CDC_Interface_fops_FS;
  res +=  USBD_CDC.Init(pdev,cfgidx);
  pCDCData = pdev->pClassData;
  pdev->pUserData = &USBD_Storage_Interface_fops_FS;
  res +=  USBD_MSC.Init(pdev,cfgidx);
  pMSCData = pdev->pClassData;
  return res;
}
/**
  * @brief  USBD_Composite_DeInit
  *         DeInitilaize  the Composite configuration
  * @param  pdev: device instance
  * @param  cfgidx: configuration index
  * @retval status
  */
static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev,
                              uint8_t cfgidx)
{
    uint8_t res = 0;
    pdev->pClassData = pCDCData;
    pdev->pUserData = &USBD_CDC_Interface_fops_FS;
    res +=  USBD_CDC.DeInit(pdev,cfgidx);
    pdev->pClassData = pMSCData;
    pdev->pUserData = &USBD_Storage_Interface_fops_FS;
    res +=  USBD_MSC.DeInit(pdev,cfgidx);
    return res;
}
static uint8_t  USBD_Composite_EP0_RxReady(USBD_HandleTypeDef *pdev)
{
    return USBD_CDC.EP0_RxReady(pdev);
}
/**
* @brief  USBD_Composite_Setup
*         Handle the Composite requests
* @param  pdev: device instance
* @param  req: USB request
* @retval status
*/
static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
  switch (req->bmRequest & USB_REQ_RECIPIENT_MASK)
  {
   case USB_REQ_RECIPIENT_INTERFACE:
     switch(req->wIndex)
      {
         case USBD_CDC_DATA_INTERFACE:
         case USBD_CDC_CMD_INTERFACE:
             pdev->pClassData = pCDCData;
             pdev->pUserData =  &USBD_CDC_Interface_fops_FS;
           return(USBD_CDC.Setup(pdev, req));
         case USBD_MSC_INTERFACE:
             pdev->pClassData = pMSCData;
             pdev->pUserData =  &USBD_Storage_Interface_fops_FS;
           return(USBD_MSC.Setup (pdev, req));
         default:
            break;
     }
     break;
   case USB_REQ_RECIPIENT_ENDPOINT:
     switch(req->wIndex)
     {
         case CDC_IN_EP:
         case CDC_OUT_EP:
         case CDC_CMD_EP:
             pdev->pClassData = pCDCData;
             pdev->pUserData =  &USBD_CDC_Interface_fops_FS;
           return(USBD_CDC.Setup(pdev, req));
         case MSC_EPIN_ADDR:
         case MSC_EPOUT_ADDR:
             pdev->pClassData = pMSCData;
             pdev->pUserData =  &USBD_Storage_Interface_fops_FS;
           return(USBD_MSC.Setup (pdev, req));
         default:
            break;
     }
     break;
  }
  return USBD_OK;
}
/**
* @brief  USBD_Composite_DataIn
*         handle data IN Stage
* @param  pdev: device instance
* @param  epnum: endpoint index
* @retval status
*/
uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev,
                              uint8_t epnum)
{
  switch(epnum)
  {
      case CDC_INDATA_NUM:
        pdev->pClassData = pCDCData;
        pdev->pUserData =  &USBD_CDC_Interface_fops_FS;
         return(USBD_CDC.DataIn(pdev,epnum));
      case MSC_INDATA_NUM:
             pdev->pClassData = pMSCData;
             pdev->pUserData =  &USBD_Storage_Interface_fops_FS;
         return(USBD_MSC.DataIn(pdev,epnum));
      default:
         break;
  }
  return USBD_FAIL;
}
/**
* @brief  USBD_Composite_DataOut
*         handle data OUT Stage
* @param  pdev: device instance
* @param  epnum: endpoint index
* @retval status
*/
uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev,
                               uint8_t epnum)
{
  switch(epnum)
  {
      case CDC_OUTDATA_NUM:
      case CDC_OUTCMD_NUM:
        pdev->pClassData = pCDCData;
        pdev->pUserData =  &USBD_CDC_Interface_fops_FS;
         return(USBD_CDC.DataOut(pdev,epnum));
      case MSC_OUTDATA_NUM:
             pdev->pClassData = pMSCData;
             pdev->pUserData =  &USBD_Storage_Interface_fops_FS;
         return(USBD_MSC.DataOut(pdev,epnum));
      default:
         break;
  }
  return USBD_FAIL;
}
/**
* @brief  USBD_Composite_GetHSCfgDesc
*         return configuration descriptor
* @param  length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length)
{
   *length = sizeof (USBD_Composite_CfgFSDesc);
   return USBD_Composite_CfgFSDesc;
}
/**
* @brief  DeviceQualifierDescriptor
*         return Device Qualifier descriptor
* @param  length : pointer data length
* @retval pointer to descriptor buffer
*/
uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length)
{
  *length = sizeof (USBD_Composite_DeviceQualifierDesc);
  return USBD_Composite_DeviceQualifierDesc;
}
/**
  * @}
  */
/**
  * @}
  */
/**
  * @}
  */
然后CDC的描述太任性了,改.


不然看文件吗根本不知道是什么玩意.接着修改usb_device.c


修改最大接口数.

因为是CDC 2个 + MSC 1个.然后如果还没有识别,修改Stack Size.

修改为IAD兼容.

复合成功:

程序:
后话:
如果电脑没驱动,请求助官网:http://www.st.com/en/development-tools/stsw-stm32102.html
思考:
如何复合多重HID呢?复合只是为了增加功能,并不能增加带宽.
我这边试过了,composite hid可以增加带宽的,最后做出来有几个interface就有几倍的速度
@cnnblike 总带宽是不变的,只能说你的HID发送的数据吃不满总带宽。
@cnnblike 想探究一下带宽,做UVC协议最清楚了。
@TaterLi 没说能提升总带宽,hid composite的优势就是任何环境都能都能免驱动,加上中断类usb端点的可保证总是最优先,做一些设备肥肠方便。
如果是stm32的话最多可以做到in endpoint 64+8+8+8=96kB/s,out endpoint 64+64+64+64=256kB/s,当然可以做in和out之间的分配的,352kBs的总带宽,差不多2.8Mb/s的速度,和usb1.1设备的带宽上限12Mb当然有差距,但是多平台包括windows,linux,macos,android,都能免驱只需要业务代码不需要kernel mode的优点还是不容抹杀的。
如果能换个arm m3芯片,pma能大点的话,最高理论上能做到512kB进,512kB出,加起来差不多8Mbps了,和理论带宽上限的差距就非常小了,可以说这个方法的前途很光明。
@cnnblike 认同,做UVC模式可以做到7Mbit左右,测试.
@cnnblike 直接用块传输就可以了
@cnnblike 中断传输USB协议限制了每次可连续传输的字节数
你好,请教一下
1.然后CDC的描述太任性了,改.这个地方到底改了哪里?是指名字改了?
2.不然看文件吗根本不知道是什么玩意.接着修改usb_device.c,这里也没看懂,仅仅是注释掉一行代码吗?
其他地方我都已经结合你的提示和根据我自己的设备进行修改了,现在的情况是完全枚举不了,还望大神帮忙提示提示
@嘉禾 下面还有程序下载
@TaterLi 非常感谢大神!!!!,HID+CDC复合成功了stm32f103,
@无名小虾 能发给我吗?我最近刚好需要用到,我QQ邮箱276642088@qq.COM
@TaterLi 我cpu是stm32f303cct6,修改后可以正确识别USB composite deivce,USB大容量存储设备,USB串口设备,但没有磁盘驱动器设备,能将你成功的程序发我吗?程序下载不了。我的邮箱:zhxzsh@msn.com
@zhxzsh 实现了BULK的读写底层数据没,如果没有,只能识别一个空储存设备.
@TaterLi CDC工程和MSC工程都市单独调试好的,虚拟串口收发数据正常,U盘读写文件正常,按上面的方法整合之后,在【通用串行总线控制器】下面有 Usb Composite Device和USB大容量存储器,在【端口】下有USB串行设备COM7,没有感叹号,但是没有盘符显示,空的都没有,串口也打开失败
@chzfmx 盘符当然不会有,因为他都没有文件系统,需要额外用实现,这和USB没关系了,串口也要自己另外逻辑实现,不然打开关闭的操作单片机上也要对应个串口或者其他设备嘛,这也和USB就没关系了.
@zhxzsh 我也是,没有磁盘设备,有串口号,但打不开
您好,按照您的思路,我复合STM32F407VET6单片机的CDC+MSC设备,能成功枚举 出来串口和U盘,且功能测试都是ok的,但是我在main函数里通过cdc发送函数,发送字符串“12345”测试串口功能时,当电脑上串口助手收到200个字节左右的数据后,再收到的数据就是乱码,再然后设备就死掉了,电脑上设备管理器就找不到设备了。
移植找不到原因在哪里,能麻烦你给指点一下吗???
很不要脸的问一句,能共享下你复合成功的例程吗
您的博客地址哪里,新浪的我带不开这个界面上的
@费猿人 文章末尾就有下载啊.就是这个啊.
@TaterLi 您好!我一直在调试这个复合设备,但是一直没有成功,你的下载地址我也一直没有找到,能否给我下载地址!非常感谢!!!
我用spi 接口的flash作为存储介质,参考您的教程,成功复合出复合设备,但是U盘的读写速度挺慢,不知道是什么原因,而且从电脑上向U盘拖东西,刚开始卡顿,延迟很长时间才开始传输数据,求大神给指点一下。
@费猿人 SPI Flash的速度本来就不快啊.而且再快,也就USB1.1的极限速度.
您的主页打不开了怎么
你好,我今天用stm32想实现CDC和自定义HID,老是不成功,单类可以。复合后就不可以。邮箱1633662870@qq.com。能麻烦发一份你的源码看一下吗?
@叶 文中下载链接已修复.
站长您好!我调试这个复合设备已经一周了,还是没有成功,您说的源码下载地址我一直没有找到, 能否提供一个下载地址,多谢!
不好意思,看到了,已经下载了,多谢!!
您好!STM32 USB可以同时用作CDC和DFU吗?可否出一份教程,谢谢啦!
@Bruce 任何复合都是一个道理,你先用这个练手试试.
感谢分享,正好一个项目有此需求,学习一下。
在205上 只出现了个 大容量移动设备,CDC没有出现 .不知道错哪
@杨飞云 USBlyzer分析一下
站长您好!我调试这个cdc十msc已1周了,未果,能否发个您的成功案例参考下,万分感谢!
@朱生 下载链接就在本文最下面啊.
你好,链接失效了呢
@qkhhyu 修复了
站长您好!我按照你的教程调试很久了,也下载到了你的工程,复制了你的composite.c和composite.h这两个文件,我用的MCU是F429IGT6,初始化遇到硬件错误,完全没有头绪,期望得到您的帮助,万分感谢。
@贺东胜 是不是4系列和7系列有什么不同的地方,不能共用这两个文件,我完全没有头绪,也没办法理解其中的含义。
期望得到你的回复
感谢博主和几位!根据博主的例程,已经移植成功HID+CDC.提醒后面同学要注意,usbd_conf.c里面的HAL_PCDEx_SetTxFiFo函数要设置你后面新增的端点的FIFO,默认情况下只有俩端点,一定要加!
[…] 使用STM32CubeMX编写USB复合设备 […]