stm32H747基于HAL库实现USB复合功能CDC+MSC

背景:最近项目需要做一个基于USB的复合设备,实现usb转串口和U盘的功能,其中遇到些许问题,记录一下,此项目是基于stm32H747实现,其实不同芯片系列的方式都一样,大家可参考使用,不详之处,可联系补充。

        文章主要分三部分展开,先实现CDC功能,在实现MSC功能,最后实现CDC+MSC功能。具有参考意义的文章会在最后端列出连接。

1、搭建环境

主芯片:stm32H747,使用M7核。

代码编译:STM32CubeIDE,也可以使用keil编译,两者就时添加源码和头文件时需要注意。

HAL库版本:可采用最新版本。

代码生成工具:CubeMX

2、USB接口实现CDC(usb转串口功能)

 2.1 打开cubeMX,选择主控芯片为stm32H747系列,如下图:使能RCC的高速时钟

2.2 在connectivity中勾选USB_OTG_FS,模式选择为设备模式

2.3 在Middleware and Software Packs中配置usb设备虚拟串口

注:默认全局中断是被打开的,usb引脚也是默认的,如果与实际不符,可根据实际修改。

2.4 时钟配置

主频可以随意配置,USB的时钟选择最方便的RC48,如果想选择PLLQ1或者PLLQ3可以根据实际调整,但是最好都配置成48MHz。

2.5 代码生成

注意交叉编译工具的选择,最下面是我本人使用的HAL库版本

可以在通用代码设置中,把.h和.c文件夹区分开,也可不区分,根据个人爱好选择。

2.6 点击生成代码即可

使用IDE打开,导入生成的工程,结构如下。CDC我们需要修改的代码在应用代码中,usb转串口的接收和发送函数,以及配置函数在usbd_cdc_if.c当中。

2.7,修改代码使用

代开usbd_cdc_if.c这个文件,其中有一个static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)函数,这个函数是配置波特率等串口参数的的,可以在CDC_GET_LINE_CODING分支下添加如下代码:

pbuf[0] = (uint8_t)(115200);
pbuf[1] = (uint8_t)(115200 >> 8);
pbuf[2] = (uint8_t)(115200 >> 16);
pbuf[3] = (uint8_t)(115200 >> 24);
pbuf[4] = 0;  // stop bits (1)
pbuf[5] = 0;  // parity (none)
pbuf[6] = 8;  // number of bits (8)

在static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)函数中添加CDC_Transmit_FS(Buf, *Len);这句代码,意在回环,这个函数是usb转串口的接收函数,添加的代码是usb转串口的发送函数,目的是把接收的数据返回回去,测试使用,实际可根据自己想法修改。修改后的整体代码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : usbd_cdc_if.c
  * @version        : v1.0_Cube
  * @brief          : Usb device for Virtual Com Port.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "usbd_cdc_if.h"

/* USER CODE BEGIN INCLUDE */

/* USER CODE END INCLUDE */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
  * @brief Usb device library.
  * @{
  */

/** @addtogroup USBD_CDC_IF
  * @{
  */

/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions
  * @brief Private types.
  * @{
  */

/* USER CODE BEGIN PRIVATE_TYPES */

/* USER CODE END PRIVATE_TYPES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines
  * @brief Private defines.
  * @{
  */

/* USER CODE BEGIN PRIVATE_DEFINES */
/* USER CODE END PRIVATE_DEFINES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros
  * @brief Private macros.
  * @{
  */

/* USER CODE BEGIN PRIVATE_MACRO */

/* USER CODE END PRIVATE_MACRO */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables
  * @brief Private variables.
  * @{
  */
/* Create buffer for reception and transmission           */
/* It's up to user to redefine and/or remove those define */
/** Received data over USB are stored in this buffer      */
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];

/** Data to send over USB CDC are stored in this buffer   */
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];

/* USER CODE BEGIN PRIVATE_VARIABLES */

/* USER CODE END PRIVATE_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
  * @brief Public variables.
  * @{
  */

extern USBD_HandleTypeDef hUsbDeviceFS;

/* USER CODE BEGIN EXPORTED_VARIABLES */

/* USER CODE END EXPORTED_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes
  * @brief Private functions declaration.
  * @{
  */

static int8_t CDC_Init_FS(void);
static int8_t CDC_DeInit_FS(void);
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum);

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

/**
  * @}
  */

USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
{
  CDC_Init_FS,
  CDC_DeInit_FS,
  CDC_Control_FS,
  CDC_Receive_FS,
  CDC_TransmitCplt_FS
};

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Initializes the CDC media low layer over the FS USB IP
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_Init_FS(void)
{
  /* USER CODE BEGIN 3 */
  /* Set Application Buffers */
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
  return (USBD_OK);
  /* USER CODE END 3 */
}

/**
  * @brief  DeInitializes the CDC media low layer
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_DeInit_FS(void)
{
  /* USER CODE BEGIN 4 */
  return (USBD_OK);
  /* USER CODE END 4 */
}

/**
  * @brief  Manage the CDC class requests
  * @param  cmd: Command code
  * @param  pbuf: Buffer containing command data (request parameters)
  * @param  length: Number of data to be sent (in bytes)
  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
  /* USER CODE BEGIN 5 */
  switch(cmd)
  {
    case CDC_SEND_ENCAPSULATED_COMMAND:

    break;

    case CDC_GET_ENCAPSULATED_RESPONSE:

    break;

    case CDC_SET_COMM_FEATURE:

    break;

    case CDC_GET_COMM_FEATURE:

    break;

    case CDC_CLEAR_COMM_FEATURE:

    break;

  /*******************************************************************************/
  /* Line Coding Structure                                                       */
  /*-----------------------------------------------------------------------------*/
  /* Offset | Field       | Size | Value  | Description                          */
  /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
  /* 4      | bCharFormat |   1  | Number | Stop bits                            */
  /*                                        0 - 1 Stop bit                       */
  /*                                        1 - 1.5 Stop bits                    */
  /*                                        2 - 2 Stop bits                      */
  /* 5      | bParityType |  1   | Number | Parity                               */
  /*                                        0 - None                             */
  /*                                        1 - Odd                              */
  /*                                        2 - Even                             */
  /*                                        3 - Mark                             */
  /*                                        4 - Space                            */
  /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */
  /*******************************************************************************/
    case CDC_SET_LINE_CODING:

    break;

    case CDC_GET_LINE_CODING:
    	pbuf[0] = (uint8_t)(115200);
    	pbuf[1] = (uint8_t)(115200 >> 8);
    	pbuf[2] = (uint8_t)(115200 >> 16);
    	pbuf[3] = (uint8_t)(115200 >> 24);
    	pbuf[4] = 0;  // stop bits (1)
    	pbuf[5] = 0;  // parity (none)
    	pbuf[6] = 8;  // number of bits (8)
    break;

    case CDC_SET_CONTROL_LINE_STATE:

    break;

    case CDC_SEND_BREAK:

    break;

  default:
    break;
  }

  return (USBD_OK);
  /* USER CODE END 5 */
}

/**
  * @brief  Data received over USB OUT endpoint are sent over CDC interface
  *         through this function.
  *
  *         @note
  *         This function will issue a NAK packet on any OUT packet received on
  *         USB endpoint until exiting this function. If you exit this function
  *         before transfer is complete on CDC interface (ie. using DMA controller)
  *         it will result in receiving more data while previous ones are still
  *         not sent.
  *
  * @param  Buf: Buffer of data to be received
  * @param  Len: Number of data received (in bytes)
  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);

  CDC_Transmit_FS(Buf, *Len);
  return (USBD_OK);
  /* USER CODE END 6 */
}

/**
  * @brief  CDC_Transmit_FS
  *         Data to send over USB IN endpoint are sent over CDC interface
  *         through this function.
  *         @note
  *
  *
  * @param  Buf: Buffer of data to be sent
  * @param  Len: Number of data to be sent (in bytes)
  * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
  */
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if (hcdc->TxState != 0){
    return USBD_BUSY;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
  /* USER CODE END 7 */
  return result;
}

/**
  * @brief  CDC_TransmitCplt_FS
  *         Data transmitted callback
  *
  *         @note
  *         This function is IN transfer complete callback used to inform user that
  *         the submitted Data is successfully sent over USB.
  *
  * @param  Buf: Buffer of data to be received
  * @param  Len: Number of data received (in bytes)
  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 13 */
  UNUSED(Buf);
  UNUSED(Len);
  UNUSED(epnum);
  /* USER CODE END 13 */
  return result;
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

/**
  * @}
  */

/**
  * @}
  */

2.8 编译测试,查看效果

3、USB接口实现MSC(U盘功能)

3.1 打开cubeMX,选择主控芯片为stm32H747系列,如下图:使能RCC的高速时钟

3.2 在connectivity中勾选USB_OTG_FS,模式选择为设备模式

3.3 在Middleware and Software Packs中配置usb设备为大容量存储类

注:默认全局中断是被打开的,usb引脚也是默认的,如果与实际不符,可根据实际修改。

 3.4 时钟配置

主频可以随意配置,USB的时钟选择最方便的RC48,如果想选择PLLQ1或者PLLQ3可以根据实际调整,但是最好都配置成48MHz。

3.5 代码生成

注意交叉编译工具的选择,最下面是我本人使用的HAL库版本

可以在通用代码设置中,把.h和.c文件夹区分开,也可不区分,根据个人爱好选择。

3.6 点击生成代码

3.7,不修改代码的情况下,编译直接烧录代码,电脑端仅可以出来个盘符,但是没有存储读写的共功能,因为没有实现这些接口。如下图。

3.8,实际的U盘功能,根据自己的实际情况实现,这里我仅使用一个数组做个示例,有些人可能使用MCU自身的flash做U盘,有些人可能使用的是spiflash做U盘,但是都可以参照本例程实现,具体是修改usbd_storage_if.c这个文件。

首先新建一个usb_storage.c和usb_storage.h文件在USB_DEVICE/APP/文件夹下,c文件中实现三个函数,初始化、读、写,

usb_storage.c的源码如下

/*
 * usb_storage.c
 *
 *  Created on: 2023年10月19日
 *      Author: pc
 */
#include "usb_storage.h"
#include <string.h>

#define STORAGE_MAX  (100*1024) //100K的一个数组,模拟U盘的大小

uint8_t usb_storage[STORAGE_MAX] = {0};//模拟的U盘实体,大小与

//初始化函数
uint8_t usb_storage_init(void)
{
	memset(usb_storage,0,STORAGE_MAX);
	return 0;
}

//读汉书
uint8_t usb_storage_read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
	memcpy(pBuffer,(void *)(usb_storage + ReadAddr),NumByteToRead);
	return 0;
}

//写函数
uint8_t usb_storage_write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
	memcpy((void *)(usb_storage + WriteAddr),pBuffer,NumByteToWrite);
	return 0;
}

usb_storage.h的源码如下

/*
 * usb_storage.h
 *
 *  Created on: 2023年10月19日
 *      Author: pc
 */

#ifndef APP_USB_STORAGE_H_
#define APP_USB_STORAGE_H_

#include "main.h"


uint8_t usb_storage_init(void);
uint8_t usb_storage_read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);
uint8_t usb_storage_write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);

#endif /* APP_USB_STORAGE_H_ */

usbd_storage_if.c代码中增加代码,主要是初始化,读写的实现,外加u盘大小的获取,

大小的定义主要是这两个宏:和usb_storage.c中定义的大小要匹配起来,

在usbd_conf.h中,修改宏MSC_MEDIA_PACKET的大小和U盘块大小(STORAGE_BLK_SIZ)一致。

usbd_storage_if.c整体的源码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : usbd_storage_if.c
  * @version        : v1.0_Cube
  * @brief          : Memory management layer.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "usbd_storage_if.h"
#include "usb_storage.h"
/* USER CODE BEGIN INCLUDE */

/* USER CODE END INCLUDE */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
  * @brief Usb device.
  * @{
  */

/** @defgroup USBD_STORAGE
  * @brief Usb mass storage device module
  * @{
  */

/** @defgroup USBD_STORAGE_Private_TypesDefinitions
  * @brief Private types.
  * @{
  */

/* USER CODE BEGIN PRIVATE_TYPES */

/* USER CODE END PRIVATE_TYPES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_Defines
  * @brief Private defines.
  * @{
  */

#define STORAGE_LUN_NBR                  1
#define STORAGE_BLK_NBR                  100//0x10000
#define STORAGE_BLK_SIZ                  1024//0x200

/* USER CODE BEGIN PRIVATE_DEFINES */

/* USER CODE END PRIVATE_DEFINES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_Macros
  * @brief Private macros.
  * @{
  */

/* USER CODE BEGIN PRIVATE_MACRO */

/* USER CODE END PRIVATE_MACRO */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_Variables
  * @brief Private variables.
  * @{
  */

/* USER CODE BEGIN INQUIRY_DATA_FS */
/** USB Mass storage Standard Inquiry Data. */
const int8_t STORAGE_Inquirydata_FS[] = {/* 36 */

  /* LUN 0 */
  0x00,
  0x80,
  0x02,
  0x02,
  (STANDARD_INQUIRY_DATA_LEN - 5),
  0x00,
  0x00,
  0x00,
  'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
  'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product      : 16 Bytes */
  ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  '0', '.', '0' ,'1'                      /* Version      : 4 Bytes */
};
/* USER CODE END INQUIRY_DATA_FS */

/* USER CODE BEGIN PRIVATE_VARIABLES */

/* USER CODE END PRIVATE_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Exported_Variables
  * @brief Public variables.
  * @{
  */

extern USBD_HandleTypeDef hUsbDeviceFS;

/* USER CODE BEGIN EXPORTED_VARIABLES */

/* USER CODE END EXPORTED_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_STORAGE_Private_FunctionPrototypes
  * @brief Private functions declaration.
  * @{
  */

static int8_t STORAGE_Init_FS(uint8_t lun);
static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
static int8_t STORAGE_IsReady_FS(uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);
static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS(void);

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

/**
  * @}
  */

USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
{
  STORAGE_Init_FS,
  STORAGE_GetCapacity_FS,
  STORAGE_IsReady_FS,
  STORAGE_IsWriteProtected_FS,
  STORAGE_Read_FS,
  STORAGE_Write_FS,
  STORAGE_GetMaxLun_FS,
  (int8_t *)STORAGE_Inquirydata_FS
};

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Initializes the storage unit (medium) over USB FS IP
  * @param  lun: Logical unit number.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Init_FS(uint8_t lun)
{
  /* USER CODE BEGIN 2 */
 //UNUSED(lun);
	usb_storage_init();
  return (USBD_OK);
  /* USER CODE END 2 */
}

/**
  * @brief  Returns the medium capacity.
  * @param  lun: Logical unit number.
  * @param  block_num: Number of total block number.
  * @param  block_size: Block size.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  /* USER CODE BEGIN 3 */
  //UNUSED(lun);

  *block_num  = STORAGE_BLK_NBR;
  *block_size = STORAGE_BLK_SIZ;
  return (USBD_OK);
  /* USER CODE END 3 */
}

/**
  * @brief   Checks whether the medium is ready.
  * @param  lun:  Logical unit number.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_IsReady_FS(uint8_t lun)
{
  /* USER CODE BEGIN 4 */
  //UNUSED(lun);

  return (USBD_OK);
  /* USER CODE END 4 */
}

