简介
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接收缓冲区基地址
删除 #define EP2_OUT_Callback NOP_Process 一行
在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设备发来的数据
用串口打印出收到的数据