上一篇文章已经详细讲解了如何在STM32平台上实现一个WinUSB免驱设备:

STM32 WinUSB(WCID)免驱高速通信 20M/s(附详细测试)_bingwueyi的博客-CSDN博客_winusb

那现在就在这个工程的基础上改造一下,实现多端点通信,实用性、可玩性、功能扩展性大大增加了!需要说明的是增加端点只会增加功能(数据通道逻辑区分),不会增加传输速率。

USB的接口(Interface)、端点(Endpoint)等概念自行了解一下吧,本文的目的是为了增加功能和区分数据通道,添加了两个端点(Endpoint),下一篇文章将会讲到增加接口,也就是复合设备。

先来张修改对比图,对下面6个文件进行了修改:

直接上代码,以下是对USB HS的修改, FS的配置同理修改即可:

1 修改usbd_cdc.h

1.1 宏定义增中EP3的定义

#define CDC_IN_EP                                   0x81U  /* EP1 for data IN */#define CDC_OUT_EP                                  0x01U  /* EP1 for data OUT */#define CDC_CMD_EP                                  0x82U  /* EP2 for CDC commands *///ADD#define CDCUSER_IN_EP                                   0x83U  /* EP3 for data IN */#define CDCUSER_OUT_EP                                  0x03U  /* EP3 for data OUT */

1.2 结构体 USBD_CDC_ItfTypeDef 的Receive定义 修改一下,增加endpoint参数,主要是为了在接收函数中区分是哪个端点的数据:

typedef struct _USBD_CDC_Itf{int8_t (* Init)(void);int8_t (* DeInit)(void);int8_t (* Control)(uint8_t cmd, uint8_t *pbuf, uint16_t length);int8_t (* Receive)(uint8_t *Buf, uint32_t *Len, uint8_t ep); //CHANGEint8_t (* TransmitCplt)(uint8_t *Buf, uint32_t *Len, uint8_t epnum);} USBD_CDC_ItfTypeDef;

1.3 下面两个函数也增加 endpoint参数:

uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev, uint8_t ep); //CHANGEuint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev, uint8_t ep); //CHANGE

2 修改 usbd_cdc.c

2.1 将 WINUSB_CONFIG_DESC_SIZE 宏的值改为46,该值表示USBD_CDC_CfgHSDesc数组的长度,本文增加了两个端点,第个端点由7个字节表示,所以 32+7+7=46:

#define WINUSB_CONFIG_DESC_SIZE 46 //32  CHANGE

2.2 在数组USBD_CDC_CfgHSDesc中修改EndPoint数量为4,同时增加端点定义:

/*Data class interface descriptor*/0x09,   /* bLength: Endpoint Descriptor size */USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */0x00,   /* bInterfaceNumber: Number of Interface, zero based index of this interface */0x00,   /* bAlternateSetting: Alternate setting */0x04,   /* bNumEndpoints: Two endpoints used */ //CHANGE0xff,   /* bInterfaceClass: vendor */0x00,   /* bInterfaceSubClass: */0x00,   /* bInterfaceProtocol: */0x00,   /* iInterface: *///此处省略一些代码...//---------------------------------------ADD--------------------------------------------------/*Endpoint OUT Descriptor */0x07,   /* bLength: Endpoint Descriptor size */USB_DESC_TYPE_ENDPOINT,      /* bDescriptorType: Endpoint */CDCUSER_OUT_EP,                        /* bEndpointAddress */0x02,                              /* bmAttributes: Bulk */LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),  /* wMaxPacketSize: */HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),0x00,                                       /* bInterval: ignore for Bulk transfer *//* Endpoint IN Descriptor */0x07,                                       /* bLength: Endpoint Descriptor size */USB_DESC_TYPE_ENDPOINT,                     /* bDescriptorType: Endpoint */CDCUSER_IN_EP,                                  /* bEndpointAddress */0x02,                                       /* bmAttributes: Bulk */LOBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),        /* wMaxPacketSize: */HIBYTE(CDC_DATA_HS_MAX_PACKET_SIZE),0x00                                        /* bInterval: ignore for Bulk transfer *///---------------------------------------------------------------------------------------------

2.3 在 USBD_CDC_Init 函数中增加端点初始化(省略了一些代码,找准位置哦):

 //--------------------ADD--------------------------------/* Open USER EP IN */(void)USBD_LL_OpenEP(pdev, CDCUSER_IN_EP, USBD_EP_TYPE_BULK,CDC_DATA_HS_IN_PACKET_SIZE);pdev->ep_in[CDCUSER_IN_EP & 0xFU].is_used = 1U;/* Open USER EP OUT */(void)USBD_LL_OpenEP(pdev, CDCUSER_OUT_EP, USBD_EP_TYPE_BULK,CDC_DATA_HS_OUT_PACKET_SIZE);pdev->ep_out[CDCUSER_OUT_EP & 0xFU].is_used = 1U;//省略(void)USBD_LL_PrepareReceive(pdev, CDCUSER_OUT_EP, hcdc->RxBuffer,CDC_DATA_HS_OUT_PACKET_SIZE);//-----------------------------------------------------------

2.4 在 USBD_CDC_DeInit 函数中增加:

//----------------------ADD----------------------/* Close EP IN */(void)USBD_LL_CloseEP(pdev, CDCUSER_IN_EP);pdev->ep_in[CDCUSER_IN_EP & 0xFU].is_used = 0U;/* Close EP OUT */(void)USBD_LL_CloseEP(pdev, CDCUSER_OUT_EP);pdev->ep_out[CDCUSER_OUT_EP & 0xFU].is_used = 0U;//--------------------------------------------------

2.5 在 USBD_CDC_DataOut 函数中修改Receive,传入ep参数:

((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength, epnum);  //CHANGE

同样的,下面两个函数也做相应的修改,传入ep参数:

uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev, uint8_t ep)  //CHANGE
{USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;USBD_StatusTypeDef ret = USBD_BUSY;if (pdev->pClassData == NULL){return (uint8_t)USBD_FAIL;}if (hcdc->TxState == 0U){/* Tx Transfer in progress */hcdc->TxState = 1U;/* Update the packet total length */pdev->ep_in[ep & 0xFU].total_length = hcdc->TxLength;  //CHANGE/* Transmit next packet */(void)USBD_LL_Transmit(pdev, ep, hcdc->TxBuffer, hcdc->TxLength);  //CHANGEret = USBD_OK;}return (uint8_t)ret;
}uint8_t USBD_CDC_ReceivePacket(USBD_HandleTypeDef *pdev, uint8_t ep)  //CHANGE
{USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef *)pdev->pClassData;if (pdev->pClassData == NULL){return (uint8_t)USBD_FAIL;}if (pdev->dev_speed == USBD_SPEED_HIGH){/* Prepare Out endpoint to receive next packet */(void)USBD_LL_PrepareReceive(pdev, ep, hcdc->RxBuffer,  //CHANGECDC_DATA_HS_OUT_PACKET_SIZE);}else{/* Prepare Out endpoint to receive next packet */(void)USBD_LL_PrepareReceive(pdev, ep, hcdc->RxBuffer,  //CHANGECDC_DATA_FS_OUT_PACKET_SIZE);}return (uint8_t)USBD_OK;
}

3 修改 usbd_cdc_if.c

3.1 修改 CDC_Receive_HS 函数定义:

static int8_t CDC_Receive_HS(uint8_t* pbuf, uint32_t *Len, uint8_t ep); //CHANGE

3.2 增加接收缓冲区和修改收发函数:

//-----------------ADD GUOXUAN-----------------------extern volatile int8_t usb_ep1_rxne;extern uint8_t usb_ep1_rx[2048];extern volatile int8_t usb_ep3_rxne;extern uint8_t usb_ep3_rx[2048];//---------------------------------------------------static int8_t CDC_Receive_HS(uint8_t* Buf, uint32_t *Len, uint8_t ep) //CHANGE{/* USER CODE BEGIN 11 *///-------------ADD GUOXUAN--------------------switch(ep){case CDC_OUT_EP:memcpy(usb_ep1_rx, Buf, *Len);usb_ep1_rxne = SET;break;case CDCUSER_OUT_EP:memcpy(usb_ep3_rx, Buf, *Len);usb_ep3_rxne = SET;break;default:break;}//--------------------------------------------USBD_CDC_SetRxBuffer(&hUsbDeviceHS, &Buf[0]);USBD_CDC_ReceivePacket(&hUsbDeviceHS, ep);  //CHANGEreturn (USBD_OK);/* USER CODE END 11 */}uint8_t CDC_Transmit_HS(uint8_t* Buf, uint16_t Len, uint8_t ep)  //CHANGE{uint8_t result = USBD_OK;/* USER CODE BEGIN 12 */USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceHS.pClassData;if (hcdc->TxState != 0){return USBD_BUSY;}USBD_CDC_SetTxBuffer(&hUsbDeviceHS, Buf, Len); //todo:result = USBD_CDC_TransmitPacket(&hUsbDeviceHS, ep);  //CHANGE/* USER CODE END 12 */return result;}

4 修改 usbd_cdc_if.h

4.1 函数 CDC_Transmit_HS 增加ep参数:

uint8_t CDC_Transmit_HS(uint8_t* Buf, uint16_t Len, uint8_t ep); //CHANGE

5 修改 usbd_conf.c

5.1 在 USBD_LL_Init 函数尾部增加txFifo初始化:

HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200);HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, 0x80);HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, 0x174);HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 3, 0x174); //ADD