/**
  * @brief  Checks whether the medium is write protected.
  * @param  lun: Logical unit number.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{
  /* USER CODE BEGIN 5 */
  //UNUSED(lun);

  return (USBD_OK);
  /* USER CODE END 5 */
}

/**
  * @brief  Reads data from the medium.
  * @param  lun: Logical unit number.
  * @param  buf: data buffer.
  * @param  blk_addr: Logical block address.
  * @param  blk_len: Blocks number.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
//  UNUSED(lun);
//  UNUSED(buf);
//  UNUSED(blk_addr);
//  UNUSED(blk_len);
	usb_storage_read(buf,blk_addr * STORAGE_BLK_SIZ,blk_len*STORAGE_BLK_SIZ);
  return (USBD_OK);
  /* USER CODE END 6 */
}

/**
  * @brief  Writes data into the medium.
  * @param  lun: Logical unit number.
  * @param  buf: data buffer.
  * @param  blk_addr: Logical block address.
  * @param  blk_len: Blocks number.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 7 */
//  UNUSED(lun);
//  UNUSED(buf);
//  UNUSED(blk_addr);
//  UNUSED(blk_len);
	usb_storage_write(buf,blk_addr * STORAGE_BLK_SIZ,blk_len*STORAGE_BLK_SIZ);
  return (USBD_OK);
  /* USER CODE END 7 */
}

/**
  * @brief  Returns the Max Supported LUNs.
  * @param  None
  * @retval Lun(s) number.
  */
int8_t STORAGE_GetMaxLun_FS(void)
{
  /* USER CODE BEGIN 8 */
  return (STORAGE_LUN_NBR - 1);
  /* USER CODE END 8 */
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

/**
  * @}
  */

/**
  * @}
  */

3.9 编译下载到MCU

出现盘符后,第一次需要格式化,大小和容量都与代码中的相匹配

格式化之后的盘符如下,估计有22K默认被占用,可能存放文件表头了,具体不是很清楚为什么只有80K。

至此U盘实验完成

4.USB实现CDC+MSC的功能

4.1 在MSC工程的基础上添加CDC的功能,拷贝cdc文件,新增复合设备的c文件。

cdc文件从cdc的工程中拷贝,仅拷贝usbd_cdc.c、usbd_cdc.h和应用代码usbd_cdc_if.c、usbd_cdc_if.h

新增的复合设备文件为:usbd_composite_builder.c usbd_composite_builder.h,这两个文件可在cubeMX的示例代码中拷贝,然后添加到工程当中,我的cubeMx安装路径在D盘,故这两个文件的路径如下,经供参考:D:\STM32CubeMX\STM32Cube\Repository\STM32Cube_FW_H7_V1.11.0\Middlewares\ST\STM32_USB_Device_Library\Class\CompositeBuilder\Src\usbd_composite_builder.c

需要把新增的文件和头文件路径在工程中添加,避免编译时找不到文件。

4.2 修改复合类设备的代码,即修改usbd_composite_builder.c

添加几个头文件

增加配置描述符,配置描述符这里不再细说,可网上参考配置描述符资料详细学习。其实就是填充USBD_CMPSIT_FSCfgDesc[USBD_CMPST_MAX_CONFDESC_SZ]这个数组。

在h文件中修改配置描述符数组长度的宏为 USBD_CMPST_MAX_CONFDESC_SZ 为106。

整体代码如下:

/**
  ******************************************************************************
  * @file    usbd_composite_builder.c
  * @author  MCD Application Team
  * @brief   This file provides all the composite builder functions.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  * @verbatim
  *
  *          ===================================================================
  *                                Composite Builder  Description
  *          ===================================================================
  *
  *           The composite builder builds the configuration descriptors based on
  *           the selection of classes by user.
  *           It includes all USB Device classes in order to instantiate their
  *           descriptors, but for better management, it is possible to optimize
  *           footprint by removing unused classes. It is possible to do so by
  *           commenting the relative define in usbd_conf.h.
  *
  *  @endverbatim
  *
  ******************************************************************************
  */

/* BSPDependencies
- None
EndBSPDependencies */

/* Includes ------------------------------------------------------------------*/
#include "usbd_composite_builder.h"
#include "usbd_def.h"
#include "usbd_cdc.h"
#include "usbd_msc.h"

#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
#ifdef USE_USBD_COMPOSITE

/** @addtogroup STM32_USB_DEVICE_LIBRARY
  * @{
  */


/** @defgroup CMPSIT_CORE
  * @brief Mass storage core module
  * @{
  */

/** @defgroup CMPSIT_CORE_Private_TypesDefinitions
  * @{
  */
/**
  * @}
  */


/** @defgroup CMPSIT_CORE_Private_Defines
  * @{
  */

/**
  * @}
  */


/** @defgroup CMPSIT_CORE_Private_Macros
  * @{
  */
/**
  * @}
  */


/** @defgroup CMPSIT_CORE_Private_FunctionPrototypes
  * @{
  */
/* uint8_t  USBD_CMPSIT_Init (USBD_HandleTypeDef *pdev,
                            uint8_t cfgidx); */ /* Function not used for the moment */

/* uint8_t  USBD_CMPSIT_DeInit (USBD_HandleTypeDef *pdev,
                              uint8_t cfgidx); */ /* Function not used for the moment */

uint8_t  *USBD_CMPSIT_GetFSCfgDesc(uint16_t *length);
#ifdef USE_USB_HS
uint8_t  *USBD_CMPSIT_GetHSCfgDesc(uint16_t *length);
#endif /* USE_USB_HS */

uint8_t  *USBD_CMPSIT_GetOtherSpeedCfgDesc(uint16_t *length);

uint8_t  *USBD_CMPSIT_GetDeviceQualifierDescriptor(uint16_t *length);

static uint8_t USBD_CMPSIT_FindFreeIFNbr(USBD_HandleTypeDef *pdev);

static void  USBD_CMPSIT_AddConfDesc(uint32_t Conf, __IO uint32_t *pSze);

static void  USBD_CMPSIT_AssignEp(USBD_HandleTypeDef *pdev, uint8_t Add, uint8_t Type, uint32_t Sze);


#if USBD_CMPSIT_ACTIVATE_HID == 1U
static void  USBD_CMPSIT_HIDMouseDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_HID == 1U */

#if USBD_CMPSIT_ACTIVATE_MSC == 1U
static void  USBD_CMPSIT_MSCDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_MSC == 1U */

#if USBD_CMPSIT_ACTIVATE_CDC == 1U
static void  USBD_CMPSIT_CDCDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_CDC == 1U */

#if USBD_CMPSIT_ACTIVATE_DFU == 1U
static void  USBD_CMPSIT_DFUDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_DFU == 1U */

#if USBD_CMPSIT_ACTIVATE_RNDIS == 1U
static void  USBD_CMPSIT_RNDISDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_RNDIS == 1U */

#if USBD_CMPSIT_ACTIVATE_CDC_ECM == 1U
static void  USBD_CMPSIT_CDC_ECMDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_CDC_ECM == 1U */

#if USBD_CMPSIT_ACTIVATE_AUDIO == 1U
static void  USBD_CMPSIT_AUDIODesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_AUDIO == 1U */

#if USBD_CMPSIT_ACTIVATE_CUSTOMHID == 1
static void  USBD_CMPSIT_CUSTOMHIDDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_CUSTOMHID == 1U */

#if USBD_CMPSIT_ACTIVATE_VIDEO == 1U
static void  USBD_CMPSIT_VIDEODesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_VIDEO == 1U */

#if USBD_CMPSIT_ACTIVATE_PRINTER == 1U
static void  USBD_CMPSIT_PRNTDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_PRINTER == 1U */

#if USBD_CMPSIT_ACTIVATE_CCID == 1U
static void  USBD_CMPSIT_CCIDDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_CCID == 1U */

#if USBD_CMPSIT_ACTIVATE_MTP == 1U
static void  USBD_CMPSIT_MTPDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed);
#endif /* USBD_CMPSIT_ACTIVATE_MTP == 1U */

/**
  * @}
  */


/** @defgroup CMPSIT_CORE_Private_Variables
  * @{
  */
/* This structure is used only for the Configuration descriptors and Device Qualifier */
USBD_ClassTypeDef  USBD_CMPSIT =
{
  NULL, /* Init, */
  NULL, /* DeInit, */
  NULL, /* Setup, */
  NULL, /* EP0_TxSent, */
  NULL, /* EP0_RxReady, */
  NULL, /* DataIn, */
  NULL, /* DataOut, */
  NULL, /* SOF,  */
  NULL,
  NULL,
#ifdef USE_USB_HS
  USBD_CMPSIT_GetHSCfgDesc,
#else
  NULL,
#endif /* USE_USB_HS */
  USBD_CMPSIT_GetFSCfgDesc,
  USBD_CMPSIT_GetOtherSpeedCfgDesc,
  USBD_CMPSIT_GetDeviceQualifierDescriptor,
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
  NULL,
#endif /* USBD_SUPPORT_USER_STRING_DESC */
};

/* The generic configuration descriptor buffer that will be filled by builder
   Size of the buffer is the maximum possible configuration descriptor size. */
__ALIGN_BEGIN static uint8_t USBD_CMPSIT_FSCfgDesc[USBD_CMPST_MAX_CONFDESC_SZ]  __ALIGN_END = {
		/* Configuration Descriptor */
		  0x09,                                       /* bLength: Configuration Descriptor size */
		  USB_DESC_TYPE_CONFIGURATION,                /* bDescriptorType: Configuration */
		  USBD_CMPST_MAX_CONFDESC_SZ,                    /* wTotalLength */
		  0x00,
		  0x03,                                       /* bNumInterfaces: 2 interfaces */
		  0x01,                                       /* bConfigurationValue: Configuration value */
		  0x00,                                       /* iConfiguration: Index of string descriptor
		                                                 describing the configuration */
		#if (USBD_SELF_POWERED == 1U)
		  0xC0,                                       /* bmAttributes: Bus Powered according to user configuration */
		#else
		  0x80,                                       /* bmAttributes: Bus Powered according to user configuration */
		#endif /* USBD_SELF_POWERED */
		  USBD_MAX_POWER,                             /* MaxPower (mA) */

		  /*---------------------------------------------------------------------------*/
		  /* Interface Association Descriptor: CDC device (virtual com port) */
		  0x08,   /* bLength: IAD size */
		  0x0B,   /* bDescriptorType: Interface Association Descriptor */
		  0x00,   /* bFirstInterface */
		  0x02,   /* bInterfaceCount */
		  0x02,   /* bFunctionClass: Communication Interface Class */
		  0x02,   /* bFunctionSubClass: Abstract Control Model */
		  0x01,   /* bFunctionProtocol: Common AT commands */
		  0x00,   /* iFunction */
		  /* Interface Descriptor */
		  0x09,                                       /* bLength: Interface Descriptor size */
		  USB_DESC_TYPE_INTERFACE,                    /* bDescriptorType: Interface */
		  /* Interface descriptor type */
		  0x00,                                       /* bInterfaceNumber: Number of Interface */
		  0x00,                                       /* bAlternateSetting: Alternate setting */
		  0x01,                                       /* bNumEndpoints: One endpoint used */
		  0x02,                                       /* bInterfaceClass: Communication Interface Class */
		  0x02,                                       /* bInterfaceSubClass: Abstract Control Model */
		  0x01,                                       /* bInterfaceProtocol: Common AT commands */
		  0x00,                                       /* 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 */
		  /* 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 */
		  0x00,                                       /* bMasterInterface: Communication class interface */
		  0x01,                                       /* 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),
		  CDC_FS_BINTERVAL,                           /* bInterval */
		  /*---------------------------------------------------------------------------*/
		  /* Data class interface descriptor */
		  0x09,                                       /* bLength: Endpoint Descriptor size */
		  USB_DESC_TYPE_INTERFACE,                    /* bDescriptorType: */
		  0x01,                                       /* bInterfaceNumber: Number of Interface */
		  0x00,                                       /* bAlternateSetting: Alternate setting */
		  0x02,                                       /* bNumEndpoints: Two endpoints used */
		  0x0A,                                       /* bInterfaceClass: CDC */
		  0x00,                                       /* bInterfaceSubClass */
		  0x00,                                       /* bInterfaceProtocol */
		  0x06,                                       /* 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),
		  0x00,                                       /* bInterval */
		  /* 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),
		  0x00,                                        /* bInterval */
		  /* Interface Association Descriptor: Mass Storage device */
		  0x08,   /* bLength: IAD size */
		  0x0B,   /* bDescriptorType: Interface Association Descriptor */
		  0x02,   /* bFirstInterface */
		  0x01,   /* bInterfaceCount */
		  0x08,   /* bFunctionClass: */
		  0x06,   /* bFunctionSubClass: */
		  0x50,   /* bFunctionProtocol: */
		  0x00,   /* iFunction */
		  /********************  Mass Storage interface ********************/
		  0x09,                                            /* bLength: Interface Descriptor size */
		  0x04,                                            /* bDescriptorType: */
		  0x02,                                            /* bInterfaceNumber: Number of Interface */
		  0x00,                                            /* bAlternateSetting: Alternate setting */
		  0x02,                                            /* bNumEndpoints */
		  0x08,                                            /* bInterfaceClass: MSC Class */
		  0x06,                                            /* bInterfaceSubClass : SCSI transparent*/
		  0x50,                                            /* nInterfaceProtocol */
		  0x00,                                            /* 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),
		  0x00,                                            /* 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),
		  0x00
};
static uint8_t *pCmpstFSConfDesc = USBD_CMPSIT_FSCfgDesc;
/* Variable that dynamically holds the current size of the configuration descriptor */
static __IO uint32_t CurrFSConfDescSz = USBD_CMPST_MAX_CONFDESC_SZ;

#ifdef USE_USB_HS
__ALIGN_BEGIN static uint8_t USBD_CMPSIT_HSCfgDesc[USBD_CMPST_MAX_CONFDESC_SZ]  __ALIGN_END = {0};
static uint8_t *pCmpstHSConfDesc = USBD_CMPSIT_HSCfgDesc;
/* Variable that dynamically holds the current size of the configuration descriptor */
static __IO uint32_t CurrHSConfDescSz = 0U;
#endif /* USE_USB_HS */

/* USB Standard Device Descriptor */
__ALIGN_BEGIN static uint8_t USBD_CMPSIT_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC]  __ALIGN_END =
{
  USB_LEN_DEV_QUALIFIER_DESC,      /* bLength */
  USB_DESC_TYPE_DEVICE_QUALIFIER,  /* bDescriptorType */
  0x00,                            /* bcdDevice low */
  0x02,                            /* bcdDevice high */
  0xEF,                            /* Class */
  0x02,                            /* SubClass */
  0x01,                            /* Protocol */
  0x40,                            /* bMaxPacketSize0 */
  0x01,                            /* bNumConfigurations */
  0x00,                            /* bReserved */
};

