WinUSB与MSC复合设备--最佳搭配!

2023-10-31 00:30

本文主要是介绍WinUSB与MSC复合设备--最佳搭配!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文中采用stm32f103核心板,自带USB FS接口,板载了Flash W25Q16,将该Flash配置为MSC的存储区,最终实现的效果为:将设备插入电脑,可以识别到WinUSB免驱设备,高速通信,同时也能识别出一个大容量存储区域,方便存放一些设备相关的资料、文档等,非常实用!

本文的方法是在WinUSB工程的基础上增加MSC功能。

首先准备好一个WinUSB工程,配置方法见之前的文章:

https://blog.csdn.net/bingwueyi/article/details/121622001

在准备WinUSB工程的时候,将SPI也配置好,后期增加MSC的时候就不用再去设置SPI相关功能,省去一些麻烦。

1 工程配置

1、通过CubeMX生成一个MSC的工程,设置如下:

2、将下图中框出的几个文件及其头文件拷贝到WinUSB工程中的对应目录中

3、将Flash的操作文件W25QXX.c和复合设备文件usbd_composite.c也放到工程目录中,并且将上述文件添加到Keil工程目录,添加完后的工程目录如下:

Keil工程配置中添加相关路径

Flash操作函数参见:STM32CubeMX系列教程11:串行外设接口SPI(二) - STM32CubeMX系列教程 微雪课堂

头文件中将引用改为

#include "main.h"

同时增加如下定义:

#define SPI_FLASH_REBUILD           1    // 1:使能格式化串行Flash,0:禁用格式化串行Flash

#define SPI_FLASH_SECTOR_SIZE    4096    // 串行Flash扇区大小

#define SPI_FLASH_START_SECTOR   256    // 串行Flash文件系统FatFS偏移量

#define SPI_FLASH_SECTOR_COUNT   256    // 串行Flash文件系统FatFS占用扇区个数 

extern  SPI_HandleTypeDef hspi1;   // 添加SPI定义 

usbd_composite.c,usbd_composite.h基于这篇文章修改:https://www.bbsmax.com/A/kjdwBXA5Np/

修改后的文件如下

//usbd_composite.c