6 最后在main.c里增加收发控制:

//--------------ADD GUOXUAN-----------------------uint8_t usb_ep1_rx[2048];uint8_t usb_ep1_tx[40960];uint8_t usb_ep3_rx[2048];uint8_t usb_ep3_tx[40960];volatile int8_t usb_ep1_rxne = RESET;volatile int8_t usb_ep3_rxne = RESET;extern USBD_HandleTypeDef hUsbDeviceHS;//-----------------------------------------------//------------ADD GUOXUAN-------------------void WinUSB_Receive_HS(){uint16_t i = 0;if (usb_ep1_rxne == SET){i = usb_ep1_rx[0] + (usb_ep1_rx[1]<<8);CDC_Transmit_HS(usb_ep1_tx, i, CDC_IN_EP);usb_ep1_rxne = RESET;}else if(usb_ep3_rxne == SET){i = usb_ep3_rx[0] + (usb_ep3_rx[1]<<8);CDC_Transmit_HS(usb_ep3_tx, i, CDCUSER_IN_EP);usb_ep3_rxne = RESET;}}//------------------------------------------

至此,修改已全部完成,下面进行测试。

在WIN10平台,使用VS2015创建C++工程,测试方法同上一篇文章,上位机发送一个64字节的包,前两字节表示要回复的长度,下位机收到后回复一个相应长度的包,重复收发1000次统计速率,按下数字选择包大小,回车即对两个端点进行测试,结果如下图所示(未使用多线程):

上位机原码下载:

https://download.csdn.net/download/bingwueyi/86399991