/**
  * @}
  */


/** @defgroup CMPSIT_CORE_Private_Functions
  * @{
  */

/**
  * @brief  USBD_CMPSIT_AddClass
  *         Register a class in the class builder
  * @param  pdev: device instance
  * @param  pclass: pointer to the class structure to be added
  * @param  class: type of the class to be added (from USBD_CompositeClassTypeDef)
  * @param  cfgidx: configuration index
  * @retval status
  */
uint8_t  USBD_CMPSIT_AddClass(USBD_HandleTypeDef *pdev,
                              USBD_ClassTypeDef *pclass,
                              USBD_CompositeClassTypeDef class,
                              uint8_t cfgidx)
{
	switch(class)
	{
		case CLASS_TYPE_CDC:{
			pdev->tclasslist[pdev->classId].ClassType = CLASS_TYPE_CDC;

			pdev->tclasslist[pdev->classId].Active = 1U;
			pdev->tclasslist[pdev->classId].NumEps = 3;

			pdev->tclasslist[pdev->classId].Eps[0].add = CDC_CMD_EP;
			pdev->tclasslist[pdev->classId].Eps[0].type = USBD_EP_TYPE_INTR;
			pdev->tclasslist[pdev->classId].Eps[0].size = CDC_CMD_PACKET_SIZE;
			pdev->tclasslist[pdev->classId].Eps[0].is_used = 1U;

			pdev->tclasslist[pdev->classId].Eps[1].add = CDC_OUT_EP;
			pdev->tclasslist[pdev->classId].Eps[1].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[1].size = CDC_DATA_FS_MAX_PACKET_SIZE;
			pdev->tclasslist[pdev->classId].Eps[1].is_used = 1U;

			pdev->tclasslist[pdev->classId].Eps[2].add = CDC_IN_EP;
			pdev->tclasslist[pdev->classId].Eps[2].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[2].size = CDC_DATA_FS_MAX_PACKET_SIZE;
			pdev->tclasslist[pdev->classId].Eps[2].is_used = 1U;

			pdev->tclasslist[pdev->classId].NumIf = 2;
			pdev->tclasslist[pdev->classId].Ifs[0] = 0;
			pdev->tclasslist[pdev->classId].Ifs[1] = 1;

		}break;

		case CLASS_TYPE_MSC:{
			pdev->tclasslist[pdev->classId].ClassType = CLASS_TYPE_MSC;

			pdev->tclasslist[pdev->classId].Active = 1U;
			pdev->tclasslist[pdev->classId].NumEps = 2;

			pdev->tclasslist[pdev->classId].Eps[0].add = MSC_EPIN_ADDR;
			pdev->tclasslist[pdev->classId].Eps[0].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[0].size = MSC_MAX_FS_PACKET;
			pdev->tclasslist[pdev->classId].Eps[0].is_used = 1U;

			pdev->tclasslist[pdev->classId].Eps[1].add = MSC_EPOUT_ADDR;
			pdev->tclasslist[pdev->classId].Eps[1].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[1].size = MSC_MAX_FS_PACKET;
			pdev->tclasslist[pdev->classId].Eps[1].is_used = 1U;


			pdev->tclasslist[pdev->classId].NumIf = 1;
			pdev->tclasslist[pdev->classId].Ifs[0] = 2;

		}break;
		default:break;
	}
	pdev->tclasslist[pdev->classId].CurrPcktSze = 0U;

  return (uint8_t)USBD_OK;
}


/**
  * @brief  USBD_CMPSIT_AddToConfDesc
  *         Add a new class to the configuration descriptor
  * @param  pdev: device instance
  * @retval status
  */
uint8_t  USBD_CMPSIT_AddToConfDesc(USBD_HandleTypeDef *pdev)
{
  uint8_t idxIf = 0U;
  uint8_t iEp = 0U;

  /* For the first class instance, start building the config descriptor common part */
  if (pdev->classId == 0U)
  {
    /* Add configuration and IAD descriptors */
    USBD_CMPSIT_AddConfDesc((uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz);
#ifdef USE_USB_HS
    USBD_CMPSIT_AddConfDesc((uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz);
#endif /* USE_USB_HS */
  }

  switch (pdev->tclasslist[pdev->classId].ClassType)
  {
#if USBD_CMPSIT_ACTIVATE_HID == 1
    case CLASS_TYPE_HID:
      /* Setup Max packet sizes (for HID, no dependency on USB Speed, both HS/FS have same packet size) */
      pdev->tclasslist[pdev->classId].CurrPcktSze = HID_EPIN_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 1U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 1U; /* EP1_IN */

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];

      /* Assign IN Endpoint */
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_HIDMouseDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_HIDMouseDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_HID */

#if USBD_CMPSIT_ACTIVATE_MSC == 1
    case CLASS_TYPE_MSC:
      /* Setup default Max packet size */
      pdev->tclasslist[pdev->classId].CurrPcktSze = MSC_MAX_FS_PACKET;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 1U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 2U; /* EP1_IN, EP1_OUT */

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_MSCDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_MSCDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_MSC */

#if USBD_CMPSIT_ACTIVATE_CDC == 1
    case CLASS_TYPE_CDC:
      /* Setup default Max packet size for FS device */
      pdev->tclasslist[pdev->classId].CurrPcktSze = CDC_DATA_FS_MAX_PACKET_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 2U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;
      pdev->tclasslist[pdev->classId].Ifs[1] = (uint8_t)(idxIf + 1U);

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 3U;

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set the second IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[2];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_CDCDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_CDCDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_CDC */

#if USBD_CMPSIT_ACTIVATE_DFU == 1
    case CLASS_TYPE_DFU:
      /* Setup Max packet sizes (for DFU, no dependency on USB Speed, both HS/FS have same packet size) */
      pdev->tclasslist[pdev->classId].CurrPcktSze = 64U;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 1U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 0U; /* only EP0 is used */

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_DFUDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_DFUDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_DFU */

#if USBD_CMPSIT_ACTIVATE_RNDIS == 1
    case CLASS_TYPE_RNDIS:
      /* Setup default Max packet size */
      pdev->tclasslist[pdev->classId].CurrPcktSze = CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 2U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;
      pdev->tclasslist[pdev->classId].Ifs[1] = (uint8_t)(idxIf + 1U);

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 3U;

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set the second IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[2];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, CDC_RNDIS_CMD_PACKET_SIZE);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_RNDISDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_RNDISDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_RNDIS */

#if USBD_CMPSIT_ACTIVATE_CDC_ECM == 1
    case CLASS_TYPE_ECM:
      /* Setup default Max packet size */
      pdev->tclasslist[pdev->classId].CurrPcktSze = CDC_ECM_DATA_FS_MAX_PACKET_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 2U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;
      pdev->tclasslist[pdev->classId].Ifs[1] = (uint8_t)(idxIf + 1U);

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 3U; /* EP1_IN, EP1_OUT,CMD_EP2 */

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set the second IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[2];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, CDC_ECM_CMD_PACKET_SIZE);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_CDC_ECMDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_CDC_ECMDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_CDC_ECM */

#if USBD_CMPSIT_ACTIVATE_AUDIO == 1
    case CLASS_TYPE_AUDIO:
      /* Setup Max packet sizes*/
      pdev->tclasslist[pdev->classId].CurrPcktSze = USBD_AUDIO_GetEpPcktSze(pdev, 0U, 0U);

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 2U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;
      pdev->tclasslist[pdev->classId].Ifs[1] = (uint8_t)(idxIf + 1U);

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 1U; /* EP1_OUT*/

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];

      /* Assign OUT Endpoint */
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_ISOC, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Configure and Append the Descriptor (only FS mode supported) */
      USBD_CMPSIT_AUDIODesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

      break;
#endif /* USBD_CMPSIT_ACTIVATE_AUDIO */

#if USBD_CMPSIT_ACTIVATE_CUSTOMHID == 1
    case CLASS_TYPE_CHID:
      /* Setup Max packet sizes */
      pdev->tclasslist[pdev->classId].CurrPcktSze = CUSTOM_HID_EPOUT_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 1U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 2U; /* EP1_IN, EP1_OUT */

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_CUSTOMHIDDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_CUSTOMHIDDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_CUSTOMHID */

#if USBD_CMPSIT_ACTIVATE_VIDEO == 1
    case CLASS_TYPE_VIDEO:
      /* Setup default Max packet size */
      pdev->tclasslist[pdev->classId].CurrPcktSze = UVC_ISO_FS_MPS;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 2U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;
      pdev->tclasslist[pdev->classId].Ifs[1] = (uint8_t)(idxIf + 1U);

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 1U; /* EP1_IN */

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];

      /* Assign IN Endpoint */
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_ISOC, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_VIDEODesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_VIDEODesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_VIDEO */

#if USBD_CMPSIT_ACTIVATE_PRINTER == 1
    case CLASS_TYPE_PRINTER:

      /* Setup default Max packet size */
      pdev->tclasslist[pdev->classId].CurrPcktSze = PRNT_DATA_FS_MAX_PACKET_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 1U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 2U;

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_PRNTDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_PRNTDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_PRINTER */

#if USBD_CMPSIT_ACTIVATE_CCID == 1

    case CLASS_TYPE_CCID:
      /* Setup default Max packet size */
      pdev->tclasslist[pdev->classId].CurrPcktSze = CCID_DATA_FS_MAX_PACKET_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 1U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 3U;

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set the second IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[2];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, CCID_CMD_PACKET_SIZE);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_CCIDDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_CCIDDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_CCID */

#if USBD_CMPSIT_ACTIVATE_MTP == 1

    case CLASS_TYPE_MTP:
      /* Setup default Max packet sizes */
      pdev->tclasslist[pdev->classId].CurrPcktSze = MTP_DATA_MAX_FS_PACKET_SIZE;

      /* Find the first available interface slot and Assign number of interfaces */
      idxIf = USBD_CMPSIT_FindFreeIFNbr(pdev);
      pdev->tclasslist[pdev->classId].NumIf = 1U;
      pdev->tclasslist[pdev->classId].Ifs[0] = idxIf;

      /* Assign endpoint numbers */
      pdev->tclasslist[pdev->classId].NumEps = 3U;

      /* Set IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[0];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set OUT endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[1];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_BULK, pdev->tclasslist[pdev->classId].CurrPcktSze);

      /* Set the second IN endpoint slot */
      iEp = pdev->tclasslist[pdev->classId].EpAdd[2];
      USBD_CMPSIT_AssignEp(pdev, iEp, USBD_EP_TYPE_INTR, MTP_CMD_PACKET_SIZE);

      /* Configure and Append the Descriptor */
      USBD_CMPSIT_MTPDesc(pdev, (uint32_t)pCmpstFSConfDesc, &CurrFSConfDescSz, (uint8_t)USBD_SPEED_FULL);

#ifdef USE_USB_HS
      USBD_CMPSIT_MTPDesc(pdev, (uint32_t)pCmpstHSConfDesc, &CurrHSConfDescSz, (uint8_t)USBD_SPEED_HIGH);
#endif /* USE_USB_HS */

      break;
#endif /* USBD_CMPSIT_ACTIVATE_MTP */

    default:
      UNUSED(idxIf);
      UNUSED(iEp);
      UNUSED(USBD_CMPSIT_FindFreeIFNbr);
      UNUSED(USBD_CMPSIT_AssignEp);
      break;
  }

  return (uint8_t)USBD_OK;
}

/**
  * @brief  USBD_CMPSIT_GetFSCfgDesc
  *         return configuration descriptor for both FS and HS modes
  * @param  length : pointer data length
  * @retval pointer to descriptor buffer
  */
uint8_t  *USBD_CMPSIT_GetFSCfgDesc(uint16_t *length)
{
  *length = (uint16_t)CurrFSConfDescSz;

  return USBD_CMPSIT_FSCfgDesc;
}

#ifdef USE_USB_HS
/**
  * @brief  USBD_CMPSIT_GetHSCfgDesc
  *         return configuration descriptor for both FS and HS modes
  * @param  length : pointer data length
  * @retval pointer to descriptor buffer
  */
uint8_t  *USBD_CMPSIT_GetHSCfgDesc(uint16_t *length)
{
  *length = (uint16_t)CurrHSConfDescSz;

  return USBD_CMPSIT_HSCfgDesc;
}
#endif /* USE_USB_HS */

/**
  * @brief  USBD_CMPSIT_GetOtherSpeedCfgDesc
  *         return other speed configuration descriptor
  * @param  length : pointer data length
  * @retval pointer to descriptor buffer
  */
uint8_t  *USBD_CMPSIT_GetOtherSpeedCfgDesc(uint16_t *length)
{
  *length = (uint16_t)CurrFSConfDescSz;

  return USBD_CMPSIT_FSCfgDesc;
}

/**
  * @brief  DeviceQualifierDescriptor
  *         return Device Qualifier descriptor
  * @param  length : pointer data length
  * @retval pointer to descriptor buffer
  */
uint8_t  *USBD_CMPSIT_GetDeviceQualifierDescriptor(uint16_t *length)
{
  *length = (uint16_t)(sizeof(USBD_CMPSIT_DeviceQualifierDesc));
  return USBD_CMPSIT_DeviceQualifierDesc;
}

/**
  * @brief  USBD_CMPSIT_FindFreeIFNbr
  *         Find the first interface available slot
  * @param  pdev: device instance
  * @retval The interface number to be used
  */
static uint8_t USBD_CMPSIT_FindFreeIFNbr(USBD_HandleTypeDef *pdev)
{
  uint32_t idx = 0U;

  /* Unroll all already activated classes */
  for (uint32_t i = 0U; i < pdev->NumClasses; i++)
  {
    /* Unroll each class interfaces */
    for (uint32_t j = 0U; j < pdev->tclasslist[i].NumIf; j++)
    {
      /* Increment the interface counter index */
      idx++;
    }
  }

  /* Return the first available interface slot */
  return (uint8_t)idx;
}

/**
  * @brief  USBD_CMPSIT_AddToConfDesc
  *         Add a new class to the configuration descriptor
  * @param  pdev: device instance
  * @retval none
  */
static void  USBD_CMPSIT_AddConfDesc(uint32_t Conf, __IO uint32_t *pSze)
{
  /* Intermediate variable to comply with MISRA-C Rule 11.3 */
  USBD_ConfigDescTypeDef *ptr = (USBD_ConfigDescTypeDef *)Conf;

  ptr->bLength = (uint8_t)sizeof(USBD_ConfigDescTypeDef);
  ptr->bDescriptorType = USB_DESC_TYPE_CONFIGURATION;
  ptr->wTotalLength = 0U;
  ptr->bNumInterfaces = 0U;
  ptr->bConfigurationValue = 1U;
  ptr->iConfiguration = USBD_CONFIG_STR_DESC_IDX;

#if (USBD_SELF_POWERED == 1U)
  ptr->bmAttributes = 0xC0U;   /* bmAttributes: Self Powered according to user configuration */
#else
  ptr->bmAttributes = 0x80U;   /* bmAttributes: Bus Powered according to user configuration */
#endif /* USBD_SELF_POWERED */

  ptr->bMaxPower = USBD_MAX_POWER;

  *pSze += sizeof(USBD_ConfigDescTypeDef);
}

/**
  * @brief  USBD_CMPSIT_AssignEp
  *         Assign and endpoint
  * @param  pdev: device instance
  * @param  Add: Endpoint address
  * @param  Type: Endpoint type
  * @param  Sze: Endpoint max packet size
  * @retval none
  */
static void  USBD_CMPSIT_AssignEp(USBD_HandleTypeDef *pdev, uint8_t Add, uint8_t Type, uint32_t Sze)
{
  uint32_t idx = 0U;

  /* Find the first available endpoint slot */
  while (((idx < (pdev->tclasslist[pdev->classId]).NumEps) && \
          ((pdev->tclasslist[pdev->classId].Eps[idx].is_used) != 0U)))
  {
    /* Increment the index */
    idx++;
  }

  /* Configure the endpoint */
  pdev->tclasslist[pdev->classId].Eps[idx].add = Add;
  pdev->tclasslist[pdev->classId].Eps[idx].type = Type;
  pdev->tclasslist[pdev->classId].Eps[idx].size = (uint8_t)Sze;
  pdev->tclasslist[pdev->classId].Eps[idx].is_used = 1U;
}

#if USBD_CMPSIT_ACTIVATE_HID == 1
/**
  * @brief  USBD_CMPSIT_HIDMouseDesc
  *         Configure and Append the HID Mouse Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_HIDMouseDesc(USBD_HandleTypeDef *pdev, uint32_t pConf,
                                      __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef *pIfDesc;
  static USBD_EpDescTypeDef *pEpDesc;
  static USBD_HIDDescTypeDef *pHidMouseDesc;

  /* Append HID Interface descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, \
                       (uint8_t)(pdev->tclasslist[pdev->classId].NumEps), 0x03U, 0x01U, 0x02U, 0U);

  /* Append HID Functional descriptor to Configuration descriptor */
  pHidMouseDesc = ((USBD_HIDDescTypeDef *)(pConf + *Sze));
  pHidMouseDesc->bLength = (uint8_t)sizeof(USBD_HIDDescTypeDef);
  pHidMouseDesc->bDescriptorType = HID_DESCRIPTOR_TYPE;
  pHidMouseDesc->bcdHID = 0x0111U;
  pHidMouseDesc->bCountryCode = 0x00U;
  pHidMouseDesc->bNumDescriptors = 0x01U;
  pHidMouseDesc->bHIDDescriptorType = 0x22U;
  pHidMouseDesc->wItemLength = HID_MOUSE_REPORT_DESC_SIZE;
  *Sze += (uint32_t)sizeof(USBD_HIDDescTypeDef);

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[0].add, USBD_EP_TYPE_INTR, HID_EPIN_SIZE, \
                       HID_HS_BINTERVAL, HID_FS_BINTERVAL);

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 1U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength  = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_HID == 1 */

#if USBD_CMPSIT_ACTIVATE_MSC == 1
/**
  * @brief  USBD_CMPSIT_MSCDesc
  *         Configure and Append the MSC Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_MSCDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  USBD_IfDescTypeDef *pIfDesc;
  USBD_EpDescTypeDef *pEpDesc;

  /* Append MSC Interface descriptor */
  __USBD_CMPSIT_SET_IF((pdev->tclasslist[pdev->classId].Ifs[0]), (0U), \
                       (uint8_t)(pdev->tclasslist[pdev->classId].NumEps), (0x08U), (0x06U), (0x50U), (0U));

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pdev->tclasslist[pdev->classId].CurrPcktSze = MSC_MAX_HS_PACKET;
  }

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[0].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[1].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 1U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_MSC == 1 */

#if USBD_CMPSIT_ACTIVATE_CDC == 1
/**
  * @brief  USBD_CMPSIT_MSCDesc
  *         Configure and Append the HID Mouse Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_CDCDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef               *pIfDesc;
  static USBD_EpDescTypeDef               *pEpDesc;
  static USBD_CDCHeaderFuncDescTypeDef    *pHeadDesc;
  static USBD_CDCCallMgmFuncDescTypeDef   *pCallMgmDesc;
  static USBD_CDCACMFuncDescTypeDef       *pACMDesc;
  static USBD_CDCUnionFuncDescTypeDef     *pUnionDesc;
#if USBD_COMPOSITE_USE_IAD == 1
  static USBD_IadDescTypeDef              *pIadDesc;
#endif /* USBD_COMPOSITE_USE_IAD == 1 */

#if USBD_COMPOSITE_USE_IAD == 1
  pIadDesc                          = ((USBD_IadDescTypeDef *)(pConf + *Sze));
  pIadDesc->bLength                 = (uint8_t)sizeof(USBD_IadDescTypeDef);
  pIadDesc->bDescriptorType         = USB_DESC_TYPE_IAD; /* IAD descriptor */
  pIadDesc->bFirstInterface         = pdev->tclasslist[pdev->classId].Ifs[0];
  pIadDesc->bInterfaceCount         = 2U;    /* 2 interfaces */
  pIadDesc->bFunctionClass          = 0x02U;
  pIadDesc->bFunctionSubClass       = 0x02U;
  pIadDesc->bFunctionProtocol       = 0x01U;
  pIadDesc->iFunction               = 0U; /* String Index */
  *Sze                              += (uint32_t)sizeof(USBD_IadDescTypeDef);
#endif /* USBD_COMPOSITE_USE_IAD == 1 */

  /* Control Interface Descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, 1U, 0x02, 0x02U, 0x01U, 0U);

  /* Control interface headers */
  pHeadDesc = ((USBD_CDCHeaderFuncDescTypeDef *)((uint32_t)pConf + *Sze));
  /* Header Functional Descriptor*/
  pHeadDesc->bLength = 0x05U;
  pHeadDesc->bDescriptorType = 0x24U;
  pHeadDesc->bDescriptorSubtype = 0x00U;
  pHeadDesc->bcdCDC = 0x0110U;
  *Sze += (uint32_t)sizeof(USBD_CDCHeaderFuncDescTypeDef);

  /* Call Management Functional Descriptor */
  pCallMgmDesc = ((USBD_CDCCallMgmFuncDescTypeDef *)((uint32_t)pConf + *Sze));
  pCallMgmDesc->bLength = 0x05U;
  pCallMgmDesc->bDescriptorType = 0x24U;
  pCallMgmDesc->bDescriptorSubtype = 0x01U;
  pCallMgmDesc->bmCapabilities = 0x00U;
  pCallMgmDesc->bDataInterface = pdev->tclasslist[pdev->classId].Ifs[1];
  *Sze += (uint32_t)sizeof(USBD_CDCCallMgmFuncDescTypeDef);

  /* ACM Functional Descriptor*/
  pACMDesc = ((USBD_CDCACMFuncDescTypeDef *)((uint32_t)pConf + *Sze));
  pACMDesc->bLength = 0x04U;
  pACMDesc->bDescriptorType = 0x24U;
  pACMDesc->bDescriptorSubtype = 0x02U;
  pACMDesc->bmCapabilities = 0x02U;
  *Sze += (uint32_t)sizeof(USBD_CDCACMFuncDescTypeDef);

  /* Union Functional Descriptor*/
  pUnionDesc = ((USBD_CDCUnionFuncDescTypeDef *)((uint32_t)pConf + *Sze));
  pUnionDesc->bLength = 0x05U;
  pUnionDesc->bDescriptorType = 0x24U;
  pUnionDesc->bDescriptorSubtype = 0x06U;
  pUnionDesc->bMasterInterface = pdev->tclasslist[pdev->classId].Ifs[0];
  pUnionDesc->bSlaveInterface = pdev->tclasslist[pdev->classId].Ifs[1];
  *Sze += (uint32_t)sizeof(USBD_CDCUnionFuncDescTypeDef);

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[2].add, \
                       USBD_EP_TYPE_INTR, CDC_CMD_PACKET_SIZE, CDC_HS_BINTERVAL, CDC_FS_BINTERVAL);

  /* Data Interface Descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[1], 0U, 2U, 0x0A, 0U, 0U, 0U);

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pdev->tclasslist[pdev->classId].CurrPcktSze = CDC_DATA_HS_MAX_PACKET_SIZE;
  }

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[0].add), \
                       (USBD_EP_TYPE_BULK), (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[1].add), \
                       (USBD_EP_TYPE_BULK), (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 2U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_CDC == 1 */

#if USBD_CMPSIT_ACTIVATE_DFU == 1
/**
  * @brief  USBD_CMPSIT_DFUDesc
  *         Configure and Append the DFU Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_DFUDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef *pIfDesc;
  static USBD_DFUFuncDescTypeDef *pDFUFuncDesc;
  uint32_t idx;
  UNUSED(speed);

  for (idx = 0U; idx < USBD_DFU_MAX_ITF_NUM; idx++)
  {
    /* Append DFU Interface descriptor to Configuration descriptor */
    __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], (uint8_t)idx, 0U, 0xFEU, 0x01U, 0x02U, \
                         (uint8_t)USBD_IDX_INTERFACE_STR + 1U + (uint8_t)idx);
  }

  /* Append DFU Functional descriptor to Configuration descriptor */
  pDFUFuncDesc = ((USBD_DFUFuncDescTypeDef *)(pConf + *Sze));
  pDFUFuncDesc->bLength              = (uint8_t)sizeof(USBD_DFUFuncDescTypeDef);
  pDFUFuncDesc->bDescriptorType      = DFU_DESCRIPTOR_TYPE;
  pDFUFuncDesc->bmAttributes         = USBD_DFU_BM_ATTRIBUTES;
  pDFUFuncDesc->wDetachTimeout       = USBD_DFU_DETACH_TIMEOUT;
  pDFUFuncDesc->wTransferSze         = USBD_DFU_XFER_SIZE;
  pDFUFuncDesc->bcdDFUVersion        = 0x011AU;
  *Sze                              += (uint32_t)sizeof(USBD_DFUFuncDescTypeDef);

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 1U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);

  UNUSED(idx);
}
#endif /* USBD_CMPSIT_ACTIVATE_DFU == 1 */

#if USBD_CMPSIT_ACTIVATE_CDC_ECM == 1
/**
  * @brief  USBD_CMPSIT_CDC_ECMDesc
  *         Configure and Append the CDC_ECM Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_CDC_ECMDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef             *pIfDesc;
  static USBD_EpDescTypeDef             *pEpDesc;
  static USBD_ECMFuncDescTypeDef        *pFuncDesc;
  static USBD_IadDescTypeDef            *pIadDesc;

  static USBD_CDCHeaderFuncDescTypeDef  *pHeadDesc;
  static USBD_CDCUnionFuncDescTypeDef   *pUnionDesc;

#if USBD_COMPOSITE_USE_IAD == 1
  pIadDesc                          = ((USBD_IadDescTypeDef *)(pConf + *Sze));
  pIadDesc->bLength                 = (uint8_t)sizeof(USBD_IadDescTypeDef);
  pIadDesc->bDescriptorType         = USB_DESC_TYPE_IAD; /* IAD descriptor */
  pIadDesc->bFirstInterface         = pdev->tclasslist[pdev->classId].Ifs[0];
  pIadDesc->bInterfaceCount         = 2U;    /* 2 interfaces */
  pIadDesc->bFunctionClass          = 0x02U;
  pIadDesc->bFunctionSubClass       = 0x06U;
  pIadDesc->bFunctionProtocol       = 0x00U;
  pIadDesc->iFunction               = 0U; /* String Index */
  *Sze                             += (uint32_t)sizeof(USBD_IadDescTypeDef);
#endif /* USBD_COMPOSITE_USE_IAD == 1 */

  /* Append ECM Interface descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, 1U, 0x02U, 0x06U, 0U, 0U);

  /* Append ECM header functional descriptor to Configuration descriptor */
  pHeadDesc = ((USBD_CDCHeaderFuncDescTypeDef *)(pConf + *Sze));
  pHeadDesc->bLength                 = (uint8_t)sizeof(USBD_CDCHeaderFuncDescTypeDef);
  pHeadDesc->bDescriptorType         = USBD_FUNC_DESCRIPTOR_TYPE;
  pHeadDesc->bDescriptorSubtype      = 0x00U;
  pHeadDesc->bcdCDC                  = 0x1000U;
  *Sze += (uint32_t)sizeof(USBD_CDCHeaderFuncDescTypeDef);

  /* Append ECM functional descriptor to Configuration descriptor */
  pFuncDesc = ((USBD_ECMFuncDescTypeDef *)(pConf + *Sze));
  pFuncDesc->bFunctionLength         = (uint8_t)sizeof(USBD_ECMFuncDescTypeDef);
  pFuncDesc->bDescriptorType         = USBD_FUNC_DESCRIPTOR_TYPE;
  pFuncDesc->bDescriptorSubType      = USBD_DESC_SUBTYPE_ACM;
  pFuncDesc->iMacAddress             = CDC_ECM_MAC_STRING_INDEX;
  pFuncDesc->bEthernetStatistics3    = CDC_ECM_ETH_STATS_BYTE3;
  pFuncDesc->bEthernetStatistics2    = CDC_ECM_ETH_STATS_BYTE2;
  pFuncDesc->bEthernetStatistics1    = CDC_ECM_ETH_STATS_BYTE1;
  pFuncDesc->bEthernetStatistics0    = CDC_ECM_ETH_STATS_BYTE0;
  pFuncDesc->wMaxSegmentSize         = CDC_ECM_ETH_MAX_SEGSZE;
  pFuncDesc->bNumberMCFiltes         = CDC_ECM_ETH_NBR_MACFILTERS;
  pFuncDesc->bNumberPowerFiltes      = CDC_ECM_ETH_NBR_PWRFILTERS;
  *Sze += (uint32_t)sizeof(USBD_ECMFuncDescTypeDef);

  /* Append ECM Union functional descriptor to Configuration descriptor */
  pUnionDesc = ((USBD_CDCUnionFuncDescTypeDef *)(pConf + *Sze));
  pUnionDesc->bLength             = (uint8_t)sizeof(USBD_CDCUnionFuncDescTypeDef);
  pUnionDesc->bDescriptorType     = 0x24U;
  pUnionDesc->bDescriptorSubtype  = 0x06U;
  pUnionDesc->bMasterInterface    = pdev->tclasslist[pdev->classId].Ifs[0];
  pUnionDesc->bSlaveInterface     = pdev->tclasslist[pdev->classId].Ifs[1];
  *Sze += (uint32_t)sizeof(USBD_CDCUnionFuncDescTypeDef);

  /* Append ECM Communication IN Endpoint Descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[2].add, USBD_EP_TYPE_INTR, CDC_ECM_CMD_PACKET_SIZE, \
                       CDC_ECM_HS_BINTERVAL, CDC_ECM_FS_BINTERVAL);

  /* Append ECM Data class interface descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[1], 0U, 2U, 0x0AU, 0U, 0U, 0U);

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pdev->tclasslist[pdev->classId].CurrPcktSze = CDC_ECM_DATA_HS_MAX_PACKET_SIZE;
  }

  /* Append ECM OUT Endpoint Descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[0].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (CDC_ECM_HS_BINTERVAL), (CDC_ECM_FS_BINTERVAL));

  /* Append ECM IN Endpoint Descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[1].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (CDC_ECM_HS_BINTERVAL), (CDC_ECM_FS_BINTERVAL));

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 2U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_CDC_ECM */

#if USBD_CMPSIT_ACTIVATE_AUDIO == 1
/**
  * @brief  USBD_CMPSIT_AUDIODesc
  *         Configure and Append the AUDIO Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_AUDIODesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef *pIfDesc;
  static USBD_IadDescTypeDef *pIadDesc;
  UNUSED(speed);

  /* Append AUDIO Interface descriptor to Configuration descriptor */
  USBD_SpeakerIfDescTypeDef            *pSpIfDesc;
  USBD_SpeakerInDescTypeDef            *pSpInDesc;
  USBD_SpeakerFeatureDescTypeDef       *pSpFDesc;
  USBD_SpeakerOutDescTypeDef           *pSpOutDesc;
  USBD_SpeakerStreamIfDescTypeDef      *pSpStrDesc;
  USBD_SpeakerIIIFormatIfDescTypeDef   *pSpIIIDesc;
  USBD_SpeakerEndDescTypeDef           *pSpEpDesc;
  USBD_SpeakerEndStDescTypeDef         *pSpEpStDesc;

#if USBD_COMPOSITE_USE_IAD == 1
  pIadDesc                          = ((USBD_IadDescTypeDef *)(pConf + *Sze));
  pIadDesc->bLength                 = (uint8_t)sizeof(USBD_IadDescTypeDef);
  pIadDesc->bDescriptorType         = USB_DESC_TYPE_IAD; /* IAD descriptor */
  pIadDesc->bFirstInterface         = pdev->tclasslist[pdev->classId].Ifs[0];
  pIadDesc->bInterfaceCount         = 2U;    /* 2 interfaces */
  pIadDesc->bFunctionClass          = USB_DEVICE_CLASS_AUDIO;
  pIadDesc->bFunctionSubClass       = AUDIO_SUBCLASS_AUDIOCONTROL;
  pIadDesc->bFunctionProtocol       = AUDIO_PROTOCOL_UNDEFINED;
  pIadDesc->iFunction               = 0U; /* String Index */
  *Sze                             += (uint32_t)sizeof(USBD_IadDescTypeDef);
#endif /* USBD_COMPOSITE_USE_IAD == 1 */

  /* Append AUDIO Interface descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, 0U, USB_DEVICE_CLASS_AUDIO, \
                       AUDIO_SUBCLASS_AUDIOCONTROL, AUDIO_PROTOCOL_UNDEFINED, 0U);

  /* Append AUDIO USB Speaker Class-specific AC Interface descriptor to Configuration descriptor */
  pSpIfDesc = ((USBD_SpeakerIfDescTypeDef *)(pConf + *Sze));
  pSpIfDesc->bLength = (uint8_t)sizeof(USBD_IfDescTypeDef);
  pSpIfDesc->bDescriptorType = AUDIO_INTERFACE_DESCRIPTOR_TYPE;
  pSpIfDesc->bDescriptorSubtype = AUDIO_CONTROL_HEADER;
  pSpIfDesc->bcdADC = 0x0100U;
  pSpIfDesc->wTotalLength = 0x0027U;
  pSpIfDesc->bInCollection = 0x01U;
  pSpIfDesc->baInterfaceNr = 0x01U;
  *Sze += (uint32_t)sizeof(USBD_IfDescTypeDef);

  /* Append USB Speaker Input Terminal Descriptor to Configuration descriptor*/
  pSpInDesc = ((USBD_SpeakerInDescTypeDef *)(pConf + *Sze));
  pSpInDesc->bLength = (uint8_t)sizeof(USBD_SpeakerInDescTypeDef);
  pSpInDesc->bDescriptorType = AUDIO_INTERFACE_DESCRIPTOR_TYPE;
  pSpInDesc->bDescriptorSubtype = AUDIO_CONTROL_INPUT_TERMINAL;
  pSpInDesc->bTerminalID = 0x01U;
  pSpInDesc->wTerminalType = 0x0101U;
  pSpInDesc->bAssocTerminal = 0x00U;
  pSpInDesc->bNrChannels = 0x01U;
  pSpInDesc->wChannelConfig = 0x0000U;
  pSpInDesc->iChannelNames = 0x00U;
  pSpInDesc->iTerminal = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_SpeakerInDescTypeDef);

  /*Append USB Speaker Audio Feature Unit Descriptor to Configuration descriptor */
  pSpFDesc = ((USBD_SpeakerFeatureDescTypeDef *)(pConf + *Sze));
  pSpFDesc->bLength = (uint8_t)sizeof(USBD_SpeakerFeatureDescTypeDef);
  pSpFDesc->bDescriptorType = AUDIO_INTERFACE_DESCRIPTOR_TYPE;
  pSpFDesc->bDescriptorSubtype = AUDIO_CONTROL_FEATURE_UNIT;
  pSpFDesc->bUnitID = AUDIO_OUT_STREAMING_CTRL;
  pSpFDesc->bSourceID = 0x01U;
  pSpFDesc->bControlSize = 0x01U;
  pSpFDesc->bmaControls = AUDIO_CONTROL_MUTE;
  pSpFDesc->iTerminal = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_SpeakerFeatureDescTypeDef);

  /*Append USB Speaker Output Terminal Descriptor to Configuration descriptor*/
  pSpOutDesc = ((USBD_SpeakerOutDescTypeDef *)(pConf + *Sze));
  pSpOutDesc->bLength = (uint8_t)sizeof(USBD_SpeakerOutDescTypeDef);
  pSpOutDesc->bDescriptorType = AUDIO_INTERFACE_DESCRIPTOR_TYPE;
  pSpOutDesc->bDescriptorSubtype = AUDIO_CONTROL_OUTPUT_TERMINAL;
  pSpOutDesc->bTerminalID = 0x03U;
  pSpOutDesc->wTerminalType = 0x0301U;
  pSpOutDesc->bAssocTerminal = 0x00U;
  pSpOutDesc->bSourceID = 0x02U;
  pSpOutDesc->iTerminal = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_SpeakerOutDescTypeDef);

  /* USB Speaker Standard AS Interface Descriptor - Audio Streaming Zero Bandwidth */
  /* Interface 1, Alternate Setting 0*/
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[1], 0U, 0U, USB_DEVICE_CLASS_AUDIO, \
                       AUDIO_SUBCLASS_AUDIOSTREAMING, AUDIO_PROTOCOL_UNDEFINED, 0U);

  /* USB Speaker Standard AS Interface Descriptor -Audio Streaming Operational */
  /* Interface 1, Alternate Setting 1*/
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[1], 0x01U, 0x01U, USB_DEVICE_CLASS_AUDIO, \
                       AUDIO_SUBCLASS_AUDIOSTREAMING, AUDIO_PROTOCOL_UNDEFINED, 0U);

  /* USB Speaker Audio Streaming Interface Descriptor */
  pSpStrDesc = ((USBD_SpeakerStreamIfDescTypeDef *)(pConf + *Sze));
  pSpStrDesc->bLength = (uint8_t)sizeof(USBD_SpeakerStreamIfDescTypeDef);
  pSpStrDesc->bDescriptorType = AUDIO_INTERFACE_DESCRIPTOR_TYPE;
  pSpStrDesc->bDescriptorSubtype = AUDIO_STREAMING_GENERAL;
  pSpStrDesc->bTerminalLink = 0x01U;
  pSpStrDesc->bDelay = 0x01U;
  pSpStrDesc->wFormatTag = 0x0001U;
  *Sze += (uint32_t)sizeof(USBD_SpeakerStreamIfDescTypeDef);

  /* USB Speaker Audio Type III Format Interface Descriptor */
  pSpIIIDesc = ((USBD_SpeakerIIIFormatIfDescTypeDef *)(pConf + *Sze));
  pSpIIIDesc->bLength = (uint8_t)sizeof(USBD_SpeakerIIIFormatIfDescTypeDef);
  pSpIIIDesc->bDescriptorType = AUDIO_INTERFACE_DESCRIPTOR_TYPE;
  pSpIIIDesc->bDescriptorSubtype = AUDIO_STREAMING_FORMAT_TYPE;
  pSpIIIDesc->bFormatType = AUDIO_FORMAT_TYPE_I;
  pSpIIIDesc->bNrChannels = 0x02U;
  pSpIIIDesc->bSubFrameSize = 0x02U;
  pSpIIIDesc->bBitResolution = 16U;
  pSpIIIDesc->bSamFreqType = 1U;
  pSpIIIDesc->tSamFreq2 = 0x80U;
  pSpIIIDesc->tSamFreq1 = 0xBBU;
  pSpIIIDesc->tSamFreq0 = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_SpeakerIIIFormatIfDescTypeDef);

  /* Endpoint 1 - Standard Descriptor */
  pSpEpDesc = ((USBD_SpeakerEndDescTypeDef *)(pConf + *Sze));
  pSpEpDesc->bLength = 0x09U;
  pSpEpDesc->bDescriptorType = USB_DESC_TYPE_ENDPOINT;
  pSpEpDesc->bEndpointAddress = pdev->tclasslist[pdev->classId].Eps[0].add;
  pSpEpDesc->bmAttributes = USBD_EP_TYPE_ISOC;
  pSpEpDesc->wMaxPacketSize = (uint16_t)USBD_AUDIO_GetEpPcktSze(pdev, 0U, 0U);
  pSpEpDesc->bInterval = 0x01U;
  pSpEpDesc->bRefresh = 0x00U;
  pSpEpDesc->bSynchAddress = 0x00U;
  *Sze += 0x09U;

  /* Endpoint - Audio Streaming Descriptor*/
  pSpEpStDesc = ((USBD_SpeakerEndStDescTypeDef *)(pConf + *Sze));
  pSpEpStDesc->bLength = (uint8_t)sizeof(USBD_SpeakerEndStDescTypeDef);
  pSpEpStDesc->bDescriptorType = AUDIO_ENDPOINT_DESCRIPTOR_TYPE;
  pSpEpStDesc->bDescriptor = AUDIO_ENDPOINT_GENERAL;
  pSpEpStDesc->bmAttributes = 0x00U;
  pSpEpStDesc->bLockDelayUnits = 0x00U;
  pSpEpStDesc->wLockDelay = 0x0000U;
  *Sze += (uint32_t)sizeof(USBD_SpeakerEndStDescTypeDef);

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 2U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_AUDIO */

#if USBD_CMPSIT_ACTIVATE_RNDIS == 1
/**
  * @brief  USBD_CMPSIT_MSCDesc
  *         Configure and Append the CDC_RNDIS Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_RNDISDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef               *pIfDesc;
  static USBD_EpDescTypeDef               *pEpDesc;
  static USBD_CDCHeaderFuncDescTypeDef    *pHeadDesc;
  static USBD_CDCCallMgmFuncDescTypeDef   *pCallMgmDesc;
  static USBD_CDCACMFuncDescTypeDef       *pACMDesc;
  static USBD_CDCUnionFuncDescTypeDef     *pUnionDesc;
  static USBD_IadDescTypeDef              *pIadDesc;

#if USBD_COMPOSITE_USE_IAD == 1
  pIadDesc                          = ((USBD_IadDescTypeDef *)(pConf + *Sze));
  pIadDesc->bLength                 = (uint8_t)sizeof(USBD_IadDescTypeDef);
  pIadDesc->bDescriptorType         = USB_DESC_TYPE_IAD; /* IAD descriptor */
  pIadDesc->bFirstInterface         = pdev->tclasslist[pdev->classId].Ifs[0];
  pIadDesc->bInterfaceCount         = 2U;    /* 2 interfaces */
  pIadDesc->bFunctionClass          = 0xE0U;
  pIadDesc->bFunctionSubClass       = 0x01U;
  pIadDesc->bFunctionProtocol       = 0x03U;
  pIadDesc->iFunction               = 0U; /* String Index */
  *Sze                              += (uint32_t)sizeof(USBD_IadDescTypeDef);