/*** @file        usbd_composite.c* @author      Weyne* @version     V01* @date        2023.09.10* @brief       MSC + WinUSB 复合设备* @note* @attention   COYPRIGHT WEYNE*/#include "usbd_composite.h"#include "usbd_cdc.h"#include "usbd_msc.h"static USBD_CDC_HandleTypeDef *pCDCData;static USBD_MSC_BOT_HandleTypeDef *pMSCData;static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev,uint8_t cfgidx);static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev,uint8_t cfgidx);static uint8_t  USBD_Composite_EP0_RxReady(USBD_HandleTypeDef *pdev);static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev,USBD_SetupReqTypedef *req);static uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev,uint8_t epnum);static uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev,uint8_t epnum);static uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length);static uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length);//-----------------ADD GUOXUAN-----------------extern uint8_t* USBD_WinUSBOSStrDescriptor(uint16_t *length);//---------------------------------------------USBD_ClassTypeDef  USBD_COMPOSITE ={USBD_Composite_Init,USBD_Composite_DeInit,USBD_Composite_Setup,NULL, /*EP0_TxSent*/USBD_Composite_EP0_RxReady,USBD_Composite_DataIn,USBD_Composite_DataOut,NULL,NULL,NULL,NULL,USBD_Composite_GetFSCfgDesc,NULL,USBD_Composite_GetDeviceQualifierDescriptor,//-----------------ADD GUOXUAN----------------USBD_WinUSBOSStrDescriptor,//--------------------------------------------};/* USB composite device Configuration Descriptor *//*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */__ALIGN_BEGIN uint8_t USBD_Composite_CfgFSDesc[USBD_COMPOSITE_DESC_SIZE]  __ALIGN_END ={0x09,   /* bLength: Configuation Descriptor size */USB_DESC_TYPE_CONFIGURATION,   /* bDescriptorType: Configuration */WBVAL(USBD_COMPOSITE_DESC_SIZE),USBD_MAX_NUM_INTERFACES ,  /* bNumInterfaces: */0x01,   /* bConfigurationValue: */0x00,   /* iConfiguration: */0xC0,   /* bmAttributes: */0x96,   /* MaxPower 300 mA *//****************************CDC************************************//* Interface Association Descriptor */USBD_IAD_DESC_SIZE,               // bLengthUSBD_IAD_DESCRIPTOR_TYPE,         // bDescriptorTypeUSBD_CDC_FIRST_INTERFACE,         // bFirstInterfaceUSBD_CDC_INTERFACE_NUM,           // bInterfaceCount0x02,                             // bFunctionClass0x02,                             // bFunctionSubClass0x01,                             // bInterfaceProtocol0x02,                             // iFunction ??/*Interface Descriptor *//* Data class interface descriptor */0x09,                                       /* bLength: Endpoint Descriptor size */USB_DESC_TYPE_INTERFACE,                    /* bDescriptorType: */0x00,                                       /* bInterfaceNumber: Number of Interface */0x00,                                       /* bAlternateSetting: Alternate setting */0x02,                                       /* bNumEndpoints: Two endpoints used */0xFF,                                       /* bInterfaceClass: CDC */0x00,                                       /* bInterfaceSubClass */0x00,                                       /* bInterfaceProtocol */0x00,                                       /* 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 *//****************************MSC************************************//* Interface Association Descriptor */USBD_IAD_DESC_SIZE,                        // bLengthUSBD_IAD_DESCRIPTOR_TYPE,                  // bDescriptorTypeUSBD_MSC_FIRST_INTERFACE,                  // bFirstInterfaceUSBD_MSC_INTERFACE_NUM,                    // bInterfaceCount0x08,                                      // bFunctionClass0x06,                                      // bFunctionSubClass0x50,                                      // bInterfaceProtocol0x05,/********************  Mass Storage interface ********************/0x09,   /* bLength: Interface Descriptor size */USB_DESC_TYPE_INTERFACE,   /* bDescriptorType: */USBD_MSC_INTERFACE,   /* bInterfaceNumber: Number of Interface */0x00,   /* bAlternateSetting: Alternate setting */0x02,   /* bNumEndpoints*/0x08,   /* bInterfaceClass: MSC Class */0x06,   /* bInterfaceSubClass : SCSI transparent*/0x50,   /* nInterfaceProtocol */0x05,          /* iInterface: *//********************  Mass Storage Endpoints ********************/0x07,   /*Endpoint descriptor length = 7*/0x05,   /*Endpoint descriptor type */MSC_EPIN_ADDR,   /*Endpoint address (IN, address 1) */0x02,   /*Bulk endpoint type */LOBYTE(MSC_MAX_FS_PACKET),HIBYTE(MSC_MAX_FS_PACKET),0x01,   /*Polling interval in milliseconds */0x07,   /*Endpoint descriptor length = 7 */0x05,   /*Endpoint descriptor type */MSC_EPOUT_ADDR,   /*Endpoint address (OUT, address 1) */0x02,   /*Bulk endpoint type */LOBYTE(MSC_MAX_FS_PACKET),HIBYTE(MSC_MAX_FS_PACKET),0x01,     /*Polling interval in milliseconds*/};/* USB Standard Device Descriptor */__ALIGN_BEGIN  uint8_t USBD_Composite_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC]  __ALIGN_END ={USB_LEN_DEV_QUALIFIER_DESC,USB_DESC_TYPE_DEVICE_QUALIFIER,0x00,0x02,0x00,0x00,0x00,0x40,0x01,0x00,};/*** @brief  USBD_Composite_Init*         Initialize the Composite interface* @param  pdev: device instance* @param  cfgidx: Configuration index* @retval status*/static uint8_t  USBD_Composite_Init (USBD_HandleTypeDef *pdev,uint8_t cfgidx){uint8_t res = 0;pdev->pUserData =  &USBD_Interface_fops_FS;res +=  USBD_CDC.Init(pdev,cfgidx);pCDCData = pdev->pClassData;pdev->pUserData = &USBD_Storage_Interface_fops_FS;res +=  USBD_MSC.Init(pdev,cfgidx);pMSCData = pdev->pClassData;return res;}/*** @brief  USBD_Composite_DeInit*         DeInitilaize  the Composite configuration* @param  pdev: device instance* @param  cfgidx: configuration index* @retval status*/static uint8_t  USBD_Composite_DeInit (USBD_HandleTypeDef *pdev,uint8_t cfgidx){uint8_t res = 0;pdev->pClassData = pCDCData;pdev->pUserData = &USBD_Interface_fops_FS;res +=  USBD_CDC.DeInit(pdev,cfgidx);pdev->pClassData = pMSCData;pdev->pUserData = &USBD_Storage_Interface_fops_FS;res +=  USBD_MSC.DeInit(pdev,cfgidx);return res;}static uint8_t  USBD_Composite_EP0_RxReady(USBD_HandleTypeDef *pdev){return USBD_CDC.EP0_RxReady(pdev);}/*** @brief  USBD_Composite_Setup*         Handle the Composite requests* @param  pdev: device instance* @param  req: USB request* @retval status*/static uint8_t  USBD_Composite_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req){switch (req->bmRequest & USB_REQ_RECIPIENT_MASK){case USB_REQ_RECIPIENT_INTERFACE:switch(req->wIndex){case USBD_CDC_DATA_INTERFACE:pdev->pClassData = pCDCData;pdev->pUserData =  &USBD_Interface_fops_FS;return(USBD_CDC.Setup(pdev, req));case USBD_MSC_INTERFACE:pdev->pClassData = pMSCData;pdev->pUserData =  &USBD_Storage_Interface_fops_FS;return(USBD_MSC.Setup (pdev, req));default:break;}break;case USB_REQ_RECIPIENT_ENDPOINT:switch(req->wIndex){case CDC_IN_EP:case CDC_OUT_EP:case CDC_CMD_EP:pdev->pClassData = pCDCData;pdev->pUserData =  &USBD_Interface_fops_FS;return(USBD_CDC.Setup(pdev, req));case MSC_EPIN_ADDR:case MSC_EPOUT_ADDR:pdev->pClassData = pMSCData;pdev->pUserData =  &USBD_Storage_Interface_fops_FS;return(USBD_MSC.Setup (pdev, req));default:break;}break;}return USBD_OK;}/*** @brief  USBD_Composite_DataIn*         handle data IN Stage* @param  pdev: device instance* @param  epnum: endpoint index* @retval status*/uint8_t  USBD_Composite_DataIn (USBD_HandleTypeDef *pdev,uint8_t epnum){switch(epnum){case CDC_INDATA_NUM:pdev->pClassData = pCDCData;pdev->pUserData =  &USBD_Interface_fops_FS;return(USBD_CDC.DataIn(pdev,epnum));case MSC_INDATA_NUM:pdev->pClassData = pMSCData;pdev->pUserData =  &USBD_Storage_Interface_fops_FS;return(USBD_MSC.DataIn(pdev,epnum));default:break;}return USBD_FAIL;}/*** @brief  USBD_Composite_DataOut*         handle data OUT Stage* @param  pdev: device instance* @param  epnum: endpoint index* @retval status*/uint8_t  USBD_Composite_DataOut (USBD_HandleTypeDef *pdev,uint8_t epnum){switch(epnum){case CDC_OUTDATA_NUM:case CDC_OUTCMD_NUM:pdev->pClassData = pCDCData;pdev->pUserData =  &USBD_Interface_fops_FS;return(USBD_CDC.DataOut(pdev,epnum));case MSC_OUTDATA_NUM:pdev->pClassData = pMSCData;pdev->pUserData =  &USBD_Storage_Interface_fops_FS;return(USBD_MSC.DataOut(pdev,epnum));default:break;}return USBD_FAIL;}/*** @brief  USBD_Composite_GetHSCfgDesc*         return configuration descriptor* @param  length : pointer data length* @retval pointer to descriptor buffer*/uint8_t  *USBD_Composite_GetFSCfgDesc (uint16_t *length){*length = sizeof (USBD_Composite_CfgFSDesc);return USBD_Composite_CfgFSDesc;}/*** @brief  DeviceQualifierDescriptor*         return Device Qualifier descriptor* @param  length : pointer data length* @retval pointer to descriptor buffer*/uint8_t  *USBD_Composite_GetDeviceQualifierDescriptor (uint16_t *length){*length = sizeof (USBD_Composite_DeviceQualifierDesc);return USBD_Composite_DeviceQualifierDesc;}/*** @}*//*** @}*//*** @}*//************************ (C) COPYRIGHT WEYNE *****END OF FILE****/

