58同城上海网站建设,微信第三方做网站需要费用吗,wordpress收费下载,12306网站建设投标书如遇开发技术问题#xff0c;欢迎前往开发者社区#xff0c;极海技术团队将在线为您解答~ 极海官方开发者社区https://community.geehy.cn/
《APM32芯得》系列内容为用户使用APM32系列产品的经验总结#xff0c;均转载自21ic论坛极海半导体专区#xff0c;全文未作任何修…如遇开发技术问题欢迎前往开发者社区极海技术团队将在线为您解答~ 极海官方开发者社区https://community.geehy.cn/
《APM32芯得》系列内容为用户使用APM32系列产品的经验总结均转载自21ic论坛极海半导体专区全文未作任何修改未经原文作者授权禁止转载。
目录
1、USB设备描述符
2、USB配置描述符
3、USB HID报告描述符
4、修改端点缓存地址 最近在编写DMA_ADC例程的过程中出现了一个中断配置的问题在ADC采集过程中结合手册进行ADC连续转换模式配置采集手册上给出需要进行中断配置的信息但是真实情况不需要进行中断配置也可以进行ADC连续转换采集因此我没过滤掉ADC采集中开启中断配置的信息开启了ADC中断采集因此这次以APM32F411官方例程中的DMA_ADC例程复刻了此次出现的问题。 APM32F103具有USB全速接口可以做USB从机的多种功能。USB协议中为了提供对多样设备的支持定义了许多外部设备子类常见的包括 人机交互类设备HIDHuman Interface Device 通信类设备CDCCommunicate Device Class 大容量存储设备MSCMass Storage Class 视频类设备UVCUSB Video Class 音频类设备UACUSB Audio Class HID (Human Interface Device) 是一种用于连接人机交互设备的USB设备类别。它定义了一组通用的协议和规范用于支持键盘、鼠标、游戏控制器等各种输入设备的连接和交互。 CDCCommunication Device Class是USB组织定义的一类专门给各种通信设备(电信通信设备和中速网络通讯设备)使用的USB子类常用于虚拟串口。 USB大容量存储设备类The USB mass storage device class是一种计算机和移动设备之间的传输协议它允许一个通用串行总线USB设备来访问主机的计算设备使两者之间进行文件传输常用于存储器读写和模拟U盘。 SDK中提供的例程就有虚拟串口CDC、鼠标HID、模拟U盘MSC的功能。 除了这些USB做单项功能的USB还可以配置复合设备能同时集成了多个不同类型的外设可以实现多个功能的同时使用 接下来就尝试在极海SDK中增加HID KeyBoardCDC 虚拟串口的复合设备配置修改就基于极海APM32F10x_SDK_V1.8中已有的USB_CDC_VirtualCOMPort例程就不用重新配置虚拟串口部分了。
实现要对USB的描述符进行修改能让电脑识别出来是个什么设备。 1、USB设备描述符
重点是bDeviceClass改成0xEF,告诉电脑这是个复合设备。
const uint8_t g_usbDeviceDescriptor[USB_DEVICE_DESCRIPTOR_SIZE] {0x12, /*bLength长度设备描述符的长度为18字节*/USBD_DESC_DEVICE, /*bDescriptorType*/0x00,0x02, /*bcdUSB 2.00 */0xEF, /*bDeviceClass*/0x02, /*bDeviceSubClass*/0x01, /*bDeviceProtocol*/0x40, /*bMaxPacketSize40---------------------------*/0x83,0x05, /*idVendor (0x0583)*/0x50,0x57, /*idProduct 0x5750*/0x00, /*bcdDevice rel. 2.00*/0x02,1, /*Index of string descriptor describingmanufacturer */2, /*Index of string descriptor describingproduct*/3, /*Index of string descriptor describing thedevice serial number */0x01 /*bNumConfigurations*/}; 2、USB配置描述符
这里配置USB的配置描述符、接口描述符和端点描述符。
HID键盘使用两个端点端点4IN和端点4OUT
VCP虚拟串口使用三个端点端点1IN、端点1OUT和端点2IN
const uint8_t g_usbConfigDescriptor[USB_CONFIG_DESCRIPTOR_SIZE] {0x09, /* bLength: Configuration Descriptor size */USBD_DESC_CONFIGURATION, /* bDescriptorType: Configuration */USB_CONFIG_DESCRIPTOR_SIZE,/* wTotalLength: Bytes returned */0x00,0x03, /* bNumInterfaces: 1 interface */0x01, /* bConfigurationValue: Configuration value */0x00, /* iConfiguration: Index of string descriptor describingthe configuration*/0xC0, /* bmAttributes: Self powered */0x32, /* MaxPower 100 mA: this current is used for detecting Vbus *//*************************************功能1 HID键盘**************************************//*IAD描述符*/0x08, //bLengthIAD描述符大小 0x0B, //bDescriptorTypeIAD描述符类型0x00, //bFirstInterface功能1 HID键盘的第一个接口描述符是在总的配置描述符中的第几个从0开始数0x01, //bInferfaceCount功能1 HID键盘有1个接口描述符0x03, //bFunctionClass同单HID功能时设备符中的bDeviceClass0x00, //bFunctionSubClass同单HID功能时设备符中的bDeviceSubClass0x01, //bFunctionProtocol同单HID功能时设备符中的bDeviceProtocol0x00, //iFunction字符串描述中关于此设备的索引(个人理解是一个字符串描述符中有比如0~5是功能1的字符串//6~10是功能2的字符串,如果是功能2的话此值为6)/************** Descriptor of Custom HID interface ****************//* 09 */0x09, /* bLength: Interface Descriptor size */USBD_DESC_INTERFACE,/* bDescriptorType: Interface descriptor type */0x00, /* bInterfaceNumber: Number of Interface */0x00, /* bAlternateSetting: Alternate setting */0x02, /* bNumEndpoints */0x03, /* bInterfaceClass: HID */0x01, /* bInterfaceSubClass : 1BOOT, 0no boot */0x01, /* nInterfaceProtocol : 0none, 1keyboard, 2mouse */0, /* iInterface: Index of string descriptor *//******************** Descriptor of Custom HID HID ********************//* 18 */0x09, /* bLength: HID Descriptor size */0x21, /* 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 */KEYBOARD_SIZ_REPORT_DESC,//KEYBOARD_SIZ_REPORT_DESC,/* wItemLength: Total length of Report descriptor */0x00,/******************** Descriptor of Custom HID endpoints ******************//* 27 */0x07, /* bLength: Endpoint Descriptor size */USBD_DESC_ENDPOINT, /* bDescriptorType: */0x84, /* bEndpointAddress: Endpoint Address (IN) */0x03, /* bmAttributes: Interrupt endpoint */0x08, /* wMaxPacketSize: 8 Bytes max */0x00,0x20, /* bInterval: Polling Interval (32 ms) *//* 34 */ 0x07, /* bLength: Endpoint Descriptor size */USBD_DESC_ENDPOINT, /* bDescriptorType: *//* Endpoint descriptor type */0x04, /* bEndpointAddress: *//* Endpoint Address (OUT) */0x03, /* bmAttributes: Interrupt endpoint */0x01, /* wMaxPacketSize: 2 Bytes max */0x00,0x20, /* bInterval: Polling Interval (20 ms) *//* 41 *//********************************功能2 VCP虚拟串口*****************************//*IAD描述符*//* Interface Association Descriptor(IAD Descriptor) */ 0x08, /* bLength */0x0B, /* bDescriptorType*/0x01, /* bFirstInterface*/0x02, /* bInterfaceCount*/0x02, /* bFunctionClass --CDC*/0x02, /* bFunctionSubClass*/0x01, /* bFunctionProtocoll*/0x00, /* iFunction *//**VCP虚拟串口**//*Interface Descriptor接口描述符*/0x09, /* bLength: Interface Descriptor size */USBD_DESC_INTERFACE, /* bDescriptorType: Interface *//* Interface descriptor type */0x01, /* bInterfaceNumber: Number of Interface */ //接口 10x00, /* bAlternateSetting: Alternate setting */0x01, /* bNumEndpoints: One endpoints used 该接口非0端点数*/0x02, /* bInterfaceClass: Communication Interface Class */0x02, /* bInterfaceSubClass: Abstract Control Model */0x01, /* bInterfaceProtocol: Common AT commands */0x00, /* 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: D0D1 */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 */0x00, /* bMasterInterface: Communication class interface */0x01, /* bSlaveInterface0: Data Class Interface *//*Endpoint 2 Descriptor端点描述符*/0x07, /* bLength: Endpoint Descriptor size */USBD_DESC_ENDPOINT, /* bDescriptorType: Endpoint */0x82, /* bEndpointAddress: (IN2) */0x03, /* bmAttributes: Interrupt */VIRTUAL_COM_PORT_INT_SIZE, /* wMaxPacketSize: */0x00,0xFF, /* bInterval: *//*Data class interface descriptor类描述符*/0x09, /* bLength: Endpoint Descriptor size */USBD_DESC_INTERFACE, /* bDescriptorType: */0x02, /* bInterfaceNumber: Number of Interface */0x00, /* bAlternateSetting: Alternate setting */0x02, /* bNumEndpoints: Two endpoints used */0x0A, /* bInterfaceClass: CDC */0x00, /* bInterfaceSubClass: */0x00, /* bInterfaceProtocol: */0x00, /* iInterface: *//*Endpoint 3 Descriptor端点描述符*/0x07, /* bLength: Endpoint Descriptor size */USBD_DESC_ENDPOINT, /* bDescriptorType: Endpoint */0x01, /* bEndpointAddress: (OUT1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00, /* bInterval: ignore for Bulk transfer *//*Endpoint 1 Descriptor 端点描述符*/0x07, /* bLength: Endpoint Descriptor size */USBD_DESC_ENDPOINT, /* bDescriptorType: Endpoint */0x81, /* bEndpointAddress: (IN1) */0x02, /* bmAttributes: Bulk */VIRTUAL_COM_PORT_DATA_SIZE, /* wMaxPacketSize: */0x00,0x00 /* bInterval */}; 3、USB HID报告描述符
const uint8_t s_hidKeyboardReportDescriptor[HID_REPORT_DESCRIPTOR_SIZE] {/*short Item D7~D4:bTag;D3~D2:bType;D1~D0:bSize**bTag ---主条目 1000:输入(Input) 1001:输出(Output) 1011:特性(Feature) 1010:集合(Collection) 1100:关集合(End Collection) ** 全局条目 0000:用途页(Usage Page) 0001:逻辑最小值(Logical Minimum) 0010:逻辑最大值(Logical Maximum) 0011:物理最小值(Physical Minimum)** 0100:物理最大值(Physical Maximum) 0101:单元指数(Unit Exponet) 0110:单元(Unit) 0111:数据域大小(Report Size)** 1000:报告ID(Report ID) 1001:数据域数量(Report Count) 1010:压栈(Push) 1011:出栈(Pop) 1100~1111:保留(Reserved)** 局部条目 0000:用途(Usage) 0001:用途最小值(Usage Minimum) 0010:用途最大值(Usage Maximum) 0011:标识符索引(Designator Index)** 0100:标识符最小值(Designator Minimum) 0101:标识符最大值(Designator Maximum) 0111:字符串索引(String Index) 1000:字符串最小值(String Minimum) ** 1001:字符串最大值(String Maximum) 1010:分隔符(Delimiter) 其他保留(Reserved)**bType---00:主条目(main) 01:全局条目(globle) 10:局部条目(local) 11:保留(reserved)**bSize---00:0字节 01:1字节 10:2字节 11:4字节*///0x05:0000 01 01 这是个全局条目用途页选择为普通桌面页0x05, 0x01, // USAGE_PAGE (Generic Desktop)//0x09:0000 10 01 这是个全局条目用途选择为键盘0x09, 0x06, // USAGE (Keyboard)//0xa1:1010 00 01 这是个主条目选择为应用集合0xa1, 0x01, // COLLECTION (Application)//0x05:0000 01 11 这是个全局条目用途页选择为键盘/按键0x05, 0x07, // USAGE_PAGE (Keyboard/Keypad)//0x19:0001 10 01 这是个局部条目用途的最小值为0xe0对应键盘上的左ctrl键0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)//0x29:0010 10 01 这是个局部条目用途的最大值为0xe7对应键盘上的有GUI(WIN)键0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)//0x15:0001 01 01 这是个全局条目说明数据的逻辑值最小值为00x15, 0x00, // LOGICAL_MINIMUM (0)//0x25:0010 01 01 这是个全局条目说明数据的逻辑值最大值为10x25, 0x01, // LOGICAL_MAXIMUM (1)//0x95:1001 01 01 这是个全局条目数据域的数量为8个0x95, 0x08, // REPORT_COUNT (8)//0x75:0111 01 01 这是个全局条目每个数据域的长度为1位0x75, 0x01, // REPORT_SIZE (1) //0x81:1000 00 01 这是个主条目有8*1bit数据域作为输入属性为:Data,Var,Abs0x81, 0x02, // INPUT (Data,Var,Abs)//0x95:1001 01 01 这是个全局条目,数据域的数量为1个0x95, 0x01, // REPORT_COUNT (1)//0x75:0111 01 01 这是个全局条目每个数据域的长度为8位0x75, 0x08, // REPORT_SIZE (8)//0x81:1000 00 01 这是个主条目有1*8bit数据域作为输入属性为:Cnst,Var,Abs0x81, 0x03, // INPUT (Cnst,Var,Abs)//0x95:1001 01 01 这是个全局条目数据域的数量为6个0x95, 0x06, // REPORT_COUNT (6)//0x75:0111 01 01 这是个全局条目每个数据域的长度为8位0x75, 0x08, // REPORT_SIZE (8)//0x25:0010 01 01 这是个全局条目逻辑最大值为2550x25, 0xFF, // LOGICAL_MAXIMUM (255)//0x19:0001 10 01 这是个局部条目用途的最小值为00x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))//0x29:0010 10 01 这是个局部条目用途的最大值为0x650x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)//0x81:1000 00 01 这是个主条目有6*8bit的数据域作为输入属相为属性为:Data,Var,Abs0x81, 0x00, // INPUT (Data,Ary,Abs)//0x25:0010 01 01 这是个全局条目逻辑的最大值为10x25, 0x01, // LOGICAL_MAXIMUM (1)//0x95:1001 01 01 这是个全局条目数据域的数量为20x95, 0x02, // REPORT_COUNT (2)//0x75:0111 01 01 这是个全局条目每个数据域的长度为1位0x75, 0x01, // REPORT_SIZE (1)//0x05:0000 01 01 这是个全局条目用途页选择为LED页0x05, 0x08, // USAGE_PAGE (LEDs)//0x19:0001 10 01 这是个局部条目用途的最小值为0x01,对应键盘上的Num Lock0x19, 0x01, // USAGE_MINIMUM (Num Lock)//0x29:0010 10 01 这是个局部条目用途的最大值为0x02,对应键盘上的Caps Lock0x29, 0x02, // USAGE_MAXIMUM (Caps Lock)//0x91:1001 00 01 这是个主条目有2*1bit的数据域作为输出属性为:Data,Var,Abs0x91, 0x02, // OUTPUT (Data,Var,Abs)//0x95:1001 01 01 这是个全局条目数据域的数量为1个0x95, 0x01, // REPORT_COUNT (1)//0x75:0111 01 01 这是个全局条目每个数据域的长度为6bit,正好与前面的2bit组成1字节0x75, 0x06, // REPORT_SIZE (6)//0x91:1001 00 01 这是个主条目有1*6bit数据域最为输出属性为:Cnst,Var,Abs0x91, 0x03, // OUTPUT (Cnst,Var,Abs)0xc0 // END_COLLECTION}; 4、修改端点缓存地址
在 usb_config.h中调整每个USB端点分配的地址。
#define ENDP0_RXADDR (0x40)#define ENDP0_TXADDR (0x80)#define ENDP1_TXADDR (0xC0)#define ENDP1_RXADDR (0x0F0)#define ENDP2_TXADDR (0x110)#define ENDP4_RXADDR (0x150)#define ENDP4_TXADDR (0x190) 这时候就完成基本的配置可以让电脑识别到键盘和虚拟串口的设备但不能正常使用。
接下来就是代码初始化部分的修改。 基于本来虚拟串口的初始化增加HID配置
void CDC_Init(void){USBD_InitParam_T usbParam;USBD_InitParamStructInit(usbParam);usbParam.classReqHandler USBD_ClassHandler;usbParam.stdReqExceptionHandler KeyBoard_ReportDescriptor;//增加HID配置usbParam.resetHandler VCP_Reset;usbParam.inEpHandler USBD_VCP_InEpCallback;usbParam.outEpHandler USBD_VCP_OutEpCallback;usbParam.pDeviceDesc (USBD_Descriptor_T *)g_deviceDescriptor;usbParam.pConfigurationDesc (USBD_Descriptor_T *)g_configDescriptor;usbParam.pStringDesc (USBD_Descriptor_T *)g_stringDescriptor;usbParam.pStdReqCallback stdReqCallback;USBD_Init(usbParam);}void KeyBoard_ReportDescriptor(USBD_DevReqData_T *reqData){uint8_t len;if((reqData-byte.bRequest USBD_GET_DESCRIPTOR) (reqData-byte.bmRequestType.bit.recipient USBD_RECIPIENT_INTERFACE) (reqData-byte.bmRequestType.bit.type USBD_REQ_TYPE_STANDARD)){if(reqData-byte.wValue[1] 0x21){len USB_MIN(reqData-byte.wLength[0], 9);USBD_CtrlInData((uint8_t *)g_configDescriptor.pDesc[0x12], len);}else if(reqData-byte.wValue[1] 0x22){len USB_MIN(reqData-byte.wLength[0], g_ReportDescriptor.size);USBD_CtrlInData((uint8_t *)g_ReportDescriptor.pDesc, len);}}else{USBD_SetEPTxRxStatus(USBD_EP_0, USBD_EP_STATUS_STALL, USBD_EP_STATUS_STALL);}} 到此配置部分基本完成接下来到main中增加段测试代码验证USB配置是否正确。
配置虚拟串口一直打印dataBuf[5] {0xaa,0xbb,0xcc,0xdd,0xff};
HID键盘根据键值表输出数字1 void Delay(uint32_t i){while(i--);}unsigned char dataBuf[5] {0xaa,0xbb,0xcc,0xdd,0xff};uint8_t Keyboad_Buf[8]{0,0,0x1E,0,0,0,0,0};int main(void){CDC_Init();while(1){USBD_TxData(USBD_EP_1, dataBuf, 5);USBD_TxData(USBD_EP_4, Keyboad_Buf, 8);Delay(0xFFFFFF);}} 烧录代码到开发板接上USB线到电脑可以看到Bushound能看到配置的复合设备。 使用串口助手能看到虚拟串口能正确打印我们的数据键盘也正常在发送数字1证明代码配置没问题两个功能使用一个USB接口实现了。SDK的虚拟串口也有做接收回传的功能可以直接使用。 到此键盘虚拟串口的例程就简单修改完成了。 注文章作者在原帖中提供了例程文件有需要请至原文21ic论坛下载 原文地址https://bbs.21ic.com/icview-3321226-1-1.html