#endif /* USBD_COMPOSITE_USE_IAD == 1 */

  /* Control Interface Descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, 1U, 0x02, 0x02, 0xFF, 0U);

  /* Control interface headers */
  pHeadDesc = ((USBD_CDCHeaderFuncDescTypeDef *)(pConf + *Sze));
  /* Header Functional Descriptor*/
  pHeadDesc->bLength            = (uint8_t)sizeof(USBD_CDCHeaderFuncDescTypeDef);
  pHeadDesc->bDescriptorType    = 0x24U;
  pHeadDesc->bDescriptorSubtype = 0x00U;
  pHeadDesc->bcdCDC             = 0x0110U;
  *Sze += (uint32_t)sizeof(USBD_CDCHeaderFuncDescTypeDef);

  /* Call Management Functional Descriptor*/
  pCallMgmDesc                     = ((USBD_CDCCallMgmFuncDescTypeDef *)(pConf + *Sze));
  pCallMgmDesc->bLength            = (uint8_t)sizeof(USBD_CDCCallMgmFuncDescTypeDef);
  pCallMgmDesc->bDescriptorType    = 0x24U;
  pCallMgmDesc->bDescriptorSubtype = 0x01U;
  pCallMgmDesc->bmCapabilities     = 0x00U;
  pCallMgmDesc->bDataInterface     = pdev->tclasslist[pdev->classId].Ifs[1];
  *Sze += (uint32_t)sizeof(USBD_CDCCallMgmFuncDescTypeDef);

  /* ACM Functional Descriptor*/
  pACMDesc                      = ((USBD_CDCACMFuncDescTypeDef *)(pConf + *Sze));
  pACMDesc->bLength             = (uint8_t)sizeof(USBD_CDCACMFuncDescTypeDef);
  pACMDesc->bDescriptorType     = 0x24U;
  pACMDesc->bDescriptorSubtype  = 0x02U;
  pACMDesc->bmCapabilities      = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_CDCACMFuncDescTypeDef);

  /* Union Functional Descriptor*/
  pUnionDesc                      = ((USBD_CDCUnionFuncDescTypeDef *)(pConf + *Sze));
  pUnionDesc->bLength             = (uint8_t)sizeof(USBD_CDCUnionFuncDescTypeDef);
  pUnionDesc->bDescriptorType     = 0x24U;
  pUnionDesc->bDescriptorSubtype  = 0x06U;
  pUnionDesc->bMasterInterface    = pdev->tclasslist[pdev->classId].Ifs[0];
  pUnionDesc->bSlaveInterface     = pdev->tclasslist[pdev->classId].Ifs[1];
  *Sze += (uint32_t)sizeof(USBD_CDCUnionFuncDescTypeDef);

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[2].add, USBD_EP_TYPE_INTR, \
                       CDC_RNDIS_CMD_PACKET_SIZE, CDC_RNDIS_HS_BINTERVAL, CDC_RNDIS_FS_BINTERVAL);

  /* Data Interface Descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[1], 0U, 2U, 0x0AU, 0x00U, 0x00U, 0U);

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pdev->tclasslist[pdev->classId].CurrPcktSze = CDC_RNDIS_DATA_HS_MAX_PACKET_SIZE;
  }

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[0].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[1].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 2U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_RNDIS == 1 */

#if USBD_CMPSIT_ACTIVATE_CUSTOMHID == 1
/**
  * @brief  USBD_CMPSIT_CUSTOMHIDDesc
  *         Configure and Append the MSC Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_CUSTOMHIDDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef *pIfDesc;
  static USBD_EpDescTypeDef *pEpDesc;
  static USBD_DescTypeDef *pDesc;

  /* Control Interface Descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0],  0U, 2U, 3U, 0U, 0U, 0U);

  /* Descriptor of CUSTOM_HID */
  pDesc = ((USBD_DescTypeDef *)((uint32_t)pConf + *Sze));
  pDesc->bLength = 0x09U;
  pDesc->bDescriptorTypeCHID = CUSTOM_HID_DESCRIPTOR_TYPE;
  pDesc->bcdCUSTOM_HID = 0x0111U;
  pDesc->bCountryCode = 0x00U;
  pDesc->bNumDescriptors = 0x01U;
  pDesc->bDescriptorType = 0x22U;
  pDesc->wItemLength = USBD_CUSTOM_HID_REPORT_DESC_SIZE;
  *Sze += (uint32_t)sizeof(USBD_DescTypeDef);

  /* Descriptor of Custom HID endpoints */
  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[0].add, \
                       USBD_EP_TYPE_INTR, CUSTOM_HID_EPIN_SIZE, CUSTOM_HID_HS_BINTERVAL, CUSTOM_HID_FS_BINTERVAL);

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[1].add, \
                       USBD_EP_TYPE_INTR, CUSTOM_HID_EPIN_SIZE, CUSTOM_HID_HS_BINTERVAL, CUSTOM_HID_FS_BINTERVAL);

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 1U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_CUSTOMHID == 1U */

#if USBD_CMPSIT_ACTIVATE_VIDEO == 1
/**
  * @brief  USBD_CMPSIT_VIDEODesc
  *         Configure and Append the VIDEO Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_VIDEODesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
#ifdef USBD_UVC_FORMAT_UNCOMPRESSED
  __ALIGN_BEGIN static uint8_t usbd_uvc_guid[16] __ALIGN_END = {DBVAL(UVC_UNCOMPRESSED_GUID), 0x00, 0x00, 0x10,
                                                                0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71
                                                               };
#endif /* USBD_UVC_FORMAT_UNCOMPRESSED */
  static USBD_IfDescTypeDef *pIfDesc;
  static USBD_IadDescTypeDef *pIadDesc;

  /* Append AUDIO Interface descriptor to Configuration descriptor */
  USBD_specificVCInDescTypeDef            *pSVCInDesc;
  USBD_InputTerminalDescTypeDef           *pInTerDesc;
  USBD_OutputTerminalDescTypeDef          *pOuTerDesc;
  USBD_ClassSpecificVsHeaderDescTypeDef   *pSpHeaDesc;
  USBD_PayloadFormatDescTypeDef           *pPayForDesc;
#ifdef USBD_UVC_FORMAT_UNCOMPRESSED
  USBD_ColorMatchingDescTypeDef           *pColMaDesc;
#endif /* USBD_UVC_FORMAT_UNCOMPRESSED */
  USBD_StandardVCDataEPDescTypeDef        *pSVCDEP;
  USBD_VIDEO_VSFrameDescTypeDef           *pClassSpecVS;

#if USBD_COMPOSITE_USE_IAD == 1
  pIadDesc                          = ((USBD_IadDescTypeDef *)(pConf + *Sze));
  pIadDesc->bLength                 = (uint8_t)sizeof(USBD_IadDescTypeDef);
  pIadDesc->bDescriptorType         = USB_DESC_TYPE_IAD; /* IAD descriptor */
  pIadDesc->bFirstInterface         = pdev->tclasslist[pdev->classId].Ifs[0];
  pIadDesc->bInterfaceCount         = 2U;    /* 2 interfaces */
  pIadDesc->bFunctionClass          = UVC_CC_VIDEO;
  pIadDesc->bFunctionSubClass       = SC_VIDEO_INTERFACE_COLLECTION;
  pIadDesc->bFunctionProtocol       = PC_PROTOCOL_UNDEFINED;
  pIadDesc->iFunction               = 0U; /* String Index */
  *Sze                             += (uint32_t)sizeof(USBD_IadDescTypeDef);
#endif /* USBD_COMPOSITE_USE_IAD == 1 */

  /* Append VIDEO Interface descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, 0U, UVC_CC_VIDEO, 1U, PC_PROTOCOL_UNDEFINED, 0U);

  /* Append Class-specific VC Interface Descriptor to Configuration descriptor*/
  pSVCInDesc = ((USBD_specificVCInDescTypeDef *)(pConf + *Sze));
  pSVCInDesc->bLength = (uint8_t)sizeof(USBD_specificVCInDescTypeDef);
  pSVCInDesc->bDescriptorType = CS_INTERFACE;
  pSVCInDesc->bDescriptorSubtype = VC_HEADER;
  pSVCInDesc->bcdUVC = UVC_VERSION;
  pSVCInDesc->wTotalLength = 0x001EU;
  pSVCInDesc->dwClockFrequency = 0x02DC6C00U;
  pSVCInDesc->baInterfaceNr = 0x01U;
  pSVCInDesc->iTerminal = 0x01U;
  *Sze += (uint32_t)sizeof(USBD_specificVCInDescTypeDef);

  /*Append Input Terminal Descriptor to Configuration descriptor */
  pInTerDesc = ((USBD_InputTerminalDescTypeDef *)(pConf + *Sze));
  pInTerDesc->bLength = (uint8_t)sizeof(USBD_InputTerminalDescTypeDef);
  pInTerDesc->bDescriptorType = CS_INTERFACE;
  pInTerDesc->bDescriptorSubtype = VC_INPUT_TERMINAL;
  pInTerDesc->bTerminalID = 0x01U;
  pInTerDesc->wTerminalType = ITT_VENDOR_SPECIFIC;
  pInTerDesc->bAssocTerminal = 0x00U;
  pInTerDesc->iTerminal =  0x00U;
  *Sze += (uint32_t)sizeof(USBD_InputTerminalDescTypeDef);

  /* Append Output Terminal Descriptor to Configuration descriptor */
  pOuTerDesc = ((USBD_OutputTerminalDescTypeDef *)(pConf + *Sze));
  pOuTerDesc->bLength = (uint8_t)sizeof(USBD_OutputTerminalDescTypeDef);
  pOuTerDesc->bDescriptorType = CS_INTERFACE;
  pOuTerDesc->bDescriptorSubtype = VC_OUTPUT_TERMINAL;
  pOuTerDesc->bTerminalID = 0x02U;
  pOuTerDesc->wTerminalType = TT_STREAMING;
  pOuTerDesc->bAssocTerminal = 0x00U;
  pOuTerDesc->bSourceID = 0x01U;
  pOuTerDesc->iTerminal = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_OutputTerminalDescTypeDef);

  /* Standard VS (Video Streaming) Interface Descriptor */
  /* Interface 1, Alternate Setting 0 = Zero Bandwidth*/
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[1], 0U, 0U, UVC_CC_VIDEO, \
                       SC_VIDEOSTREAMING, PC_PROTOCOL_UNDEFINED, 0U);

  /* Append Class-specific VS Header Descriptor (Input) to Configuration descriptor */
  pSpHeaDesc = ((USBD_ClassSpecificVsHeaderDescTypeDef *)(pConf + *Sze));
  pSpHeaDesc->bLength = (uint8_t)sizeof(USBD_ClassSpecificVsHeaderDescTypeDef);
  pSpHeaDesc->bDescriptorType = CS_INTERFACE;
  pSpHeaDesc->bDescriptorSubtype = VS_INPUT_HEADER;
  pSpHeaDesc->bNumFormats = 0x4D01U;
  pSpHeaDesc->bVideoControlSize = 0x00U;
  pSpHeaDesc->bEndPointAddress = UVC_IN_EP;
  pSpHeaDesc->bmInfo = 0x00U;
  pSpHeaDesc->bTerminalLink = 0x02U;
  pSpHeaDesc->bStillCaptureMethod = 0x00U;
  pSpHeaDesc->bTriggerSupport = 0x00U;
  pSpHeaDesc->bTriggerUsage = 0x00U;
  pSpHeaDesc->bControlSize = 0x01U;
  pSpHeaDesc->bmaControls = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_ClassSpecificVsHeaderDescTypeDef);

  /* Append Payload Format Descriptor to Configuration descriptor */
  pPayForDesc = ((USBD_PayloadFormatDescTypeDef *)(pConf + *Sze));
  pPayForDesc->bLength = (uint8_t)sizeof(USBD_PayloadFormatDescTypeDef);
  pPayForDesc->bDescriptorType = CS_INTERFACE;
  pPayForDesc->bDescriptorSubType = VS_FORMAT_SUBTYPE;
  pPayForDesc->bFormatIndex = 0x01U;
  pPayForDesc->bNumFrameDescriptor = 0x01U;
#ifdef USBD_UVC_FORMAT_UNCOMPRESSED
  (void)USBD_memcpy(pPayForDesc->pGiudFormat, usbd_uvc_guid, 16);
  pPayForDesc->bBitsPerPixel = UVC_BITS_PER_PIXEL;
#else
  pPayForDesc->bmFlags = 0x01U;
#endif /* USBD_UVC_FORMAT_UNCOMPRESSED */
  pPayForDesc->bDefaultFrameIndex = 0x01U;
  pPayForDesc->bAspectRatioX = 0x00U;
  pPayForDesc->bAspectRatioY = 0x00U;
  pPayForDesc->bInterlaceFlags = 0x00U;
  pPayForDesc->bCopyProtect = 0x00U;
  *Sze += (uint32_t)sizeof(USBD_PayloadFormatDescTypeDef);

  /* Append Class-specific VS (Video Streaming) Frame Descriptor to Configuration descriptor */
  pClassSpecVS = ((USBD_VIDEO_VSFrameDescTypeDef *)(pConf + *Sze));
  pClassSpecVS->bLength = (uint8_t)sizeof(USBD_VIDEO_VSFrameDescTypeDef);
  pClassSpecVS->bDescriptorType = CS_INTERFACE;
  pClassSpecVS->bDescriptorSubType = VS_FRAME_SUBTYPE;
  pClassSpecVS->bFrameIndex = 0x01U;

#ifdef USBD_UVC_FORMAT_UNCOMPRESSED
  pClassSpecVS->bmCapabilities = 0x00U;
#else
  pClassSpecVS->bmCapabilities = 0x02U;
#endif /* USBD_UVC_FORMAT_UNCOMPRESSED */

  pClassSpecVS->wWidth = UVC_WIDTH;
  pClassSpecVS->wHeight = UVC_HEIGHT;

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pClassSpecVS->dwMinBitRate = UVC_MIN_BIT_RATE(UVC_CAM_FPS_HS);
    pClassSpecVS->dwMaxBitRate = UVC_MAX_BIT_RATE(UVC_CAM_FPS_HS);
    pClassSpecVS->dwDefaultFrameInterval = UVC_INTERVAL(UVC_CAM_FPS_HS);
    pClassSpecVS->dwMinFrameInterval = UVC_INTERVAL(UVC_CAM_FPS_HS);
  }
  else
  {
    pClassSpecVS->dwMinBitRate = UVC_MIN_BIT_RATE(UVC_CAM_FPS_FS);
    pClassSpecVS->dwMaxBitRate = UVC_MAX_BIT_RATE(UVC_CAM_FPS_FS);
    pClassSpecVS->dwDefaultFrameInterval = UVC_INTERVAL(UVC_CAM_FPS_FS);
    pClassSpecVS->dwMinFrameInterval = UVC_INTERVAL(UVC_CAM_FPS_FS);
  }

  pClassSpecVS->dwMaxVideoFrameBufSize = UVC_MAX_FRAME_SIZE;
  pClassSpecVS->bFrameIntervalType = 0x01U;

  *Sze += (uint32_t)sizeof(USBD_VIDEO_VSFrameDescTypeDef);

#ifdef USBD_UVC_FORMAT_UNCOMPRESSED
  /* Append Color Matching Descriptor to Configuration descriptor */
  pColMaDesc = ((USBD_ColorMatchingDescTypeDef *)(pConf + *Sze));
  pColMaDesc->bLength = (uint8_t)sizeof(USBD_ColorMatchingDescTypeDef);
  pColMaDesc->bDescriptorType = CS_INTERFACE;
  pColMaDesc->bDescriptorSubType = VS_COLORFORMAT;
  pColMaDesc->bColorPrimarie = UVC_COLOR_PRIMARIE;
  pColMaDesc->bTransferCharacteristics = UVC_TFR_CHARACTERISTICS;
  pColMaDesc->bMatrixCoefficients = UVC_MATRIX_COEFFICIENTS;
  *Sze += (uint32_t)sizeof(USBD_ColorMatchingDescTypeDef);
#endif /* USBD_UVC_FORMAT_UNCOMPRESSED */

  /* USB Standard VS Interface  Descriptor - data transfer mode */
  /* Interface 1, Alternate Setting 1*/
  __USBD_CMPSIT_SET_IF(1U, 1U, 1U, UVC_CC_VIDEO, SC_VIDEOSTREAMING, PC_PROTOCOL_UNDEFINED, 0U);

  /* Standard VS (Video Streaming) data Endpoint */
  pSVCDEP = ((USBD_StandardVCDataEPDescTypeDef *)(pConf + *Sze));
  pSVCDEP->bLength = (uint8_t)sizeof(USBD_StandardVCDataEPDescTypeDef);
  pSVCDEP->bDescriptorType = USB_DESC_TYPE_ENDPOINT;
  pSVCDEP->bEndpointAddress = UVC_IN_EP;
  pSVCDEP->bmAttributes = 0x05U;
  pSVCDEP->bInterval = 0x01U;

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pSVCDEP->wMaxPacketSize = UVC_ISO_HS_MPS;
  }
  else
  {
    pSVCDEP->wMaxPacketSize = UVC_ISO_FS_MPS;
  }

  *Sze += (uint32_t)sizeof(USBD_StandardVCDataEPDescTypeDef);

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 2U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_VIDEO == 1 */

#if USBD_CMPSIT_ACTIVATE_PRINTER == 1
/**
  * @brief  USBD_CMPSIT_PRINTERDesc
  *         Configure and Append the PRINTER Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_PRNTDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef *pIfDesc;
  static USBD_EpDescTypeDef *pEpDesc;

  /* Control Interface Descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, 0x02, 0x07, 0x01U, USB_PRNT_BIDIRECTIONAL, 0U);

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pdev->tclasslist[pdev->classId].CurrPcktSze = PRNT_DATA_HS_MAX_PACKET_SIZE;
  }

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[1].add), \
                       (USBD_EP_TYPE_BULK), (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[0].add), \
                       (USBD_EP_TYPE_BULK), (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 1U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_PRINTER == 1 */

#if USBD_CMPSIT_ACTIVATE_CCID == 1
/**
  * @brief  USBD_CMPSIT_CCIDDesc
  *         Configure and Append the CCID Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_CCIDDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  static USBD_IfDescTypeDef *pIfDesc;
  static USBD_EpDescTypeDef *pEpDesc;
  static USBD_CCID_DescTypeDef *pDesc;

  /* Control Interface Descriptor */
  __USBD_CMPSIT_SET_IF(pdev->tclasslist[pdev->classId].Ifs[0], 0U, 0x03, 0x0BU, 0U, 0U, 0U);

  /* Control interface headers */
  pDesc = ((USBD_CCID_DescTypeDef *)((uint32_t)pConf + *Sze));

  /* Device Descriptor */
  pDesc->bLength = 0x36U;
  pDesc->bDescriptorType = 0x21U;
  pDesc->bcdCCID = 0x0110U;
  pDesc->bMaxSlotIndex = 0x00U;
  pDesc->bVoltageSupport = CCID_VOLTAGE_SUPP;
  pDesc->dwProtocols = USBD_CCID_PROTOCOL;
  pDesc->dwDefaultClock = USBD_CCID_DEFAULT_CLOCK_FREQ;
  pDesc->dwMaximumClock = USBD_CCID_MAX_CLOCK_FREQ;
  pDesc->bNumClockSupported = 0x00U;
  pDesc->dwDataRate = USBD_CCID_DEFAULT_DATA_RATE;
  pDesc->dwMaxDataRate = USBD_CCID_MAX_DATA_RATE;
  pDesc->bNumDataRatesSupported = 0x35U;
  pDesc->dwMaxIFSD = USBD_CCID_MAX_INF_FIELD_SIZE;
  pDesc->dwSynchProtocols = 0U;
  pDesc->dwMechanical = 0U;
  pDesc->dwFeatures = 0x000104BAU;
  pDesc->dwMaxCCIDMessageLength = CCID_MAX_BLOCK_SIZE_HEADER;
  pDesc->bClassGetResponse = 0U;
  pDesc->bClassEnvelope = 0U;
  pDesc->wLcdLayout = 0U;
  pDesc->bPINSupport = 0x03U;
  pDesc->bMaxCCIDBusySlots = 0x01U;

  *Sze += (uint32_t)sizeof(USBD_CCID_DescTypeDef);

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pdev->tclasslist[pdev->classId].CurrPcktSze = CCID_DATA_HS_MAX_PACKET_SIZE;
  }

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[0].add), \
                       (USBD_EP_TYPE_BULK), (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[1].add), \
                       (USBD_EP_TYPE_BULK), (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[2].add, \
                       USBD_EP_TYPE_INTR, CCID_CMD_PACKET_SIZE, CCID_CMD_HS_BINTERVAL, CCID_CMD_FS_BINTERVAL);

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 1U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_CCID == 1 */

#if USBD_CMPSIT_ACTIVATE_MTP == 1
/**
  * @brief  USBD_CMPSIT_MTPDesc
  *         Configure and Append the MTP Descriptor
  * @param  pdev: device instance
  * @param  pConf: Configuration descriptor pointer
  * @param  Sze: pointer to the current configuration descriptor size
  * @retval None
  */
static void  USBD_CMPSIT_MTPDesc(USBD_HandleTypeDef *pdev, uint32_t pConf, __IO uint32_t *Sze, uint8_t speed)
{
  USBD_IfDescTypeDef *pIfDesc;
  USBD_EpDescTypeDef *pEpDesc;

  /* Append MTP Interface descriptor */
  __USBD_CMPSIT_SET_IF((pdev->tclasslist[pdev->classId].Ifs[0]), (0U), \
                       (uint8_t)(pdev->tclasslist[pdev->classId].NumEps), USB_MTP_INTRERFACE_CLASS, \
                       USB_MTP_INTRERFACE_SUB_CLASS, USB_MTP_INTRERFACE_PROTOCOL, (0U));

  if (speed == (uint8_t)USBD_SPEED_HIGH)
  {
    pdev->tclasslist[pdev->classId].CurrPcktSze = MTP_DATA_MAX_HS_PACKET_SIZE;
  }

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[0].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP((pdev->tclasslist[pdev->classId].Eps[1].add), (USBD_EP_TYPE_BULK), \
                       (pdev->tclasslist[pdev->classId].CurrPcktSze), (0U), (0U));

  /* Append Endpoint descriptor to Configuration descriptor */
  __USBD_CMPSIT_SET_EP(pdev->tclasslist[pdev->classId].Eps[2].add, \
                       USBD_EP_TYPE_INTR, MTP_CMD_PACKET_SIZE, MTP_HS_BINTERVAL, MTP_FS_BINTERVAL);

  /* Update Config Descriptor and IAD descriptor */
  ((USBD_ConfigDescTypeDef *)pConf)->bNumInterfaces += 1U;
  ((USBD_ConfigDescTypeDef *)pConf)->wTotalLength = (uint16_t)(*Sze);
}
#endif /* USBD_CMPSIT_ACTIVATE_MTP == 1 */

/**
  * @brief  USBD_CMPSIT_SetClassID
  *         Find and set the class ID relative to selected class type and instance
  * @param  pdev: device instance
  * @param  Class: Class type, can be CLASS_TYPE_NONE if requested to find class from setup request
  * @param  Instance: Instance number of the class (0 if first/unique instance, >0 otherwise)
  * @retval The Class ID, The pdev->classId is set with the value of the selected class ID.
  */
uint32_t  USBD_CMPSIT_SetClassID(USBD_HandleTypeDef *pdev, USBD_CompositeClassTypeDef Class, uint32_t Instance)
{
  uint32_t idx;
  uint32_t inst = 0U;

  /* Unroll all already activated classes */
  for (idx = 0U; idx < pdev->NumClasses; idx++)
  {
    /* Check if the class correspond to the requested type and if it is active */
    if (((USBD_CompositeClassTypeDef)(pdev->tclasslist[idx].ClassType) == Class) &&
        ((pdev->tclasslist[idx].Active) == 1U))
    {
      if (inst == Instance)
      {
        /* Set the new class ID */
        pdev->classId = idx;

        /* Return the class ID value */
        return (idx);
      }
      else
      {
        /* Increment instance index and look for next instance */
        inst++;
      }
    }
  }

  /* No class found, return 0xFF */
  return 0xFFU;
}

/**
  * @brief  USBD_CMPSIT_GetClassID
  *         Returns the class ID relative to selected class type and instance
  * @param  pdev: device instance
  * @param  Class: Class type, can be CLASS_TYPE_NONE if requested to find class from setup request
  * @param  Instance: Instance number of the class (0 if first/unique instance, >0 otherwise)
  * @retval The Class ID (this function does not set the pdev->classId field.
  */
uint32_t  USBD_CMPSIT_GetClassID(USBD_HandleTypeDef *pdev, USBD_CompositeClassTypeDef Class, uint32_t Instance)
{
  uint32_t idx;
  uint32_t inst = 0U;

  /* Unroll all already activated classes */
  for (idx = 0U; idx < pdev->NumClasses; idx++)
  {
    /* Check if the class correspond to the requested type and if it is active */
    if (((USBD_CompositeClassTypeDef)(pdev->tclasslist[idx].ClassType) == Class) &&
        ((pdev->tclasslist[idx].Active) == 1U))
    {
      if (inst == Instance)
      {
        /* Return the class ID value */
        return (idx);
      }
      else
      {
        /* Increment instance index and look for next instance */
        inst++;
      }
    }
  }

  /* No class found, return 0xFF */
  return 0xFFU;
}

/**
  * @brief  USBD_CMPST_ClearConfDesc
  *         Reset the configuration descriptor
  * @param  pdev: device instance (reserved for future use)
  * @retval Status.
  */
uint8_t USBD_CMPST_ClearConfDesc(USBD_HandleTypeDef *pdev)
{
  UNUSED(pdev);

  /* Reset the configuration descriptor pointer to default value and its size to zero */
  pCmpstFSConfDesc = USBD_CMPSIT_FSCfgDesc;
  CurrFSConfDescSz = 0U;

#ifdef USE_USB_HS
  pCmpstHSConfDesc = USBD_CMPSIT_HSCfgDesc;
  CurrHSConfDescSz = 0U;
#endif /* USE_USB_HS */

  /* All done, can't fail */
  return (uint8_t)USBD_OK;
}

#endif /* USE_USBD_COMPOSITE */

4.3 修改端点的地址

cdc的在usbd_cdc.h中,

#ifndef CDC_IN_EP
#define CDC_IN_EP                                   0x81U  /* EP1 for data IN */
#endif /* CDC_IN_EP */
#ifndef CDC_OUT_EP
#define CDC_OUT_EP                                  0x01U  /* EP1 for data OUT */
#endif /* CDC_OUT_EP */
#ifndef CDC_CMD_EP
#define CDC_CMD_EP                                  0x82U  /* EP2 for CDC commands */
#endif /* CDC_CMD_EP  */

msc的在usbd_msc.h中

#ifndef MSC_EPIN_ADDR
#define MSC_EPIN_ADDR                0x83U
#endif /* MSC_EPIN_ADDR */

#ifndef MSC_EPOUT_ADDR
#define MSC_EPOUT_ADDR               0x03U
#endif /* MSC_EPOUT_ADDR */

4.4 修改设备类的添加函数,内部涉及接口、端点、类型等

在文件usbd_composite_builder.c中,根据类型和classID填充不同的参数,完整代码见4.2

