前期准备:
一、硬件资源:STM32F103,USB-FS固件库。
链接:
STM32 之 标准外设版USB驱动库详解(架构+文件+函数+使用说明+示例程序)
https://blog.csdn.net/ZCShouCSDN/article/details/78936456?utm_source=blogxgwz1
二、调试软件:usbtrace3.0或者BusHound,用于看USB设备的信息。KEIL编译环境-用于开发。
后续相关工作:
(1)用STM32CubeMX配置,具体实现其它的HID,自定义虚拟串口等实验;
链接:利用STM32CubeMX生成BID通信
https://www.cnblogs.com/libra13179/p/6891685.html?utm_source=itdadao&utm_medium=referral
(2)了解USB的枚举配置过程。
链接:https://blog.csdn.net/huohongpeng/article/details/54927337
三、重点掌握的知识点:
(1)USB设备描述符,
(2)STM32F103的USB-FS固件库相关架构;
(3)USB的数据发送与接收,即通信原理;
本次USB做成复合设备,HID+AUDIO_MIDI设备,HID与上位机通信,MIDI设备与主流音乐DAW软件通信
(4)调试USB数据包的过程;
(5)移植步骤:
--配置好相关的KEIL工程,或者STM32CubeMX配置;
--添加USB固件库里面的HID工程-参考正点原子的STM32F1开发指南-库函数版本_V3.1;
--修改相应的usb描述符,VID/PID等,可以添加原子自己的USB启动通用函数;
(6)技术参考以下博文:
1-STM32 USB 之从0开始移植笔记https://blog.csdn.net/gzzxbcxm2005/article/details/51347624
2-从头调试STM32 HID http://www.cnblogs.com/sz189981/p/7291121.html
3-移植STM32固件库用于HID双向通信https://blog.csdn.net/a827415225/article/details/51745013
调试中期:
一、移植好修改配置描述符后插入PC端,显示HID-人体学输入设备与USB输入设备,AUDIO设备也增加了一个
图一:
图二:
BUS Hound 软件捕捉到的信息:
至此,产品已经能正确的MIDI通信,至于HID上位机通信,后面将补充代码
二、程序解析
(1)USB数据包的发送与接收;
--USB数据的发送与接收流程分析https://www.cnblogs.com/skl374199080/p/3910066.html
自己重写的MIDI发送代码:
uint32_t USB_SendData(uint8_t *data,uint32_t dataNum) { // #ifndef STM32F10X_MD //¸Ä±äÈ«¾Ö¶¨Òå //½«Êý¾Ýͨ¹ýUSB·¢ËͳöÈ¥-----------by EP2¶Ëµã·¢ËÍTX UserToPMABufferCopy(data, ENDP4_TXADDR, dataNum); SetEPTxCount(ENDP4, 8); SetEPTxValid(ENDP4); //ʹÄÜ // #else // USB_SIL_Write(EP4_IN, data, dataNum); // SetEPTxValid(ENDP4); // #endif //return dataNum; } uint32_t USB_GetData(uint8_t *data,uint32_t dataNum) { uint32_t len=0; if(dataNum>sizeof(USB_Receive_Buffer)) { dataNum = sizeof(USB_Receive_Buffer); } for(len=0;len<dataNum;len++) { *data=USB_Receive_Buffer[len]; data++; } return dataNum; //·µ»Ø }
(2)主要的USB描述符--HID+AUDIO_MIDI设备
/* USB Standard Device Descriptor */ const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] = { 0x12, /*bLength */ USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/ 0x10, /*bcdUSB 1.0*/ 0x01, 0x00, /*bDeviceClass*/ 0x00, /*bDeviceSubClass*/ 0x00, /*bDeviceProtocol*/ 0x40, /*bMaxPacketSize 64 bytes*/ //ÕâÀïµÄsize»áÔì³ÉÉ豸ÇëÇóÃèÊö·ûʧ°Ü /************** ÉèÖÃVID and PID ****************/ 0x11, /*idVendor (0x0483)*/ 0x20, 0x15, /*idProduct = 0x5750*/ 0x07, 0x00, /*bcdDevice rel. 2.00*/ 0x00, 1, /*Index of string descriptor describing manufacturer */ 2, /*Index of string descriptor describing product*/ 3, /*Index of string descriptor describing the device serial number */ 0x01 /*bNumConfigurations*/ }; /* CustomHID_DeviceDescriptor */ /* USB Configuration Descriptor */ /* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */ const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] = { /************** Descriptor of standard audio +HID Configuration ****************///ÅäÖÃÃèÊö·û 0x09, /* bLength: Configuration Descriptor size */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */ 0x85, //Õâ¸ö³¤¶ÈÐèҪȷ¶¨ÏÂ133 /* wTotalLength: Bytes returned */ 0x00, 0x03, /* bNumInterfaces: 1 HID interface +MIDI 2 interface 03*/ 0x01, /* bConfigurationValue: Configuration value */ 0x00, /* iConfiguration: Index of string descriptor describingthe configuration*/ 0x00, /* bmAttributes: Self powered */ 0xFA, /* MaxPower 0xFA:500 mA */ /************** Descriptor of µÚÒ»¸ö HID ½Ó¿ÚÃèÊö·û ****************/ /* Interface Descriptor 0/0 HID, 2 Endpoints */ 0x09, /* bLength: Interface Descriptor size */ USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType: Interface descriptor type */ 0x00, /* bInterfaceNumber: Number of Interface */ //¸Ã½Ó¿ÚµÄ±àºÅ0 0x00, /* bAlternateSetting: Alternate setting */ //±¸ÓñàºÅ 0x02, /* bNumEndpoints */ //¶ËµãÊýÁ¿2£¬ÖжÏÊäÈëºÍÊä³ö 0x03, /* bInterfaceClass: HID */ 0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */ 0x00, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */ //ʹÓõÄÐÒé 0x00, /* iInterface: Index of string descriptor */ //¸Ã½Ó¿ÚµÄ×Ö·û´®Ë÷ÒýºÅ0ûÓÐ×Ö·û´® /******************** Descriptor of HID ÃèÊö·û ********************/ 0x09, /* bLength: HID Descriptor size */ HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID *///0x21 0x11, /* bcdHID: HID Class Spec release number *///HID 1.1ÐÒé 0x01, 0x00, /* bCountryCode: Hardware target country */ 0x01, /* bNumDescriptors: Number of HID class descriptors to follow *///ϼ¶ÃèÊö·ûÊýÁ¿-±¨¸æÃèÊö·û 0x22, /* bDescriptorType */ //ϼ¶ÃèÊö·ûÀàÐÍΪ±¨¸æÃèÊö·û£¬±àºÅ0x22 /* wItemLength: Total length of Report descriptor */ CUSTOMHID_SIZ_REPORT_DESC, //±¨¸æÃèÊö·ûµÄ´óС 0x00, /******************** Descriptor of Custom HID endpoints ¶ËµãÃèÊö·û******************/ /* Endpoint Descriptor 81 1 In, Interrupt, 1 ms */ //ÊäÈë¶Ëµã 0x07, /* bLength: Endpoint Descriptor size */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */ /* Endpoint descriptor type */ 0x81, /* bEndpointAddress: Endpoint Address (IN) */ // 1 IN Endpoint 0x03, /* bmAttributes: Interrupt endpoint */ //Ñ¡ÔñΪÖж϶˵ã 0x20, /* wMaxPacketSize: 32 Bytes max */ //µÍ×Ö½ÚÔÚǰ 0x00, 0x01, /* bInterval: Polling Interval (1 ms) */ //¶Ëµã²éѯʱ¼ä /* Endpoint Descriptor 02 2 Out, Interrupt, 1 ms*/ 0x07, /* bLength: Endpoint Descriptor size */ USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */ /* Endpoint descriptor type */ 0x02, /* bEndpointAddress: */ /* Endpoint Address (OUT) */ 0x03, /* bmAttributes: Interrupt endpoint */ 0x20, /* wMaxPacketSize: 32 Bytes max */ //µÍ×Ö½ÚÔÚǰ 0x00, 0x01, /* bInterval: Polling Interval (1 ms) */ //¶Ëµã²éѯʱ¼ä /************** Descriptor of µÚ¶þ¸ö MIDI AUDIO ½Ó¿ÚÃèÊö·û ****************/ /* Interface Descriptor 1/0 Audio, 0 Endpoints */ //ûÓж˵ã 0x09, /*bLength: Interface Descriptor size*/ 0x04, /*bDescriptorType: Interface descriptor type*/ 0x01, /*bInterfaceNumber: Number of Interface*/ //½Ó¿Ú±àºÅ01 0x00, /*bAlternateSetting: Alternate setting*/ 0x00, /*bNumEndpoints: no endpoints*/ 0x01, /*bInterfaceClass: Audio device class 0x01*/ 0x01, /*bInterfaceSubClass : Audio control*/ 0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ 0x00, /*iInterface: Index of string descriptor*/ /* Audio Control Interface Header Descriptor */ //class_specific_interface_descritor //ÀàÌØÊâ½Ó¿ÚÃèÊö·û£ºÀàÌØÊâÒôƵ¿ØÖÆ½Ó¿Ú 0x09, //ÀàÌØÊâ½Ó¿ÚÃèÊö·ûµÄ×Ö½ÚÊý´óС 0x24, //ÀàÌØÊâ½Ó¿ÚÃèÊö·ûÀàÐͱàºÅ 0x01, //ÃèÊö·û×ÓÀà 0x00, 0x01, //×ÓÀà°æ±¾£¬1.0 0x09, 0x00, //ÀàÌØÊâÃèÊö´óС 0x01, //Á÷½Ó¿ÚÊýÁ¿ 0x02, //MIDI Á÷½Ó¿Ú1ÊôÓÚ´ËÒôƵ¿ØÖÆ½Ó¿Ú /* Interface Descriptor 2/0 Audio, 2 Endpoints */ //Á½¸ö¶Ëµã //Standard MS Interface Descriptor£¬Ê¹ÓÃÁ½¸öÅúÁ¿¶ËµãÀ´·Ö±ðÊä³öºÍÊäÈëMIDIÊý¾ÝÁ÷---µÚ¶þ¸ö½Ó¿Ú 0x09, //bLength½Ó¿ÚÃèÊö·ûµÄ×Ö½ÚÊý´óС 0x04, //bDescriptorType½Ó¿ÚÃèÊö·ûÀàÐͱàºÅ 0x02, //bInterfaceNumber½Ó¿Ú±àºÅΪ02 0x00, //bAlternateSetting±¸ÓñàºÅΪ0 0x02, //bNumEndpoints·Ç0¶ËµãÊýÁ¿Îª2 bNumEndpoints,Ò»¶ÔÅúÁ¿¶Ëµã 0x01, //bInterfaceClassÒôƵÉ豸£¨AUDIO£©Àà0x01 bInterfaceSubClass0x03 0x03, //ʹÓõÄ×ÓÀࣺMIDIÁ÷(MIDI STREAMING)Àà 0x00, //δÓÃbInterfaceProtocol 0x00, //δÓÃbInterfaceProtocol /************** ÀàÌØÊâMIDIÁ÷½Ó¿ÚÃèÊö·û----ÖØµãÅäÖÃ**************************************/ /*ÀàÌØÊâMIDIÁ÷ÃèÊöÉ豸ÄÚ¸÷¸öÄ£¿éµÄÁ¬½Ó¹ØÏµ£¬ÓÐËÄÖÖ²å¿×£ºÄÚǶÊäÈ룬ÄÚǶÊä³ö£¬ÍⲿÊäÈ룬ÍⲿÊä³ö£¨·½ÏòÏà¶ÔÓÚÉ豸£© ÿ¸ö²å¿×¶¼Î¨Ò»µÄID±àºÅ£¬ É豸µÄÊý¾Ýͨ¹ýÄÚǶÊä³ö²å¿×Êä³öµ½¼ÆËã»ú£¬²»ÊÇÖ±½Óµ½PC,¶øÊÇͨ¹ýÐéÄâÍⲿÊäÈë²å¿×Á¬½Ó */ /* MIDI Streaming Interface Header Descriptor */ 0x07, //ÀàÌØÊâMS½Ó¿ÚÍ·ÃèÊö·ûµÄ×Ö½ÚÊý´óС----Í·ÃèÊö·û 0x24, //ÀàÌØÊâ½Ó¿ÚÃèÊö·ûÀàÐͱàºÅ0x24 0x01, //ÃèÊö·û×ÓÀà 0x00, 0x01, //×ÓÀà°æ±¾£¬1.0 0x41, 0x00, //ÀàÌØÊâÃèÊö×ܳ¤¶È0x0041 //MIDI IN Jack Descriptor(Embedded) ÄÚǶIN½Ó¿Ú 0x06, //MIDIÊäÈë²å¿×ÃèÊö·û 0x24, //ÀàÌØÊâ½Ó¿Ú 0x02, //MIDI_IN_JACK×ÓÀà0x02 0x01, //EMBEDDED²å¿×Àà 0x01, //¸Ã²å¿ÚµÄID-------------------1 0x00, //δÓà //MIDI IN Jack Descriptor (External) ÍⲿIN½Ó¿Ú 0x06, //MIDIÊäÈë²å¿×ÃèÊö·û 0x24, //ÀàÌØÊâ½Ó¿Ú 0x02, //MIDI_IN_JACK×ÓÀà 0x02, //EXTERNAL²å¿×Àà 0x02, //¸Ã²å¿ÚµÄID-------------------2 0x00, //δÓà //MIDI OUT Jack Descriptor ÄÚǶOUT½Ó¿Ú 0x09, //MIDIÊäÈë²å¿×ÃèÊö·û 0x24, //ÀàÌØÊâ½Ó¿Ú 0x03, //MIDI_OUT_JACK×ÓÀà 0x01, //EMBEDDED²å¿×Àà 0x03, //¸Ã²å¿ÚµÄID------------------3 0x01, //¸Ã²å¿ÚµÄÊäÈëÒý½ÅÊý 0x02, //Á¬½Ó¸ÃÒý½ÅËùÔÚʵÌåµÄID-----ÍⲿIN²å¿×---ÐéÄâÁ¬½ÓÆðÀ´ 0x01, //Á¬½Óµ½¸ÃʵÌåÊä³ö½ÅµÄÊäÈë½ÅµÄ±àºÅ 0x00, //δÓà //MIDI OUT Jack Descriptor (External) ÍⲿOUT½Ó¿Ú 0x09, //MIDIÊäÈë²å¿×ÃèÊö·û 0x24, //ÀàÌØÊâ½Ó¿Ú 0x03, //MIDI_OUT_JACK×ÓÀà 0x02, //EXTERNAL²å¿×Àà 0x04, //¸Ã²å¿ÚµÄID------------------4 0x01, //¸Ã²å¿ÚµÄÊäÈëÒý½ÅÊý 0x01, //¸ÃÒý½ÅËùÔÚʵÌåµÄID--------ÄÚǶÊäÈë²å¿× 0x01, //Á¬½Óµ½¸ÃʵÌåÊä³ö½ÅµÄÊäÈë½ÅµÄ±àºÅ 0x00, /***************************¶ËµãÃèÊö·ûºÍÀàÌØÊâ¶ËµãÃèÊö·û£¨MS£©********************* ÿ¸ö±ê×¼µÄÅúÁ¿Êý¾Ý¶ËµãÃèÊö·ûºóÃæ¸ú×ÅÒ»¸öÀàÌØÊâÊý¾Ý¶ËµãÃèÊö·û*********************/ /* Endpoint Descriptor 03 3 Out, Bulk, 64 bytes */ 0x09, //¶ËµãÃèÊö·ûµÄ×Ö½ÚÊý´óС 0x05, //¶ËµãÃèÊö·ûÀàÐͱàºÅ 0x03, //3 out bEndpointAddress 0x02, //ʹÓõĴ«ÊäÀàÐÍ£ºÅúÁ¿´«ÊäBULK 0x40, //¸Ã¶ËµãÖ§³ÖµÄ×î´ó°ü³ß´ç£¬64×Ö½Ú 0x00, 0x00, //ÖжÏɨÃèʱ¼ä£¬ÎÞЧ//bInterval 0x00, //bRefresh 0x00, //bSynchAddress /* Unrecognized Audio Class-Specific Descriptor */ 0x05, //¶ËµãÃèÊö·ûµÄ×Ö½ÚÊý´óС 0x25, //Unrecognized Audio Class-Specific 0x01, 0x01, 0x01, /* Endpoint Descriptor 84 4 In, Bulk, 64 bytes */ 0x09, //¶ËµãÃèÊö·ûµÄ×Ö½ÚÊý´óС 0x05, //¶ËµãÃèÊö·ûÀàÐͱàºÅ 0x84, //4 IN bEndpointAddress 0x02, //ʹÓõĴ«ÊäÀàÐÍ£ºÅúÁ¿´«ÊäBULK 0x40, //¸Ã¶ËµãÖ§³ÖµÄ×î´ó°ü³ß´ç£¬64×Ö½Ú 0x00, 0x00, //ÖжÏɨÃèʱ¼ä£¬ÎÞЧ0x0A//bInterval 0x00, //bRefresh 0x00, //bSynchAddress /* Unrecognized Audio Class-Specific Descriptor */ 0x05, //¶ËµãÃèÊö·ûµÄ×Ö½ÚÊý´óС 0x25, //Unrecognized Audio Class-Specific 0x01, 0x01, 0x03 };
(3)其中的4个端点地址的设置需要研究下,
链接:
stm32 usb数据缓冲区疑问
http://blog.sina.com.cn/s/blog_640029b30100vwfp.html
#define BTABLE_ADDRESS (0x00)
/* EP0 */
/* rx/tx buffer base address */
//#define ENDP0_RXADDR (0x18)
//#define ENDP0_TXADDR (0x58)
#define ENDP0_RXADDR (0x40)
#define ENDP0_TXADDR (0x80)
/* EP1 */
/* tx buffer base address */
#define ENDP1_TXADDR (0xC0) //ENDP0_TXADDR+0x40¿ªÊ¼
//#define ENDP1_RXADDR (0x130+0x40)
/* EP2 */
/* rx buffer base address */
#define ENDP2_RXADDR (0xE0)
//#define ENDP2_TXADDR (0x170+0x40)
/* EP3 RX*/
/* tx buffer base address */
//#define ENDP3_TXADDR (0x210)
#define ENDP3_RXADDR (0x100)
/* EP4 TX*/
/* tx buffer base address */
#define ENDP4_TXADDR (0x100+0x40)
//#define ENDP4_RXADDR (0x250+0x40)
(4)对于USB HID的理解参考以下博文: