STM32的USB例程JoyStickMouse改成自定义HID设备

时间:2024-04-03 22:12:01

简介

USB HID类是USB设备的一个标准设备类,包括的设备非常多。HID类设备定义它属于人机交互操作的设备,用于控制计算机操作的一些方面,如USB鼠标、USB键盘、USB游戏操纵杆等。但HID设备类不一定要有人机接口,只要符合HID类别规范的设备都是HID设备。
USB HID设备的一个好处就是操作系统自带了HID类的驱动程序,而用户无需去开发驱动程序,只要使用API系统调用即可完成通信。
STM32F1的JoyStickMouse例程用到了端点1用作鼠标数据输入,要改成能双向通信的自定义HID设备就要增加一个端点用于数据输出,本文用端点1为输入,端点2为输出,包长分别为EP1_MAX_TXSIZE,EP2_MAX_RXSIZE字节,下面是具体操作

1.修改USB描述符,增加一个输出端点

设备描述符可以不用改动

/*设备描述符*/
const uint8_t Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC] =
  {
    0x12,                       /*bLength */						/*USB设备描述符的长度 固定为12H*/
    USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/					/*USB设备描述符的类型值 固定为01H*/
    0x00,                       /*bcdUSB */							/*USB版本号*/
    0x02,																								/*bcdUSB = 2.00*/
    0x00,                       /*bDeviceClass*/				/*USB所遵循的标准设备类。0表示设备的接口相互独立,分别属于不同的设备类;
																1~FEH之间表示USB协议中定义的某个类。03H表示HID类,02H表示CDC类。
																FFH表示供应商自定义的设备类*/
    0x00,                       /*bDeviceSubClass*/				/*USB设备所属的标准设备子类 bDeviceClass为0时,该值为0;该值为FFH时,表示供应商自定义的设备子类*/
    0x00,                       /*bDeviceProtocol*/					/*采用的设备类协议。该值为FFH时表示设备类协议由供应商自定义*/
    0x40,                       /*bMaxPacketSize 64*/			/*端点0所支持最大数据包长度(字节),低速为8,全速为8,16,32或64,高速为64*/
    0x83,                       /*idVendor (0x0483)*/			/*VID*/
    0x04,
    0x50,                       /*idProduct = 0x5750*/			/*PID*/
    0x57,
    0x00,                       /*bcdDevice rel. 2.00*/	/*设备版本号*/
    0x02,
    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*/	/*USB设备所支持的配置数*/
  };

下面我们需要把接口描述符的端点数量改为2,然后添加一个端点描述符用于接收数据,再修改描述符数组长度JOYSTICK_SIZ_CONFIG_DESC

	/*配置描述符*/
/*   All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
const uint8_t Joystick_ConfigDescriptor[JOYSTICK_SIZ_CONFIG_DESC] =
  {
    0x09, /* bLength*/											/*描述符的长度*/
    USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType*/		/*USB设备描述符的类型值 固定为02H*/
    JOYSTICK_SIZ_CONFIG_DESC,	/* wTotalLength*/				/*配置描述符的总长*/
    0x00,
    0x01,         /*bNumInterfaces*/							/*此配置所支持的接口个数*/
    0x01,         /*bConfigurationValue*/
    0x00,         /*iConfiguration*/	        
	0xC0,         /*bmAttributes: Self powered */
    0x32,         /*MaxPower 100mA*/
		/**************接口描述符***************/
    /* 09 */
    0x09,         /*bLength*/
    USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType*/	/*USB接口描述符的类型值 固定为04H*/
    0x00,         /*bInterfaceNumber*/					/*接口号*/
    0x00,         /*bAlternateSetting*/					/*可选设置的索引值*/
    0x02,         /*bNumEndpoints*/						/*此接口用的端点数量,由1改为2,端点0不算在内*/
    0x03,         /*bInterfaceClass*/					/*HID*/
    0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
    0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
    0,            /*iInterface: Index of string descriptor*/	
 
		/*******************HID描述符******************/
    /* 18 */
    0x09,         /*bLength: HID Descriptor size*/
    HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/			/*USB HID描述符的类型值 固定为21H*/
    0x10,         /*bcdHID*/								/*HID版本号*/
    0x01,
    0x00,         /*bCountryCode*/							/*HID设备国家/地区代码*/
    0x01,         /*bNumDescriptors*/
    0x22,         /*bDescriptorType*/																							
		JOYSTICK_SIZ_REPORT_DESC,/*wItemLength*/			/*HID报告描述符长度,改成修改后的的HID报告描述符长度*/
    0x00,

		/*****************端点描述符********************/
    /* 27 */
    0x07,          /*bLength*/
    USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/	/*USB端点描述符的类型值 固定为05H*/

    0x81,          /*bEndpointAddress*/					/*端点地址及输入输出属性*//*bit7: 输入=1,输出=0;bit0,1,2,3:端点号*/
    0x03,          /*bmAttributes*/						/*端点的传输类型属性 bit0~1	 00=控制传输、01=同步传输、10=批量传输、11=中断传输*/
    EP1_MAX_TXSIZE,/*wMaxPacketSize*/					/*端点收、发的最大包大小,这里改成需要的大小*/
    0x00,
    0x1,          /*bInterval*/							/*定义了该端点被主机的访问周期,此域值对于批量传输和控制传输毫无意义。*/
    /* 34 */
									/*在这里添加一个新的端点描述符用于接收主机输出的数据*/																														
	0x07,          /*bLength*/
    USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/						
    0x02,          /*bEndpointAddress*/						/*端点2 输出*/
    0x03,          /*bmAttributes*/							/*中断传输*/
    EP2_MAX_RXSIZE,        /*wMaxPacketSize*/				/*端点收、发的最大包大小*/
    0x00,
    0x1,          /*bInterval*/																																					
		/*41*/
  }

