发布版本: 1.0
文件密级: 公开资料
前言
概述
读者
本文档(本指南)主要使用于以下工程师:
软件开发工程师
产品版本 修订记录
日期 | 版本 | 作者/邮箱 | 修订说明 |
---|---|---|---|
2019-10-7 | V1.0 | wingceltis-c/[email protected] | 初始版本 |
USB组合设备Composite Device内只有一个Function,只有一套PID/VID,通过将不同的interface定义为不同的类来实现多个功能的组合。
复制USB_HID工程为USB_HID_CDC工程,添加CDC相关类容。(USB_HID工程和文档在参考链接中)
1.合并CDC
2.新建usbd_composite文件,并添加文件到Keil.
4.修改HID所用EP端口.并添加HID_EPOUT_ADDR
修改设备描述符
__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*/
};
编辑复合头文件.复合用IAD.写在一起.
usbd_composite.h
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBD_COMPOSITE_H
#define __USBD_COMPOSITE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_hid.h"
#include "usbd_cdc.h"
#include "usbd_cdc_if.h"
#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 2 /* CDC Interface NUM */
#define USBD_CDC_CMD_INTERFACE 0
#define USBD_CDC_DATA_INTERFACE 1
#define USBD_HID_FIRST_INTERFACE 2 /* HID FirstInterface */
#define USBD_HID_INTERFACE_NUM 1 /* HID Interface NUM */
#define USBD_HID_INTERFACE 2
#define HID_INDATA_NUM (HID_EPIN_ADDR & 0x0F)
#define HID_OUTDATA_NUM (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 USBD_COMPOSITE_DESC_SIZE (9 + 58 + 8 + 32 + 8 )
extern USBD_ClassTypeDef USBD_COMPOSITE;
extern USBD_CDC_HandleTypeDef *pCDCData;
extern USBD_HID_HandleTypeDef *pHIDData;
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USBD_COMPOSITE_H */
/**
* @}
*/
/*****************************END OF FILE****/
usbd_composite.c
#include "usbd_composite.h"
#include "usbd_cdc.h"
#include "usbd_hid.h"
#include "usbd_cdc_if.h"
USBD_CDC_HandleTypeDef *pCDCData;
USBD_HID_HandleTypeDef *pHIDData;
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);
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,
};
/* 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 */
USBD_COMPOSITE_DESC_SIZE,
0x00,
USBD_MAX_NUM_INTERFACES , /* bNumInterfaces: */
0x01, /* bConfigurationValue: */
0x00, /* iConfiguration: 04 */
0xc0, /* bmAttributes:c0 */
0x32, /* MaxPower 300 mA 96 */
/****************************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 CDC Control
0x02, // bFunctionSubClass Abstract Control Model
0x01, // bInterfaceProtocol AT Commands: V.250 etc
0x04, // 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 */
0x01, /* 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: 1 */
/*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 */
USBD_CDC_CMD_INTERFACE, /* bMasterInterface: Communication class interface */
USBD_CDC_DATA_INTERFACE, /* 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),
0x01, /* bInterval: */
/*Data class interface descriptor*/
0x09, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
USBD_CDC_DATA_INTERFACE, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints: Two endpoints used */
0x0A, /* bInterfaceClass: CDC */
0x02, /* bInterfaceSubClass: */
0x00, /* bInterfaceProtocol: */
0x01, /* 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),
0x01, /* bInterval: ignore for Bulk transfer */
/*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),
0x01, /* bInterval: ignore for Bulk transfer */
/****************************HID************************************/
/* Interface Association Descriptor */
USBD_IAD_DESC_SIZE, // bLength
USBD_IAD_DESCRIPTOR_TYPE, // bDescriptorType
USBD_HID_FIRST_INTERFACE, // bFirstInterface
USBD_HID_INTERFACE_NUM, // bInterfaceCount
0x03, // bFunctionClass
0x00, // bFunctionSubClass
0x00, // bInterfaceProtocol
0x00,
/******************** HID interface ********************/
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
USBD_HID_INTERFACE, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x02, /* bNumEndpoints*/
0x03, /* bInterfaceClass: HID Class */
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot*/
0x00, /* nInterfaceProtocol 0=none, 1=keyboard, 2=mouse*/
0x00, /* iInterface: */
/* 18 */
0x09, /*bLength: HID Descriptor size*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
0x10, /*bcdHID: HID Class Spec release number*/
0x01,
0x00, /*bCountryCode: Hardware target country*/
0x01, /*bNumDescriptors: Number of HID class descriptors to follow*/
0x22, /*bDescriptorType*/
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
0x00,
/******************** HID Endpoints ********************/
/* 27 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
0x00,
HID_FS_BINTERVAL, /*bInterval: Polling Interval (10 ms)*/
/* 34 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */
0x00,
HID_FS_BINTERVAL, /*bInterval: Polling Interval (10 ms)*/
};
/* 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 = (void *)&USBD_Interface_fops_FS;
res += USBD_CDC.Init(pdev,cfgidx);
pCDCData = pdev->pClassData;
pdev->pUserData = (void *)NULL;
res += USBD_HID.Init(pdev,cfgidx);
pHIDData = 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 = (void *)&USBD_Interface_fops_FS;
res += USBD_CDC.DeInit(pdev,cfgidx);
pdev->pClassData = pHIDData;
pdev->pUserData = (void *)NULL;
res += USBD_HID.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:
case USBD_CDC_CMD_INTERFACE:
pdev->pClassData = pCDCData;
pdev->pUserData = (void *)&USBD_Interface_fops_FS;
return(USBD_CDC.Setup(pdev, req));
case USBD_HID_INTERFACE:
pdev->pClassData = pHIDData;
pdev->pUserData = (void *)NULL;
return(USBD_HID.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 = (void *)&USBD_Interface_fops_FS;
return(USBD_CDC.Setup(pdev, req));
case HID_EPIN_ADDR:
case HID_EPOUT_ADDR:
pdev->pClassData = pHIDData;
pdev->pUserData = (void *)NULL;
return(USBD_HID.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 = (void *)&USBD_Interface_fops_FS;
return(USBD_CDC.DataIn(pdev,epnum));
case HID_INDATA_NUM:
pdev->pClassData = pHIDData;
pdev->pUserData = (void *)NULL;
return(USBD_HID.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 = (void *)&USBD_Interface_fops_FS;
return(USBD_CDC.DataOut(pdev,epnum));
case HID_OUTDATA_NUM:
pdev->pClassData = pHIDData;
pdev->pUserData = (void *)NULL;
return(USBD_HID.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;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
10.修改hid cdc设备的classdata指针。
默认classdata指针是通过hUsbDeviceFS变量获取的,但是当前系统中有两个设备,对应的classdata是分开的。接收函数是中断调用usbd_composite再调用到cdc或者hid对应方法中,在usbd_composite是有重新对classdata进行赋值 ,但是发送函数是直接获取hUsbDeviceFS变量中的,所有需要直接指定使用对应的classdata。
cdc设备修改
键鼠的发送函数不用修改可以直接使用,在usbd_cdc_if.c的接收函数中也添加了CDC_Transmit_FS方法,接收到任何数据都会发送回去。
while (1)
{
/* USER CODE END WHILE */
if((HAL_GetTick() - old_tick) >= 1000)
{
CDC_Transmit_FS("123",3);
old_tick = HAL_GetTick();
}
mouse_send(10,10);
HAL_Delay(100);
//keyboard_send(4);
HAL_Delay(1000);
mouse_send(10,10);
HAL_Delay(100);
//keyboard_send(0);
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
https://www.lijingquan.net/?p=2355
https://blog.csdn.net/longor1991/article/details/81095896
https://www.cnblogs.com/shangdawei/p/4712305.html
USB_HID
https://blog.csdn.net/wingceltis/article/details/102413072
USB_CDC
https://blog.csdn.net/wingceltis/article/details/102412729
工程地址
https://download.csdn.net/download/wingceltis/11836087