//usbd_composite.h

/*** @file        usbd_composite.h* @author      Weyne* @version     V01* @date        2016.10.28* @brief       MSC + CDC 复合设备* @note* @attention   COYPRIGHT WEYNE*//* Define to prevent recursive inclusion -------------------------------------*/#ifndef __USBD_COMPOSITE_H#define __USBD_COMPOSITE_H#ifdef __cplusplusextern "C" {#endif/* Includes ------------------------------------------------------------------*/#include  "usbd_msc.h"#include  "usbd_cdc.h"#include "usbd_storage_if.h"#include "usbd_cdc_if.h"#define WBVAL(x) (x & 0xFF),((x >> 8) & 0xFF)#define DBVAL(x) (x & 0xFF),((x >> 8) & 0xFF),((x >> 16) & 0xFF),((x >> 24) & 0xFF)#define USBD_IAD_DESC_SIZE           0x08#define USBD_IAD_DESCRIPTOR_TYPE     0x0B#define USBD_CDC_FIRST_INTERFACE     0          /* CDC FirstInterface */#define USBD_CDC_INTERFACE_NUM       1          /* winusb Interface NUM */#define USBD_CDC_DATA_INTERFACE      0#define USBD_MSC_FIRST_INTERFACE     1          /* MSC FirstInterface */#define USBD_MSC_INTERFACE_NUM       1          /* MSC Interface NUM */#define USBD_MSC_INTERFACE           1#define MSC_INDATA_NUM              (MSC_EPIN_ADDR & 0x0F)#define MSC_OUTDATA_NUM             (MSC_EPOUT_ADDR & 0x0F)#define CDC_INDATA_NUM              (CDC_IN_EP & 0x0F)#define CDC_OUTDATA_NUM             (CDC_OUT_EP & 0x0F)#define CDC_OUTCMD_NUM              (CDC_CMD_EP & 0x0F)#define USBD_COMPOSITE_DESC_SIZE    (71)extern USBD_ClassTypeDef    USBD_COMPOSITE;/*** @}*//*** @}*/#ifdef __cplusplus}#endif#endif  /* __USBD_MSC_H *//*** @}*//************************ (C) COPYRIGHT WEYNE *****END OF FILE****/