然后修改HID报告描述符,用HID Descriptor Tool生成一个就行,改了这个主机就不会把usb设备识别为鼠标了

const uint8_t Joystick_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC] =
  {
0x05, 0x8c, 						/* USAGE_PAGE (ST Page) */ 
	0x09, 0x01, 					/* USAGE (Demo Kit) */ 
	0xa1, 0x01,						/* COLLECTION (Application) */ 
	
	// The Input report 
	0x09,0x03, 						// USAGE ID - Vendor defined 
	0x15,0x00, 						// LOGICAL_MINIMUM (0) 
	0x26,0x00, 0xFF,			// LOGICAL_MAXIMUM (255) 
	0x75,0x08, 						// REPORT_SIZE (8bit) 
	0x95,EP1_MAX_TXSIZE,	// REPORT_COUNT (4Byte) 
	0x91,0x02,						// INtPUT (Data,Var,Abs) 

	// The Output report 
	0x09,0x04,						// USAGE ID - Vendor defined 
	0x15,0x00,						// LOGICAL_MINIMUM (0) 
	0x26,0x00,0xFF, 			// LOGICAL_MAXIMUM (255) 
	0x75,0x08, 						// REPORT_SIZE (8bit) 
	0x95,EP2_MAX_RXSIZE, 	// REPORT_COUNT (4Byte) 
	0x81,0x02,						// OUTPUT (Data,Var,Abs) 

0xc0 										/* END_COLLECTION */ 

2.在Joystick_Reset函数中添加端点2初始化代码

	/* Initialize Endpoint 2 */
	SetEPType(ENDP2, EP_INTERRUPT);					//端点2为中断端点																	
 	SetEPRxAddr(ENDP2, ENDP2_RXADDR);				//设置接收缓冲区地址
 	SetEPRxCount(ENDP2, EP2_MAX_RXSIZE);			//每次接收EP2_MAX_RXSIZE个字节
	SetEPRxStatus(ENDP2, EP_RX_VALID);

3.编写端点2的输出回调函数

首先在usb_conf.h文件中把端点数设置为3,然后设置设置端点2接收缓冲区基地址

STM32的USB例程JoyStickMouse改成自定义HID设备
删除 #define EP2_OUT_Callback NOP_Process 一行
STM32的USB例程JoyStickMouse改成自定义HID设备

在usb_endp.c中编写端点2输出回调函数
先从缓冲区中读取主机发过来的数据,再把端点2状态设置为VALID

void EP2_OUT_Callback(void)		
{
	u8 *buff;													
	buff=(u8*)mymalloc(EP2_MAX_RXSIZE);
	PMAToUserBufferCopy(buff,ENDP2_RXADDR, EP2_MAX_RXSIZE);//从接收缓冲区中读取EP2_MAX_RXSIZE字节数据
	SetEPRxStatus(ENDP2, EP_RX_VALID);
	for(u8 i=0;i<EP2_MAX_RXSIZE;i++)
	{
		printf("RxBuff[%d]=0x%x\n",i,buff[i]);
	}
}

再修改一下Joystick_Send函数

void Joystick_Send(u8 *buffer,u8 size)
{
   
	if(size>EP1_MAX_TXSIZE)
	{
		return;
	}
	/* Copy mouse position info in ENDP1 Tx Packet Memory Area*/
	USB_SIL_Write(EP1_IN,buffer, EP1_MAX_TXSIZE); 
	/* Enable endpoint for transmission */
	SetEPTxValid(ENDP1);  
}

到这里,修改工作差不多就完成了,下面是收发数据测试

4.完成

主机接收到自定义HID设备发来的数据
STM32的USB例程JoyStickMouse改成自定义HID设备
用串口打印出收到的数据
STM32的USB例程JoyStickMouse改成自定义HID设备