uint8_t  USBD_CMPSIT_AddClass(USBD_HandleTypeDef *pdev,
                              USBD_ClassTypeDef *pclass,
                              USBD_CompositeClassTypeDef class,
                              uint8_t cfgidx)
{
	switch(class)
	{
		case CLASS_TYPE_CDC:{
			pdev->tclasslist[pdev->classId].ClassType = CLASS_TYPE_CDC;

			pdev->tclasslist[pdev->classId].Active = 1U;
			pdev->tclasslist[pdev->classId].NumEps = 3;

			pdev->tclasslist[pdev->classId].Eps[0].add = CDC_CMD_EP;
			pdev->tclasslist[pdev->classId].Eps[0].type = USBD_EP_TYPE_INTR;
			pdev->tclasslist[pdev->classId].Eps[0].size = CDC_CMD_PACKET_SIZE;
			pdev->tclasslist[pdev->classId].Eps[0].is_used = 1U;

			pdev->tclasslist[pdev->classId].Eps[1].add = CDC_OUT_EP;
			pdev->tclasslist[pdev->classId].Eps[1].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[1].size = CDC_DATA_FS_MAX_PACKET_SIZE;
			pdev->tclasslist[pdev->classId].Eps[1].is_used = 1U;

			pdev->tclasslist[pdev->classId].Eps[2].add = CDC_IN_EP;
			pdev->tclasslist[pdev->classId].Eps[2].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[2].size = CDC_DATA_FS_MAX_PACKET_SIZE;
			pdev->tclasslist[pdev->classId].Eps[2].is_used = 1U;

			pdev->tclasslist[pdev->classId].NumIf = 2;
			pdev->tclasslist[pdev->classId].Ifs[0] = 0;
			pdev->tclasslist[pdev->classId].Ifs[1] = 1;

		}break;

		case CLASS_TYPE_MSC:{
			pdev->tclasslist[pdev->classId].ClassType = CLASS_TYPE_MSC;

			pdev->tclasslist[pdev->classId].Active = 1U;
			pdev->tclasslist[pdev->classId].NumEps = 2;

			pdev->tclasslist[pdev->classId].Eps[0].add = MSC_EPIN_ADDR;
			pdev->tclasslist[pdev->classId].Eps[0].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[0].size = MSC_MAX_FS_PACKET;
			pdev->tclasslist[pdev->classId].Eps[0].is_used = 1U;

			pdev->tclasslist[pdev->classId].Eps[1].add = MSC_EPOUT_ADDR;
			pdev->tclasslist[pdev->classId].Eps[1].type = USBD_EP_TYPE_BULK;
			pdev->tclasslist[pdev->classId].Eps[1].size = MSC_MAX_FS_PACKET;
			pdev->tclasslist[pdev->classId].Eps[1].is_used = 1U;


			pdev->tclasslist[pdev->classId].NumIf = 1;
			pdev->tclasslist[pdev->classId].Ifs[0] = 2;

		}break;
		default:break;
	}
	pdev->tclasslist[pdev->classId].CurrPcktSze = 0U;

  return (uint8_t)USBD_OK;
}

4.5 在usbd_conf.c中修改端点发送fifo配置

USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
{
  /* Init USB Ip. */
  if (pdev->id == DEVICE_FS) {
  /* Link the driver to the stack. */
  hpcd_USB_OTG_FS.pData = pdev;
  pdev->pData = &hpcd_USB_OTG_FS;

  hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
  hpcd_USB_OTG_FS.Init.dev_endpoints = 9;
  hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
  hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
  hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
  hpcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
  hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
  hpcd_USB_OTG_FS.Init.lpm_enable = DISABLE;
  hpcd_USB_OTG_FS.Init.battery_charging_enable = DISABLE;
  hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
  hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;
  if (HAL_PCD_Init(&hpcd_USB_OTG_FS) != HAL_OK)
  {
    Error_Handler( );
  }

#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
  /* Register USB PCD CallBacks */
  HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_SOF_CB_ID, PCD_SOFCallback);
  HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback);
  HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_RESET_CB_ID, PCD_ResetCallback);
  HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback);
  HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback);
  HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback);
  HAL_PCD_RegisterCallback(&hpcd_USB_OTG_FS, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback);

  HAL_PCD_RegisterDataOutStageCallback(&hpcd_USB_OTG_FS, PCD_DataOutStageCallback);
  HAL_PCD_RegisterDataInStageCallback(&hpcd_USB_OTG_FS, PCD_DataInStageCallback);
  HAL_PCD_RegisterIsoOutIncpltCallback(&hpcd_USB_OTG_FS, PCD_ISOOUTIncompleteCallback);
  HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_OTG_FS, PCD_ISOINIncompleteCallback);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
  /* USER CODE BEGIN TxRx_Configuration */
  HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80);
  HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40);
  HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x40);
  HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 3, 0x40);
  /* USER CODE END TxRx_Configuration */
  }
  return USBD_OK;
}

在usbd_conf.h中修改支持最大接口数,同时修改此文件中的malloc和free函数

#define USBD_MAX_NUM_INTERFACES     3U


#define USBD_malloc         malloc//(void *)USBD_static_malloc

/** Alias for memory release. */
#define USBD_free           free//USBD_static_free

4.6 修改设备描述符
  因现在是复合设备,则需要修改usbd_desc.c中的设备描述符:

__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
  0x12,                       /*bLength */
  USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/
  0x00,                       /*bcdUSB */
  0x02,
  0xEF,                       /*bDeviceClass*/
  0x02,                       /*bDeviceSubClass*/
  0x01,                       /*bDeviceProtocol*/
  USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
  LOBYTE(USBD_VID),           /*idVendor*/
  HIBYTE(USBD_VID),           /*idVendor*/
  LOBYTE(USBD_PID_FS),        /*idProduct*/
  HIBYTE(USBD_PID_FS),        /*idProduct*/
  0x00,                       /*bcdDevice rel. 2.00*/
  0x02,
  USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
  USBD_IDX_PRODUCT_STR,       /*Index of product string*/
  USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
  USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
};

4.7 修改cdc的一些函数

usbd_cdc_if.c中的CDC_Init_FS(),CDC_Transmit_FS()函数

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : usbd_cdc_if.c
  * @version        : v1.0_Cube
  * @brief          : Usb device for Virtual Com Port.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "usbd_cdc_if.h"

/* USER CODE BEGIN INCLUDE */

/* USER CODE END INCLUDE */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
  * @brief Usb device library.
  * @{
  */

/** @addtogroup USBD_CDC_IF
  * @{
  */

/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions
  * @brief Private types.
  * @{
  */

/* USER CODE BEGIN PRIVATE_TYPES */

/* USER CODE END PRIVATE_TYPES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines
  * @brief Private defines.
  * @{
  */

/* USER CODE BEGIN PRIVATE_DEFINES */
/* USER CODE END PRIVATE_DEFINES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros
  * @brief Private macros.
  * @{
  */

/* USER CODE BEGIN PRIVATE_MACRO */

/* USER CODE END PRIVATE_MACRO */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables
  * @brief Private variables.
  * @{
  */
/* Create buffer for reception and transmission           */
/* It's up to user to redefine and/or remove those define */
/** Received data over USB are stored in this buffer      */
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];

/** Data to send over USB CDC are stored in this buffer   */
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];

/* USER CODE BEGIN PRIVATE_VARIABLES */

/* USER CODE END PRIVATE_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables
  * @brief Public variables.
  * @{
  */

extern USBD_HandleTypeDef hUsbDeviceFS;

/* USER CODE BEGIN EXPORTED_VARIABLES */

/* USER CODE END EXPORTED_VARIABLES */

/**
  * @}
  */

/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes
  * @brief Private functions declaration.
  * @{
  */

static int8_t CDC_Init_FS(void);
static int8_t CDC_DeInit_FS(void);
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
static int8_t CDC_TransmitCplt_FS(uint8_t *pbuf, uint32_t *Len, uint8_t epnum);

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

/**
  * @}
  */

USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
{
  CDC_Init_FS,
  CDC_DeInit_FS,
  CDC_Control_FS,
  CDC_Receive_FS,
  CDC_TransmitCplt_FS
};

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  Initializes the CDC media low layer over the FS USB IP
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_Init_FS(void)
{
  /* USER CODE BEGIN 3 */
  USBD_HandleTypeDef *pdev = &hUsbDeviceFS;
  uint8_t idx = USBD_CoreFindEP(pdev, CDC_IN_EP);
  /* Set Application Buffers */
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0,idx);
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
  return (USBD_OK);
  /* USER CODE END 3 */
}

/**
  * @brief  DeInitializes the CDC media low layer
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_DeInit_FS(void)
{
  /* USER CODE BEGIN 4 */
  return (USBD_OK);
  /* USER CODE END 4 */
}

/**
  * @brief  Manage the CDC class requests
  * @param  cmd: Command code
  * @param  pbuf: Buffer containing command data (request parameters)
  * @param  length: Number of data to be sent (in bytes)
  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
  /* USER CODE BEGIN 5 */
  switch(cmd)
  {
    case CDC_SEND_ENCAPSULATED_COMMAND:

    break;

    case CDC_GET_ENCAPSULATED_RESPONSE:

    break;

    case CDC_SET_COMM_FEATURE:

    break;

    case CDC_GET_COMM_FEATURE:

    break;

    case CDC_CLEAR_COMM_FEATURE:

    break;

  /*******************************************************************************/
  /* Line Coding Structure                                                       */
  /*-----------------------------------------------------------------------------*/
  /* Offset | Field       | Size | Value  | Description                          */
  /* 0      | dwDTERate   |   4  | Number |Data terminal rate, in bits per second*/
  /* 4      | bCharFormat |   1  | Number | Stop bits                            */
  /*                                        0 - 1 Stop bit                       */
  /*                                        1 - 1.5 Stop bits                    */
  /*                                        2 - 2 Stop bits                      */
  /* 5      | bParityType |  1   | Number | Parity                               */
  /*                                        0 - None                             */
  /*                                        1 - Odd                              */
  /*                                        2 - Even                             */
  /*                                        3 - Mark                             */
  /*                                        4 - Space                            */
  /* 6      | bDataBits  |   1   | Number Data bits (5, 6, 7, 8 or 16).          */
  /*******************************************************************************/
    case CDC_SET_LINE_CODING:

    break;

    case CDC_GET_LINE_CODING:
    	pbuf[0] = (uint8_t)(115200);
    	pbuf[1] = (uint8_t)(115200 >> 8);
    	pbuf[2] = (uint8_t)(115200 >> 16);
    	pbuf[3] = (uint8_t)(115200 >> 24);
    	pbuf[4] = 0;  // stop bits (1)
    	pbuf[5] = 0;  // parity (none)
    	pbuf[6] = 8;  // number of bits (8)
    break;

    case CDC_SET_CONTROL_LINE_STATE:

    break;

    case CDC_SEND_BREAK:

    break;

  default:
    break;
  }

  return (USBD_OK);
  /* USER CODE END 5 */
}

/**
  * @brief  Data received over USB OUT endpoint are sent over CDC interface
  *         through this function.
  *
  *         @note
  *         This function will issue a NAK packet on any OUT packet received on
  *         USB endpoint until exiting this function. If you exit this function
  *         before transfer is complete on CDC interface (ie. using DMA controller)
  *         it will result in receiving more data while previous ones are still
  *         not sent.
  *
  * @param  Buf: Buffer of data to be received
  * @param  Len: Number of data received (in bytes)
  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);

  CDC_Transmit_FS(Buf, *Len);
  return (USBD_OK);
  /* USER CODE END 6 */
}

/**
  * @brief  CDC_Transmit_FS
  *         Data to send over USB IN endpoint are sent over CDC interface
  *         through this function.
  *         @note
  *
  *
  * @param  Buf: Buffer of data to be sent
  * @param  Len: Number of data to be sent (in bytes)
  * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
  */
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
#if 0
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if (hcdc->TxState != 0){
    return USBD_BUSY;
  }
  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
  /* USER CODE END 7 */
  return result;
#else
    uint8_t result = USBD_OK;
    USBD_HandleTypeDef *pdev = &hUsbDeviceFS;

    /* Get the class index relative to this endpoint */
    uint8_t idx = USBD_CoreFindEP(pdev, CDC_IN_EP);
    if (((uint8_t)idx != 0xFFU) && (idx < USBD_MAX_SUPPORTED_CLASS))
    {
      pdev->classId = idx;

      USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassDataCmsit[pdev->classId];
      if (hcdc->TxState != 0){
        return USBD_BUSY;
      }
      USBD_CDC_SetTxBuffer(pdev, Buf, Len, idx);
      result = USBD_CDC_TransmitPacket(pdev,idx);

      return result;
    }

    return USBD_FAIL;
#endif
}

/**
  * @brief  CDC_TransmitCplt_FS
  *         Data transmitted callback
  *
  *         @note
  *         This function is IN transfer complete callback used to inform user that
  *         the submitted Data is successfully sent over USB.
  *
  * @param  Buf: Buffer of data to be received
  * @param  Len: Number of data received (in bytes)
  * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 13 */
  UNUSED(Buf);
  UNUSED(Len);
  UNUSED(epnum);
  /* USER CODE END 13 */
  return result;
}

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */

/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

4.8 在工程中增加复合类的宏变量USE_USBD_COMPOSITE

或者可以在main.h中定义该宏

4.9 修改usb的初始化函数

将cdc和msc的类注册到复合设备类中,注意注册的接口和类顺序,否则会出问题,需要和设备描述符中的描述一致,先是cdc,在是msc,usb_device.c中修改如下。需要添加几个头文件

#include "usbd_cdc.h"
#include "usbd_cdc_if.h"
#include "usbd_composite_builder.h"

void MX_USB_DEVICE_Init(void)
{
  /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */

  /* USER CODE END USB_DEVICE_Init_PreTreatment */

  /* Init Device Library, add supported class and start the library. */
#if 0
  if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
  {
    Error_Handler();
  }
  if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_MSC) != USBD_OK)
  {
    Error_Handler();
  }
  if (USBD_MSC_RegisterStorage(&hUsbDeviceFS, &USBD_Storage_Interface_fops_FS) != USBD_OK)
  {
    Error_Handler();
  }
  if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
  {
    Error_Handler();
  }

  /* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */
  HAL_PWREx_EnableUSBVoltageDetector();

  /* USER CODE END USB_DEVICE_Init_PostTreatment */
#endif


  if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
    {
      Error_Handler();
    }

    if(USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK)
    {
      Error_Handler();
    }

    if(USBD_RegisterClassComposite(&hUsbDeviceFS, &USBD_CDC,CLASS_TYPE_CDC,0) != USBD_OK)
    {
      Error_Handler();
    }

    if (USBD_MSC_RegisterStorage(&hUsbDeviceFS, &USBD_Storage_Interface_fops_FS) != USBD_OK)
    {
      Error_Handler();
    }

    if(USBD_RegisterClassComposite(&hUsbDeviceFS, &USBD_MSC,CLASS_TYPE_MSC,0) != USBD_OK)
    {
      Error_Handler();
    }

    if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
    {
      Error_Handler();
    }

}

4.10,编译运行,效果如下

由于盘符是数组模拟的,故每次上电后都需要格式化一次。

2023.10.19   西安北郊,随时欢迎各位来西安游玩。

  • 15
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值