简单几步让WinUSB设备变为多端点设备相关推荐

  1. CoreAudioApi-音频端点设备-检测耳机插拔

    术语"端点设备"是指位于数据路径一端的硬件设备,该数据路径源自或终止于应用程序.音频终端设备的例子有扬声器.耳机.麦克风和CD播放器.沿着数据路径移动的音频数据可能在应用程序和端点 ...

  2. 简单五步,实现物联网批量创建设备

    产品指某一类设备,创建完产品后,需要为具体设备创建身份.您可以创建单个设备,也可以批量创建设备.本文为您讲述如何批量创建设备. 操作步骤 1.登录物联网平台控制台. 2.在左侧导航栏,选择设备管理 & ...

  3. 简单几步解决企业USB端口隐患

    随着科技的发展,信息化技术不断进步,便捷式设备也遍地开花.iPod.PDA.智能手机.移动硬盘.MP3.MP4及优盘等等可移动便捷设备给我们的日常生活带来了诸多的便利.随着这些新设备的不断出现,给我们 ...

  4. 简单几步教你怎么在路由器上搭建PHP环境的网站

    2019独角兽企业重金招聘Python工程师标准>>> 今天早上在锐哥博客看到的,他说他的博客布置在路由器上,我对于网络硬件不是很了解,但是感觉很牛逼,于是希望他能写一个教程教大家怎 ...

  5. WinUSB - 微软为所有 USB 设备提供的常规驱动程序

    WinUSB - 微软为所有 USB 设备提供的常规驱动程序  [复制链接]     shangdawei 20 主题 0 好友 717 积分 高级会员 莫元 696 发消息 电梯直达 1楼  发表于 ...

  6. 简单几步实现内网穿透

    场景 为了避免阐述过多理论,我们直接从需求场景入手,来了解一下为什么需要内网穿透? 小明是少数派的一位咕咕作者,在家里电脑稿某文稿了一半,到公司后打算摸鱼继续稿,怎么办呢(此处假定他没有使用任何云同步 ...

  7. 简单三步快速实现内网穿透

    都知道现在基本处于大内网环境,运营商一般不会分配给到公网IP.但有些时候需要在公网环境下访问内网,如: 远程连接内网电脑 远程公司内网服务器.数据库 远程NAS 公网访问内网web站点 ssh远程树莓 ...

  8. 华为手机usb计算机连接在哪里设置密码,简单十步设置Huawei Share,手机与电脑传输从此告别数据线...

    原标题:简单十步设置Huawei Share,手机与电脑传输从此告别数据线 最近发现很多人使用华为手机和电脑连接还需要使用数据线,没有使用Huawei Share功能,就写了一下简单的教程,供参考. ...

  9. “果粉”速递:简单9步轻松绕过iCloud 激活锁

    本文讲的是"果粉"速递:简单9步轻松绕过iCloud 激活锁,如何在iPhone 7(Plus).6S Plus.6S.6 Plus.6.5S.5C.4S.4以及iPad或iPod ...

最新文章

  1. 逻辑模型设计步骤-粒度层次划分
  2. 【统计学习方法】K近邻对鸢尾花(iris)数据集进行多分类
  3. 5G时代,会有什么奇葩事儿?
  4. java泛型-类型擦除
  5. Qt中的QMap和QHash
  6. 私家车合乘系统 matlab,私家车贴上邻里合乘标志 武汉探路拼车合法化
  7. JDK安装和坏境变量配置
  8. Qt Creator管理工作区
  9. hive mysql编码问题_Hive中文乱码 生产环境问题解决
  10. python开发的类似stardict工具
  11. 动态路由RIP的简易配置
  12. GIS_gdal geotiff文件与JAVA 浮点二维数组array之间的转换
  13. Spark OOM:java heap space,OOM:GC overhead limit exceeded解决方法
  14. 谈工作没兴趣,空谈都有兴趣
  15. 微波雷达传感器模块,智能感知人体存在,实时感应交互控制应用
  16. 怎样做终端安全防御?
  17. 【CSS】span标签设置宽度
  18. Git-删除文件后找回
  19. 数据安全对物联网越来越重要
  20. 【抓包】【Mac Charles】局域网无法抓包 手机热点来解决

热门文章

  1. 魔兽怀旧服最新服务器人口,魔兽世界:仅三天时间正式服人口减少20万,怀旧服人口超越正式服...
  2. linux开机磁盘检查挂载失败 ,导致无法进入系统
  3. VMware 12 安装 macOS S 10.12
  4. python 打卡记录代码_利用Python实现对考勤打卡数据处理的总结
  5. twilio php 发送短信,如何使用 Twilio 实现语音和短信功能 (PHP) | Microsoft Docs
  6. 求最小公倍数的方法php,JS怎么求得最小公倍数和最大公约数
  7. 前端学习第八弹:制作一个精美书签
  8. error: C2679
  9. 我上传了一个图片 谁知道我上传哪去了 找不见了
  10. 踩坑nessus激活码-点击官方邮件链接不能获取到验证码