※ The full source code is here.
There is some posts discussion about how to implementation an USB composite device on stm32, like this, this, this and this. But I could not find out a post to illustrate how to deal with a 3-classese composite device. After my study, it is more tricky to implement a 3-classe device than 2 classes, and those tricks do not been mentioned on the posts. This post is to record those tricks, to help the people want to implement an USB composite device on stm32.
Here I use custom Human Interface Device(HID) + Communication Device Class(CDC, also call com port) + Mass Storage Class(MSC) as the example, which is the single most common use-case for a 3 classes USB compsoite device.
零. Check the max endpoint number of your STM32.
I use stm32F103 in this example, and stm32F103 supports with USB full speed mode only.
For Custom HID + CDC + MSC device, the amount of the endpoints are : 1 USB controling (called EP0), 2 for CDC(1 control + 1 data), 1 for MSC, and 1 for custom HID, totally those are five endpoints.
But Not all stm32 meet this requirement on the full speed mode: for example, STM32F2XX and STM32F4XX on full speed mode, there are only 4 endpoints. So, Here I use stm32F103, which support 8 endpoins.
壹. Use STM32CubeIDE to generate the USB classes code, and make sure they can work individually.
As you know, while the ioc setting changed, would delete the previous generated code. So it is necessary to backup the generated USB class code then copy back.
甲. Bring CustomHID working
On the ico for USB Device customHID setting, we set USBD_CUSTOMHID_OUTREPORT_BUF_SIZE as 32.
After the code generated, we modify CUSTOM_HID_ReportDesc_FS, which locates at the File USB_DEVICE\App\usbd_custom_hid_if.c , as :
: /** Usb HID report descriptor. */ __ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END = { /* USER CODE BEGIN 0 */ 0x05, 0xFF, // USAGE_PAGE(User define) 0x09, 0xFF, // USAGE(User define) 0xa1, 0x01, // COLLECTION (Application) /* 6 Bytes*/ // The Input report 0x05, 0x01, // USAGE_PAGE(1) 0x19, 0x00, // USAGE_MINIMUM(0) 0x29, 0xFF, // USAGE_MAXIMUM(255) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0xFF, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE, // REPORT_COUNT (USBD_CUSTOMHID_OUTREPORT_BUF_SIZE) 0x81, 0x02, // INPUT (Data,Var,Abs) /* 22 Bytes */ // The Output report 0x05, 0x02, // USAGE_PAGE(2) 0x19, 0x00, // USAGE_MINIMUM (0) 0x29, 0xFF, // USAGE_MAXIMUM (255) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0xFF, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE, // REPORT_COUNT (USBD_CUSTOMHID_OUTREPORT_BUF_SIZE) 0x91, 0x02, // OUTPUT (Data,Var,Abs) /* 38 Bytes */ /* USER CODE END 0 */ 0xC0 /* END_COLLECTION */ }; /* USER CODE BEGIN PRIVATE_VARIABLES */ /* USER CODE END PRIVATE_VARIABLES */ /** * @} */ /** @defgroup USBD_CUSTOM_HID_Exported_Variables USBD_CUSTOM_HID_Exported_Variables * @brief Public variables. * @{ */ extern USBD_HandleTypeDef hUsbDeviceFS; :
※ The HID descriptor could be generated by the program, HID Descriptor Tool, provided by USB org.
That structure means, for both input(device to host) and output, the packet size are 32 bytes.
The remain part is to make sure the customHID workable, that is very straightforword : to create the input and output interfaces for relaying the input to the UART, and responding to the output while the button pressed :
USB_DEVICE\App\usbd_custom_hid_if.c :
: /** * @brief Manage the CUSTOM HID class events * @param event_idx: Event index * @param state: Event state * @retval USBD_OK if all operations are OK else USBD_FAIL */ static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state) { /* USER CODE BEGIN 6 */ UNUSED(event_idx); UNUSED(state); USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef *)hUsbDeviceFS.pClassData; uint32_t usb_recv_len = USBD_GetRxCount(&hUsbDeviceFS, CUSTOM_HID_EPOUT_ADDR); PRINTF("Custom HID::usb_recv_len = %u\r\n", usb_recv_len); PRINTF("Custom HID::received data = "); for(uint32_t i = 0; i < usb_recv_len; i++) PRINTF_NO_COMNAME("%02X ", hhid->Report_buf[i]); PRINTF_NO_COMNAME("\r\n"); return (USBD_OK); /* USER CODE END 6 */ } /* USER CODE BEGIN 7 */ /** * @brief Send the report to the Host * @param report: The report to be sent * @param len: The report length * @retval USBD_OK if all operations are OK else USBD_FAIL */ static int8_t USBD_CUSTOM_HID_SendReport_FS(uint8_t *report, uint16_t len) { return USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, report, len); } /* USER CODE END 7 */ /* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */ int8_t USBD_CUSTOM_HID_Send(uint8_t data[USBD_CUSTOMHID_OUTREPORT_BUF_SIZE]) { return USBD_CUSTOM_HID_SendReport_FS(&data[0], USBD_CUSTOMHID_OUTREPORT_BUF_SIZE); } /* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */
main.c :
: uint32_t k = 0; while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if (true == s_is_GPIO_EXTI) { switch (s_GPIO_Pin) { case KEY0_Pin: { if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)) { HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET); PRINTF("KEY0 pushed\r\n"); uint8_t customhid_data[USBD_CUSTOMHID_OUTREPORT_BUF_SIZE] = {0}; memcpy(&customhid_data[0], &k, sizeof(uint32_t)); USBD_CUSTOM_HID_Send(&customhid_data[0]); PRINTF("k = %u\r\n", k); k++; } else { HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET); PRINTF("KEY0 released\r\n"); } :
To make sure it works, it could use ST's USB HID Demonstrator(installation is required) for testing.
乙. Bring CDC working
The parameters on the ico for CDC are all default, we directly use the auto-generated code. But we rename the variable from USBD_Interface_fops_FS to USBD_CDC_Interface_fops_FS, as below:
: // the original name was USBD_Interface_fops_FS USBD_CDC_ItfTypeDef USBD_CDC_Interface_fops_FS = { CDC_Init_FS, CDC_DeInit_FS, CDC_Control_FS, CDC_Receive_FS }; :
that makes the variable meaning be much more clear and explicit while we do the compositing work.
丙. Bring MSC working
Change the parameter MSC_MEDIA_PACKET on the ioc, as the integer multiple of your flash sector size. If you are using a common SD card, most of them are sector size 512 bytes (but a little bit is 1024). Here MSC_MEDIA_PACKET is set as 512.
After the code generated, we need to implement the spi-diskio layer for usbd_storage_if.c using. The implementation is as this post. But we rename the spi-diskio file names from user_diskio_spi to spi-diskio, and the function names from USER_SPI_xx (like, USER_SPI_read) to spi_diskio_xx (like, spi_diskio_read).
That post is good, that does work. However, one insufficiency needs to be improved : there is the possibility to reset the SD card fail. So it needs to add the retry loop in the diskio initialization:
inline DSTATUS spi_diskio_initialize ( BYTE drv /* Physical drive number (0) */ ) { : FCLK_SLOW(); for (n = 10; n; n--) xchg_spi(0xFF); /* Send 80 dummy clocks */ ty = 0; uint32_t retry_times = 0; do { if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI/Idle state */ SPI_Timer_On(1000); /* Initialization timeout = 1 sec */ if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */ if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */ while (SPI_Timer_Status() && send_cmd(ACMD41, 1UL << 30)) ; /* Wait for end of initialization with ACMD41(HCS) */ if (SPI_Timer_Status() && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */ } } } else { /* Not SDv2 card */ if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */ ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */ } else { ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */ } while (SPI_Timer_Status() && send_cmd(cmd, 0)) ; /* Wait for end of initialization */ if (!SPI_Timer_Status() || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */ ty = 0; } break; } retry_times++; SPI_Timer_On(1000); #define MAX_PUT_SPI_IDLE_STATE_RETRY_TIMES (100) }while(retry_times < MAX_PUT_SPI_IDLE_STATE_RETRY_TIMES); //printf("retry_times = %lu\r\n", retry_times); CardType = ty; /* Card type */ despiselect(); :
To here, the implementation of the functions at the file USB_DEVICE\App\usbd_storage_if.c is simple, just pass the arguments to spi-diskio, as below :
/* Private functions ---------------------------------------------------------*/ /** * @brief Initializes over USB FS IP * @param lun: * @retval USBD_OK if all operations are OK else USBD_FAIL */ int8_t STORAGE_Init_FS(uint8_t lun) { /* USER CODE BEGIN 2 */ spi_diskio_initialize(0); return (USBD_OK); /* USER CODE END 2 */ } /** * @brief . * @param lun: . * @param block_num: . * @param 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 */ spi_diskio_ioctl(0, GET_SECTOR_COUNT, block_num); spi_diskio_ioctl(0, GET_SECTOR_SIZE, block_size); return (USBD_OK); /* USER CODE END 3 */ } /** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */ int8_t STORAGE_IsReady_FS(uint8_t lun) { /* USER CODE BEGIN 4 */ return (USBD_OK); /* USER CODE END 4 */ } /** * @brief . * @param lun: . * @retval USBD_OK if all operations are OK else USBD_FAIL */ int8_t STORAGE_IsWriteProtected_FS(uint8_t lun) { /* USER CODE BEGIN 5 */ return (USBD_OK); /* USER CODE END 5 */ } /** * @brief . * @param lun: . * @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 */ PRINTF("%s :: blk_addr = %lu, blk_len = %u\r\n", __FUNCTION__, blk_addr, blk_len); spi_diskio_read(0, buf, blk_addr, blk_len); return (USBD_OK); /* USER CODE END 6 */ } /** * @brief . * @param lun: . * @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 */ PRINTF("%s :: blk_addr = %lu, blk_len = %u\r\n", __FUNCTION__, blk_addr, blk_len); spi_diskio_write(0, buf, blk_addr, blk_len); return (USBD_OK); /* USER CODE END 7 */ } /** * @brief . * @param None * @retval . */ 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 */ :
#ifndef _USBD_COMPOSITE_HANDLES_H_ #define _USBD_COMPOSITE_HANDLES_H_ #include "usbd_customhid.h" #include "usbd_cdc.h" #include "usbd_custom_hid_if.h" #include "usbd_cdc_if.h" #include "usbd_msc.h" #include "usbd_storage_if.h" USBD_CUSTOM_HID_HandleTypeDef* GetCustomHIDHandlePtr(void); USBD_CDC_HandleTypeDef* GetCDCHandlePtr(void); USBD_MSC_BOT_HandleTypeDef* GetMSCBOTHandlePtr(void); void SwitchHandleInterfaceToCustomHID(USBD_HandleTypeDef *pdev); void SwitchHandleInterfaceToCDC(USBD_HandleTypeDef *pdev); void SwitchHandleInterfaceToMSC(USBD_HandleTypeDef *pdev); #endif /* _USBD_COMPOSITE_HANDLES_H_ */
#include "usbd_composite_handles.h"
static USBD_CUSTOM_HID_HandleTypeDef s_p_custom_hid_handle;
static USBD_CDC_HandleTypeDef s_cdc_handle;
static USBD_MSC_BOT_HandleTypeDef s_msc_bot_handle;
/*******************************************************************************/
USBD_CUSTOM_HID_HandleTypeDef* GetCustomHIDHandlePtr(void){ return &s_p_custom_hid_handle;}
USBD_CDC_HandleTypeDef* GetCDCHandlePtr(void){ return &s_cdc_handle;}
USBD_MSC_BOT_HandleTypeDef* GetMSCBOTHandlePtr(void){ return &s_msc_bot_handle;}
/*******************************************************************************/
void SwitchHandleInterfaceToCustomHID(USBD_HandleTypeDef *pdev)
{
pdev->pUserData = &USBD_CustomHID_fops_FS;
pdev->pClassData = &s_p_custom_hid_handle;
}
:
: void *USBD_static_malloc(uint32_t size) { if(size == sizeof(USBD_CUSTOM_HID_HandleTypeDef)) return GetCustomHIDHandlePtr(); if(size == sizeof(USBD_CDC_HandleTypeDef)) return GetCDCHandlePtr(); if(size == sizeof(USBD_MSC_BOT_HandleTypeDef)) return GetMSCBOTHandlePtr(); return NULL; } :
#ifndef _USBD_CustomHID_CDC_MSC_COMPOSITE_H_ #define _USBD_CustomHID_CDC_MSC_COMPOSITE_H_ #include "usbd_customhid.h" #include "usbd_custom_hid_if.h" #include "usbd_cdc.h" #include "usbd_cdc_if.h" #include "usbd_msc.h" #include "usbd_storage_if.h" extern USBD_ClassTypeDef USBD_CustomHID_CDC_MSC_COMPOSITE; #endif
#define USBD_IAD_DESC_SIZE 0x08 #define USBD_IAD_DESCRIPTOR_TYPE 0x0B #ifdef USBD_MAX_NUM_INTERFACES #undef USBD_MAX_NUM_INTERFACES #endif #define USBD_MAX_NUM_INTERFACES 4 /*1 for Custom HID, 2 for CDC, 1 for MSC */ #define USBD_CUSTOM_HID_INTERFACE_NUM 1 /* CUSTOM_HID Interface NUM */ #define USBD_CUSTOM_HID_INTERFACE 0 #define USBD_CDC_INTERFACE_NUM 2 /* CDC Interface NUM */ #define USBD_CDC_FIRST_INTERFACE 1 /* CDC FirstInterface */ #define USBD_CDC_CMD_INTERFACE 1 #define USBD_CDC_DATA_INTERFACE 2 #define USBD_MSC_INTERFACE_NUM 1 /* MSC Interface NUM */ #define USBD_MSC_FIRST_INTERFACE 3 #define USBD_MSC_INTERFACE 3 #define CUSTOM_HID_INDATA_NUM (CUSTOM_HID_EPIN_ADDR & 0x0F) #define CUSTOM_HID_OUTDATA_NUM (CUSTOM_HID_EPOUT_ADDR & 0x0F) #define CDC_INDATA_NUM (CDC_IN_EP & 0x0F) #define CDC_OUTDATA_NUM (CDC_OUT_EP & 0x0F) #define CDC_OUTCMD_NUM (CDC_CMD_EP & 0x0F) #define MSC_INDATA_NUM (MSC_EPIN_ADDR & 0x0F) #define MSC_OUTDATA_NUM (MSC_EPOUT_ADDR & 0x0F)
__ALIGN_BEGIN uint8_t USBD_CustomHID_CDC_MSC_Composite_CfgFSDesc[USBD_CUSTOMHID_CDC_MSC_COMPOSITE_DESC_SIZE] __ALIGN_END = { 0x09, /* bLength: Configuation Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ WBVAL(USBD_CUSTOMHID_CDC_MSC_COMPOSITE_DESC_SIZE), USBD_MAX_NUM_INTERFACES , /* bNumInterfaces: */ 0x01, /* bConfigurationValue: */ 0x00, /* iConfiguration: */ 0xC0, /* bmAttributes: self powered */ 0x00, /* MaxPower 0 mA */ /***************************CUSTOM HID********************************/ /*Interface Descriptor */ 0x09, /*bLength: Interface Descriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ USBD_CUSTOM_HID_INTERFACE, /*bInterfaceNumber: Number of Interface*/ 0x00, /*bAlternateSetting: Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass: CUSTOM_HID*/ 0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/ 0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ 0x00, /*iInterface: Index of string descriptor*/ /******************** Descriptor of CUSTOM_HID *************************/ 0x09, /*bLength: CUSTOM_HID Descriptor size*/ CUSTOM_HID_DESCRIPTOR_TYPE, /*bDescriptorType: CUSTOM_HID*/ 0x11, /*bCUSTOM_HIDUSTOM_HID: CUSTOM_HID Class Spec release number*/ 0x01, 0x00, /*bCountryCode: Hardware target country*/ 0x01, /*bNumDescriptors: Number of CUSTOM_HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ USBD_CUSTOM_HID_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/ 0x00, : /****************************CDC************************************/ /* Interface Association Descriptor */ USBD_IAD_DESC_SIZE, // bLength USBD_IAD_DESCRIPTOR_TYPE, // bDescriptorType USBD_CDC_FIRST_INTERFACE, // bFirstInterface USBD_CDC_INTERFACE_NUM, // bInterfaceCount 0x02, // bFunctionClass 0x02, // bFunctionSubClass 0x01, // bInterfaceProtocol 0x00, // iFunction /*Interface Descriptor */ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */ /* Interface descriptor type */ USBD_CDC_CMD_INTERFACE, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x01, /* bNumEndpoints: One endpoints used */ 0x02, /* bInterfaceClass: Communication Interface Class */ 0x02, /* bInterfaceSubClass: Abstract Control Model */ 0x01, /* bInterfaceProtocol: Common AT commands */ 0x00, /* iInterface: */ : /******************** Mass Storage interface ********************/ 0x09, /* bLength: Interface Descriptor size */ USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */ USBD_MSC_INTERFACE, /* bInterfaceNumber: Number of Interface */ 0x00, /* bAlternateSetting: Alternate setting */ 0x02, /* bNumEndpoints*/ 0x08, /* bInterfaceClass: MSC Class */ 0x06, /* bInterfaceSubClass : SCSI transparent*/ 0x50, /* nInterfaceProtocol */ 0x05, /* iInterface: */ /******************** Mass Storage Endpoints ********************/ : };
static uint8_t USBD_CustomHID_CDC_MSC_Composite_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx); static uint8_t USBD_CustomHID_CDC_MSC_Composite_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);:
static uint8_t USBD_CustomHID_CDC_MSC_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);:
USBD_ClassTypeDef USBD_CustomHID_CDC_MSC_COMPOSITE = { USBD_CustomHID_CDC_MSC_Composite_Init, USBD_CustomHID_CDC_MSC_Composite_DeInit, USBD_CustomHID_CDC_MSC_Composite_Setup,:
USBD_CustomHID_CDC_MSC_Composite_GetDeviceQualifierDescriptor, }; : /*******************************************************************************/ static uint8_t USBD_CustomHID_CDC_MSC_Composite_Init (USBD_HandleTypeDef *pdev, uint8_t cfgidx) { uint8_t res = 0; pdev->pUserData = &USBD_CustomHID_fops_FS; res += USBD_CUSTOM_HID.Init(pdev, cfgidx); pdev->pUserData = &USBD_CDC_Interface_fops_FS; res += USBD_CDC.Init(pdev, cfgidx); pdev->pUserData = &USBD_Storage_Interface_fops_FS; res += USBD_MSC.Init(pdev,cfgidx); return res; } : /*******************************************************************************/ static uint8_t USBD_CustomHID_CDC_MSC_Composite_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) { switch(epnum) { case CUSTOM_HID_INDATA_NUM: SwitchHandleInterfaceToCustomHID(pdev); return(USBD_CUSTOM_HID.DataIn(pdev, epnum)); case CDC_INDATA_NUM: SwitchHandleInterfaceToCDC(pdev); return(USBD_CDC.DataIn(pdev, epnum)); case MSC_INDATA_NUM: SwitchHandleInterfaceToMSC(pdev); return(USBD_MSC.DataIn(pdev, epnum)); default: break; } return USBD_FAIL; }
:
/** @defgroup USBD_CUSTOM_HID_Exported_Defines * @{ */ #define CUSTOM_HID_EPIN_ADDR 0x81U #define CUSTOM_HID_EPIN_SIZE 0x02U #define CUSTOM_HID_EPOUT_ADDR 0x01U #define CUSTOM_HID_EPOUT_SIZE 0x02U #define USB_CUSTOM_HID_CONFIG_DESC_SIZ 41U #define USB_CUSTOM_HID_DESC_SIZ 9U /*---------- -----------*/ #define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 32:
: /** @defgroup usbd_cdc_Exported_Defines * @{ */ #define CDC_IN_EP 0x82U /* EP for data IN */ #define CDC_OUT_EP 0x02U /* EP for data OUT */ #define CDC_CMD_EP 0x84U /* EP for CDC commands */ :
: #define MSC_EPIN_ADDR 0x83U #define MSC_EPOUT_ADDR 0x03U :
: USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev) { : HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_FS, PCD_ISOINIncompleteCallback); #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */ /* USER CODE BEGIN EndPoint_Configuration */ /* * Buffer Description Table * https://www.docin.com/p-760532785.html * https://blog.csdn.net/wangzibigan/article/details/54409734 * https://www.amobbs.com/thread-5692754-1-1.html */ #define ACTUAL_USED_ENDPOINTS (1 + 1 + 1 + 1 + 1) uint32_t pma_adress = BTABLE_ADDRESS + (ACTUAL_USED_ENDPOINTS) * (4 + 4); HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, 0x00 , PCD_SNG_BUF, pma_adress); /*EP0_IN = RX*/ pma_adress += USB_FS_MAX_PACKET_SIZE; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, 0x80 , PCD_SNG_BUF, pma_adress); /*EP0_OUT = TX*/ pma_adress += USB_FS_MAX_PACKET_SIZE; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CUSTOM_HID_EPIN_ADDR , PCD_SNG_BUF, pma_adress); pma_adress += USBD_CUSTOMHID_OUTREPORT_BUF_SIZE; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CUSTOM_HID_EPOUT_ADDR, PCD_SNG_BUF, pma_adress); pma_adress += USBD_CUSTOMHID_OUTREPORT_BUF_SIZE; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CDC_IN_EP, PCD_SNG_BUF, pma_adress); pma_adress += CDC_DATA_FS_MAX_PACKET_SIZE; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CDC_OUT_EP, PCD_SNG_BUF, pma_adress); pma_adress += CDC_DATA_FS_MAX_PACKET_SIZE; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, MSC_EPIN_ADDR , PCD_SNG_BUF, pma_adress); pma_adress += MSC_MAX_FS_PACKET; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, MSC_EPOUT_ADDR , PCD_SNG_BUF, pma_adress); pma_adress += MSC_MAX_FS_PACKET; HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData, CDC_CMD_EP, PCD_SNG_BUF, pma_adress); pma_adress += CDC_CMD_PACKET_SIZE; /* USER CODE END EndPoint_Configuration */ return USBD_OK; } :
void USB_DEVICE_CustomHID_CDC_MSC_Composite_Init(void) { if(0x00 != hUsbDeviceFS.pDesc) USBD_DeInit(&hUsbDeviceFS); USB_DEVICE_Renumerate(); if(USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS)!= USBD_OK) Error_Handler(); if(USBD_RegisterClass(&hUsbDeviceFS, &USBD_CustomHID_CDC_MSC_COMPOSITE) != USBD_OK) Error_Handler(); if (USBD_Start(&hUsbDeviceFS) != USBD_OK) Error_Handler(); }
/** @defgroup USBD_DESC_Private_Defines USBD_DESC_Private_Defines * @brief Private defines. * @{ */ #define USBD_VID 1155 #define USBD_LANGID_STRING 1033 #define USBD_MANUFACTURER_STRING "STMicroelectronics" /* #define USBD_PID_FS 22352 #define USBD_PRODUCT_STRING_FS "STM32 Custom Human interface" #define USBD_CONFIGURATION_STRING_FS "Custom HID Config" #define USBD_INTERFACE_STRING_FS "Custom HID Interface" */ /* #define USBD_PID_FS 22336 #define USBD_PRODUCT_STRING_FS "STM32 Virtual ComPort" #define USBD_CONFIGURATION_STRING_FS "CDC Config" #define USBD_INTERFACE_STRING_FS "CDC Interface" */ #define USBD_PID_FS 22314 #define USBD_PRODUCT_STRING_FS "STM32 Mass Storage" #define USBD_CONFIGURATION_STRING_FS "MSC Config" #define USBD_INTERFACE_STRING_FS "MSC Interface" /* USER CODE BEGIN PRIVATE_DEFINES */
沒有留言:
張貼留言