简单几步让WinUSB设备变为多端点设备

上一篇文章已经详细讲解了如何在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); //CHANGE

  int8_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); //CHANGE

uint8_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 */ //CHANGE

  0xff,   /* 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);  //CHANGE

    ret = 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,  //CHANGE
                                 CDC_DATA_HS_OUT_PACKET_SIZE);
  }
  else
  {
    /* Prepare Out endpoint to receive next packet */
  (void)USBD_LL_PrepareReceive(pdev, ep, hcdc->RxBuffer,  //CHANGE
                                 CDC_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);  //CHANGE

  return (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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值