2 修改工程文件

2.1 修改usbd_storage_if.c

1、添加Flash操作函数头文件

#include "W25QXX.h"

2、根据Flash容量修改block数量,例如此处我用的时2MB的Flash,Flash需要划分一部分空间存文件系统信息,此处Block大小为4K,数量为256,总容量为1M,修改如下

#define STORAGE_LUN_NBR                  1#define STORAGE_BLK_NBR                  256#define STORAGE_BLK_SIZ                  0x1000

3、在STORAGE_Init_FS中加入Flash初始化函数BSP_W25Qx_Init(),在初始化中可以执行唤醒、读写使能、三四字节模式切换等操作。

int8_t STORAGE_Init_FS(uint8_t lun){/* USER CODE BEGIN 2 */BSP_W25Qx_Init();return (USBD_OK);/* USER CODE END 2 */}

4、在读写函数中分别加入对Flash的操作

int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len){/* USER CODE BEGIN 6 */blk_addr+=SPI_FLASH_START_SECTOR;        BSP_W25Qx_Read(buf, blk_addr*SPI_FLASH_SECTOR_SIZE, blk_len*SPI_FLASH_SECTOR_SIZE);return (USBD_OK);/* USER CODE END 6 */}int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len){/* USER CODE BEGIN 7 */uint32_t write_addr;blk_addr+=SPI_FLASH_START_SECTOR;write_addr = blk_addr*SPI_FLASH_SECTOR_SIZE;   BSP_W25Qx_Erase_Block(write_addr);BSP_W25Qx_Write((uint8_t *)buf,write_addr,blk_len*SPI_FLASH_SECTOR_SIZE);return (USBD_OK);/* USER CODE END 7 */}

2.2 修改usbd_msc.h

查看MSC_EPIN_ADDR的值为0x81,与WinUSB的端点重复了,此处将MSC的端点改为0x83和0x03:

#define MSC_EPIN_ADDR                0x83U#define MSC_EPOUT_ADDR               0x03U

2.3 修改usb_device.c

1、添加复合设备头文件引用

#include "usbd_composite.h"

2、将初始化函数中的设备注册修改注册为复合设备

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 (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK){Error_Handler();}USBD_RegisterClass(&hUsbDeviceFS, &USBD_COMPOSITE);//  if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK)//  {//    Error_Handler();//  }//  if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK)//  {//    Error_Handler();//  }if (USBD_Start(&hUsbDeviceFS) != USBD_OK){Error_Handler();}/* USER CODE BEGIN USB_DEVICE_Init_PostTreatment *//* USER CODE END USB_DEVICE_Init_PostTreatment */}

2.4 修改usbd_conf.c

1、添加msc的头文件引用

#include "usbd_msc.h"

2、在USBD_LL_Init函数中增加MSC的内存区间定义

USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev){/* Init USB Ip. */uint32_t addr = 0x20;/* Link the driver to the stack. */hpcd_USB_FS.pData = pdev;pdev->pData = &hpcd_USB_FS;hpcd_USB_FS.Instance = USB;hpcd_USB_FS.Init.dev_endpoints = 8;hpcd_USB_FS.Init.speed = PCD_SPEED_FULL;hpcd_USB_FS.Init.low_power_enable = DISABLE;hpcd_USB_FS.Init.lpm_enable = DISABLE;hpcd_USB_FS.Init.battery_charging_enable = DISABLE;if (HAL_PCD_Init(&hpcd_USB_FS) != HAL_OK){Error_Handler( );}#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)/* Register USB PCD CallBacks */HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SOF_CB_ID, PCD_SOFCallback);HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback);HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESET_CB_ID, PCD_ResetCallback);HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback);HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback);HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback);HAL_PCD_RegisterCallback(&hpcd_USB_FS, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback);HAL_PCD_RegisterDataOutStageCallback(&hpcd_USB_FS, PCD_DataOutStageCallback);HAL_PCD_RegisterDataInStageCallback(&hpcd_USB_FS, PCD_DataInStageCallback);HAL_PCD_RegisterIsoOutIncpltCallback(&hpcd_USB_FS, PCD_ISOOUTIncompleteCallback);HAL_PCD_RegisterIsoInIncpltCallback(&hpcd_USB_FS, PCD_ISOINIncompleteCallback);#endif /* USE_HAL_PCD_REGISTER_CALLBACKS *//* USER CODE BEGIN EndPoint_Configuration */HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, addr); addr = addr + 0x40;HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, addr); addr = addr + 0x40;HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , MSC_EPIN_ADDR , PCD_SNG_BUF, addr); addr = addr + 0x40;HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , MSC_EPOUT_ADDR , PCD_SNG_BUF, addr); addr = addr + 0x40;HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_IN_EP , PCD_SNG_BUF, addr); addr = addr + 0x40;HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_OUT_EP , PCD_SNG_BUF, addr); addr = addr + 0x40;HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , CDC_CMD_EP   , PCD_SNG_BUF, addr); addr = addr + 0x40;/* USER CODE END EndPoint_Configuration_MSC */return USBD_OK;}

3、修改USBD_static_malloc函数,增加MSC的存储空间:

void *USBD_static_malloc(uint32_t size){static uint32_t mem2[(sizeof(USBD_MSC_BOT_HandleTypeDef)/4)+1];/* On 32-bit boundary */static uint32_t mem[(sizeof(USBD_CDC_HandleTypeDef)/4)+1];/* */if(size == sizeof(USBD_MSC_BOT_HandleTypeDef))return mem2;else return mem;}

2.5 修改usbd_conf.h

1、将USBD_MAX_NUM_INTERFACES定义为2个接口:

#define USBD_MAX_NUM_INTERFACES     2

2、添加MSC_MEDIA_PACKET定义:

#define MSC_MEDIA_PACKET     4096

3 测试

完成上述修改(建议随意修改一个PID VID),编译-->下载-->插入电脑,将会枚举出一个usb复合设备,并且识别到一个WinUSB设备和一个大容量存储设备:

查看识别到的U盘,容量与2.1章节第2小节设置的一致,打开U盘创建文件、导入、导出等功能一切正常。

使用WinUSB通用调试软件,可以识别到刚插入的设备,并且通信正常,此处WinUSB为回环模式,收到数据原包回复。

这篇关于WinUSB与MSC复合设备--最佳搭配!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/311569

相关文章

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

Prometheus与Grafana在DevOps中的应用与最佳实践

Prometheus 与 Grafana 在 DevOps 中的应用与最佳实践 随着 DevOps 文化和实践的普及,监控和可视化工具已成为 DevOps 工具链中不可或缺的部分。Prometheus 和 Grafana 是其中最受欢迎的开源监控解决方案之一,它们的结合能够为系统和应用程序提供全面的监控、告警和可视化展示。本篇文章将详细探讨 Prometheus 和 Grafana 在 DevO

springboot整合swagger2之最佳实践

来源:https://blog.lqdev.cn/2018/07/21/springboot/chapter-ten/ Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架。 一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现。 SpringBoot集成 pom <!--swagge

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python

全英文地图/天地图和谷歌瓦片地图杂交/设备分布和轨迹回放/无需翻墙离线使用

一、前言说明 随着风云局势的剧烈变化,对我们搞软件开发的人员来说,影响也是越发明显,比如之前对美对欧的软件居多,现在慢慢的变成了对大鹅和中东以及非洲的居多,这两年明显问有没有俄语或者阿拉伯语的输入法的增多,这要是放在2019年以前,一年也遇不到一个人问这种需求场景的。 地图应用这块也是,之前的应用主要在国内,现在慢慢的多了一些外国的应用场景,这就遇到一个大问题,我们平时主要开发用的都是国内的地

驱动(RK3588S)第七课时:单节点设备树

目录 需求一、设备树的概念1、设备树的后缀名:2、设备树的语法格式3、设备树的属性(重要)4、设备树格式举例 二、设备树所用函数1、如何在内核层种获取设备树节点:2、从设备树上获取 gpio 口的属性3、获取节点上的属性只针对于字符串属性的4、函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的

《C++中的移动构造函数与移动赋值运算符:解锁高效编程的最佳实践》

在 C++的编程世界中,移动构造函数和移动赋值运算符是提升程序性能和效率的重要工具。理解并正确运用它们,可以让我们的代码更加高效、简洁和优雅。 一、引言 随着现代软件系统的日益复杂和对性能要求的不断提高,C++程序员需要不断探索新的技术和方法来优化代码。移动构造函数和移动赋值运算符的出现,为解决资源管理和性能优化问题提供了有力的手段。它们允许我们在不进行不必要的复制操作的情况下,高效地转移资源

Unity协程搭配队列开发Tips弹窗模块

概述 在Unity游戏开发过程中,提示系统是提升用户体验的重要组成部分。一个设计良好的提示窗口不仅能及时传达信息给玩家,还应当做到不干扰游戏流程。本文将探讨如何使用Unity的协程(Coroutine)配合队列(Queue)数据结构来构建一个高效且可扩展的Tips弹窗模块。 技术模块介绍 1. Unity协程(Coroutines) 协程是Unity中的一种特殊函数类型,允许异步操作的实现

海鲜加工污水处理设备处理效果高

诸城市鑫淼环保小编带大家了解一下海鲜加工污水处理设备处理效果高   海鲜加工污水处理设备通常采用物理、化学和生物处理相结合的方法,对废水中的污染物进行高xiao去除。设备设计紧凑,占地面积小,操作简便,适用于不同规模的海鲜加工厂。   设备特点   高xiao性:采用先进的处理工艺和技术,确保废水处理效果稳定可靠。   占地面积小:设备设计紧凑,占地面积小,适合在有限的空间内安装。