STM32 USB HID详解.docx

上传人:b****4 文档编号:12381073 上传时间:2023-04-18 格式:DOCX 页数:19 大小:34.86KB
下载 相关 举报
STM32 USB HID详解.docx_第1页
第1页 / 共19页
STM32 USB HID详解.docx_第2页
第2页 / 共19页
STM32 USB HID详解.docx_第3页
第3页 / 共19页
STM32 USB HID详解.docx_第4页
第4页 / 共19页
STM32 USB HID详解.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

STM32 USB HID详解.docx

《STM32 USB HID详解.docx》由会员分享,可在线阅读,更多相关《STM32 USB HID详解.docx(19页珍藏版)》请在冰豆网上搜索。

STM32 USB HID详解.docx

STM32USBHID详解

STM32USBHID详解

1、USB简介

2、USB描述符

USB只是一个总线,只提供一个数据通路而已。

USB总线驱动程序并不知道一个设备具体如何操作,有哪些行为。

具体的一个设备实现什么功能,要由设备自己来决定。

那么,USB主机是如何知道一个设备的功能以及行为呢?

这就要通过描述符来实现了。

描述符中记录了设备的类型、厂商ID和产品ID(通常依靠它们来加载对应的驱动程序)、端点情况、版本号等众多信息。

标准的USB设备有5种USB描述符:

设备描述符,配置描述符,接口描述符,端点描述符,字符串描述符。

下面详解:

2.1、设备描述符

一个USB设备只有一个设备描述符。

设备描述符主要记录的信息有:

设备所使用的USB协议版本号、设备类型、端点0的最大包大小、厂商ID(VID)和产品ID(PID)、设备版本号、厂商字符串索引、产品字符串索引、设备序列号索引、可能的配置数等。

偏移量

大小/字节

说明

0

bLength

1

该描述符的长度(0x12=18字节)

1

bDescriptorType

1

描述符类型(0x01设备描述符)

2

bcdUSB

2

本设备使用的USB协议版本

4

bDeviceClass

1

类代码

5

bDeviceSubClass

1

子类代码

6

bDeviceProtocol

1

协议码

7

bMaxPacketSize

1

端点0最大包长

8

idVendor

2

厂商ID

10

idProduct

2

产品ID

12

bcdDevice

2

设备版本号

14

iManufacturer

1

描述厂商的字符串索引

15

iProduct

1

描述产品的字符串索引

16

iSerialNumber

1

产品序列号的字符串索引

17

bNumConfigurations

1

可能的配置数

2.2、配置描述符

设备描述符里决定了该设备有多少种配置,每种配置都有一个配置描述符。

配置描述符主要记录的信息有:

配置所包含的接口数、配置的编号、供电方式、是否支持远程唤醒、电流需求量等。

偏移量

大小/字节

说明

0

bLength

1

该描述符的长度(0x09字节)

1

bDescriptorType

1

描述符类型(0x02配置描述符)

2

wTotalLength

2

配置、接口、端点和类描述符字节总和

4

bNumInterfaces

1

支持接口数

5

bConfigurationValue

1

本配置描述符标识

6

iConfiguration

1

配置描述符说明字符串索引

7

bmAttributes

1

电源及唤醒

8

MaxPower

1

设备耗电电流

2.3、接口描述符

在每个配置描述符中又定义了该配置有多少个接口,每个接口都有一个接口描述符。

接口描述符主要记录的信息有:

接口的编号、接口的端点数、接口所使用的类、子类、协议等。

偏移量

大小/字节

说明

0

bLength

1

该描述符的长度(0x09字节)

1

bDescriptorType

1

描述符类型(0x04接口描述符)

2

bInterfaceNumber

1

本接口描述符标识

3

bAlternateSetting

1

4

bNumEndpoints

1

接口端点数

5

bInterfaceClass

1

接口类代码

6

bInterfaceSubClass

1

启动类型1=BOOT,0=NoBOOT

7

bInterfaceProtocol

1

0=None,1=Keyboard,2=Mouse

8

iInterface

1

接口描述符说明字符串索引

2.4、[类描述符]

该描述符不是必须的,如果配置的USB类型有类特殊描述符(如HID类),它跟在相应的接口描述符之后。

2.5、端点描述符

在接口描述符里又定义了该接口有多少个端点,每个端点都有一个端点描述符。

端点描述符主要记录的信息有:

端点号及方向、端点的传输类型、最大包长度、查询时间间隔等。

偏移量

大小/字节

说明

0

bLength

1

该描述符的长度(0x07字节)

1

bDescriptorType

1

描述符类型(0x5端点描述符)

2

bEndpointAddress

1

端点地址

3

bmAttributes

1

端点类型

4

wMaxPacketSize

2

端点发送接收最大包长

6

bInterval

1

中断端点轮训时间间隔

2.6、[字符串描述符]

字符串描述符主要是提供一些方便人们阅读的信息,它不是必需的。

偏移量

大小/字节

说明

0

bLength

1

该描述符的长度(0x04/0xXX字节),第一个字符串描述符0x04

1

bDescriptorType

1

描述符类型(0x3字符串描述符)

2

wLANGID

2/XX

第一个字符串描述符时2字节,表示语言编码,其他自定义

3、USBHID

为了把一个设备识别为HID类别,设备在定义描述符的时候必须遵守HID规范。

除了USB标准定义的一些描述符外,HID设备还必须定义HID描述符。

另外设备和主机的通信是通过报告的形式来实现的,所以还必须定义报告描述符;而物理描述符不是必需的。

还有就是HID描述符是关联于接口(而不是端点)的,所以设备不需要为每个端点都提供一个HID描述符。

详情参看《USBHID协议中文版_USBHID设备》

3.1、HID描述符

HID描述符是HID类特有的描述符,保证设备正确识别,遵循规定的格式。

偏移量

大小/字节

说明

0

bLength

1

该描述符的长度(0x09字节)

1

bDescriptorType

1

描述符类型(0x21HID描述符)

2

bcdHID

2

HID规范版本

4

bCountryCode

1

国家代码

5

bNumDescriptors

1

支持的描述符个数

6

bDescriptorType

1

支持的描述符类别0x22报表

7

wItemLength

2

支持的描述符长度

3.2、报告描述符

报告描述符比较复杂,它是以item形式排列组合而成,无固定长度。

为了准确描述来自一个控制管道的数据,一个报告描述符必须包括以下内容:

偏移量

大小/字节

说明

0

USAGE_PAGE

2

2

USAGE

2

4

COLLECTION

2

6

USAGEID

2

8

LOGICAL_MINIMUM

2

10

LOGICAL_MAXIMUM

3

13

REPORT_SIZE

2

15

REPORT_COUNT

2

17

INPUT/OUTPUT

2

…上述重复

XX

END_COLLECTION

3.3、[物理描述符]

该描述符不是必须的。

4、STM32USBHID

在STM32上实现USBHID的功能,首先芯片选择要选则带有USB接口的系列。

正确搭建硬件环境,添加使用官方USB库。

4.1、USB库简介

详细正确内容请参看《深入解析STM32_USB-FS-Device_Lib库V0.2》以下仅个人整理。

包含官方库文件,及自己封装的一些函数。

 

1、hw_config

其他工程摘的USB配置(IO、中断等)函数,也可自行实现在其他文件中。

2、usb_core.c

这个c文件是个庞大的文件,主要是定义了usb2.0的标注协议处理函数。

3、usb_desc.c

描述符相关

4、usb_endp.c

这个文件很简单,就是定义了结果几个端点输入输出函数。

5、usb_init.c

这个文件是主要是初始化。

6、usb_int.c

一看就知道跟中断相关。

在该文件中定义了两个函数,分别为低优先级的端点正确传输中断服务程序CTR_LP()和高优先级端点正确传输的中断服务程序CTR_HP()。

7、usb_io.c

自己封装USB操作函数,初始化、发送数据等。

8、usb_istr.c

这个c文件,主要是注册一些端点响应函数,如上面的端点输入输出回电函数,还有就是ISTR中断状态状态寄存器的中断处理。

9、usb_mem.c

从文件名就能知道跟内存有关,这个文件主要定义了两个函数,一个读双缓冲区PMA的数据PMAToUserBufferCopy(),另一个是写数据到双缓冲区PMA,UserToPMABufferCopy。

如果,当你的usb设备接收到了数据,当然数据存放在PMA中了,我们要读出数据就要用到PMAToUserBufferCopy()函数了,如果我们想要发送数据给usb主机,就要将你要发送的数据拷贝到PMA缓冲区中了,这样才能发送出去,原理跟串口类似。

10、usb_prop.c

usb_prop.c文件可以说是一个蛮重要的文件,因为USB的许多处理函数都在这里定义。

在无论是在USB的建立阶段、数据阶段还是状态阶段的一些处理都在这个文件,USB标准函数请求的函数也在这个文件里。

11、usb_pwr.c

这个文件看文件名就知道跟功耗有关了,有很多的状态:

上电、掉电、挂起、恢复。

12、usb_regs.c

13、usb_sil.c

这个文件主要是简单接口层的初始化,和端点的读写操作函数。

总共有3个函数:

USB_SIL_Init();USB_SIL_Write();USB_SIL_Read()。

14、platform_config.h

其他工程摘的USB上拉IO定义。

4.2、USBHID设备自定义

在各种STM32学习板自带的演示例程中,都有几个USB的例程。

如果我们想实现一个USB功能,可以拿里面的例子来改。

那么具体要改哪些地方呢?

首先要改各种描述符,然后是具体的数据处理。

1、更改设备描述符

描述符在文件usb_desc.c中。

设备描述符的结构都标准的,长度也是固定的。

更改如下:

constuint8_tDeviceDescriptor[SIZ_DEVICE_DESC]=

{

0x12,/*bLength*/

USB_DEVICE_DESCRIPTOR_TYPE,/*bDescriptorType*/

0x00,/*bcdUSB*/

0x02,

0x00,/*bDeviceClass*/

0x00,/*bDeviceSubClass*/

0x00,/*bDeviceProtocol*/

0x40,/*bMaxPacketSize40*/

0x83,/*idVendor(0x0483)*/

0x04,

0x50,/*idProduct=0x5750*/

0x57,

0x00,/*bcdDevicerel.2.00*/

0x02,

0x01,/*Indexofstringdescriptordescribingmanufacturer*/

0x02,/*Indexofstringdescriptordescribingproduct*/

0x03,/*Indexofstringdescriptordescribingthedeviceserialnumber*/

0x01/*bNumConfigurations*/

};

2、更改配置描述符集合

配置描述符集合包括配置描述符、接口描述符、类特殊描述符(这里是HID描述符)、以及端点描述符。

constuint8_tConfigDescriptor[SIZ_CONFIG_DESC]=

{

/*配置描述符*/

0x09,/*bLength:

ConfiguationDescriptorsize*/

USB_CONFIGURATION_DESCRIPTOR_TYPE,/*bConfigurationType*/

CUSTOMHID_SIZ_CONFIG_DESC,/*wTotalLength:

Bytesreturned*/

0x00,

0x01,/*bNumInterfaces:

1interface*/

0x01,/*bConfigurationValue:

Configurationvalue*/

0x00,/*iConfiguration*/

0xC0,/*bmAttributes:

Buspowered*/

0x96,/*MaxPower0x96*2=300mA*/

/*接口描述符*/

0x09,/*bLength:

InterfaceDescriptorsize*/

USB_INTERFACE_DESCRIPTOR_TYPE,/*bInterfaceType*/

0x00,/*bInterfaceNumber:

NumberofInterface*/

0x00,/*bAlternateSetting:

Alternatesetting*/

0x02,/*bNumEndpoints*/

0x03,/*bInterfaceClass:

HID*/

0x00,/*bInterfaceSubClass:

1=BOOT,0=noboot*/

0x00,/*nInterfaceProtocol:

0=none*/

0,/*iInterface:

Indexofstringdescriptor*/

/*HID描述符*/

0x09,/*bLength:

HIDDescriptorsize*/

HID_DESCRIPTOR_TYPE,/*bDescriptorType:

HID*/

0x10,/*bcdHID:

HIDClassSpecreleasenumber*/

0x01,

0x00,/*bCountryCode:

Hardwaretargetcountry*/

0x01,/*bNumDescriptors:

NumberofHIDclassdescriptorstofollow*/

0x22,/*bDescriptorType*/

CUSTOMHID_SIZ_REPORT_DESC,/*wItemLength:

TotallengthofReportdescriptor*/

0x00,

/*端点描述符*/

0x07,/*bLength:

EndpointDescriptorsize*/

USB_ENDPOINT_DESCRIPTOR_TYPE,/*bDescriptorType:

*/

0x82,/*bEndpointAddress:

EndpointAddress(IN)*/

//bit3...0:

theendpointnumber

//bit6...4:

reserved

//bit7:

0(OUT),1(IN)

0x03,/*bmAttributes:

Interruptendpoint*/

0x40,/*wMaxPacketSize:

64Bytesmax*/

0x00,

0x02,/*bInterval:

PollingInterval(2ms)*/

0x07,/*bLength:

EndpointDescriptorsize*/

USB_ENDPOINT_DESCRIPTOR_TYPE,/*bDescriptorType:

*/

0x01,/*bEndpointAddress:

*/

/*EndpointAddress(OUT)*/

0x03,/*bmAttributes:

Interruptendpoint*/

0x40,/*wMaxPacketSize:

64Bytesmax*/

0x00,

0x02,/*bInterval:

PollingInterval(2ms)*/

};

3、更改字符串描述符

字符串描述符主要是设备的显示名称等。

constuint8_tStringLangID[SIZ_STRING_LANGID]=

{

CUSTOMHID_SIZ_STRING_LANGID,

USB_STRING_DESCRIPTOR_TYPE,

0x09,

0x04

};/*LangID=0x0409:

U.S.English*/

constuint8_tStringVendor[SIZ_STRING_VENDOR]=

{

CUSTOMHID_SIZ_STRING_VENDOR,/*SizeofVendorstring*/

USB_STRING_DESCRIPTOR_TYPE,/*bDescriptorType*/

'M',0,'y',0,'U',0,'S',0,'B',0,'_',0,'H',0,'I',0,'D',0

};

constuint8_tStringProduct[SIZ_STRING_PRODUCT]=

{

CUSTOMHID_SIZ_STRING_PRODUCT,/*bLength*/

USB_STRING_DESCRIPTOR_TYPE,/*bDescriptorType*/

'C',0,'S',0,'C',0,'',0,'R',0,'e',0,'a',0,'d',0,'e',0,'r',0,'',0

};

uint8_tStringSerial[CUSTOMHID_SIZ_STRING_SERIAL]=

{

CUSTOMHID_SIZ_STRING_SERIAL,/*bLength*/

USB_STRING_DESCRIPTOR_TYPE,/*bDescriptorType*/

'x',0,'x',0,'x',0,'x',0,'x',0,'x',0,'x',0

};

4、更改报告描述符

报告描述符比较复杂,这里就不详述了

constuint8_tReportDescriptor[SIZ_REPORT_DESC]=

{

//

0x05,0x8c,/*USAGE_PAGE(STPage)*/

0x09,0x01,/*USAGE(DemoKit)*/

0xa1,0x01,/*COLLECTION(Application)*/

//TheInputreport

0x09,0x03,//USAGEID-Vendordefined

0x15,0x00,//LOGICAL_MINIMUM(0)

0x26,0x00,0xFF,//LOGICAL_MAXIMUM(255)

0x75,0x08,//REPORT_SIZE(8bit)

0x95,0x40,//REPORT_COUNT(64Byte)

0x81,0x02,//INPUT(Data,Var,Abs)

//TheOutputreport

0x09,0x04,//USAGEID-Vendordefined

0x15,0x00,//LOGICAL_MINIMUM(0)

0x26,0x00,0xFF,//LOGICAL_MAXIMUM(255)

0x75,0x08,//REPORT_SIZE(8bit)

0x95,0x40,//REPORT_COUNT(64Byte)

0x91,0x02,//OUTPUT(Data,Var,Abs)

0xc0/*END_COLLECTION*/

};

5、更改端口初始化

对应描述符中的端口设置对端口初始化。

在usb_prop.c文件中,找到voidCustomHID_Reset(void)函数,该函数是负责初始化端点的。

/*InitializeEndpoint1*/

SetEPType(ENDP1,EP_INTERRUPT);

SetEPRxAddr(ENDP1,ENDP1_RXADDR);

SetEPRxCount(ENDP1,REPORT_COUNT);

SetEPRxStatus(ENDP1,EP_RX_VALID);

/*InitializeEndpoint2*/

SetEPType(ENDP2,EP_INTERRUPT);

SetEPTxAddr(ENDP2,ENDP2_TXADDR);

SetEPTxCount(ENDP2,REPORT_COUNT);

SetEPTxStatus(ENDP2,EP_TX_NAK);

设置端点1接收,端点2发送。

6、更改数据接收函数

在usb_conf.h中找到#defineEP1_OUT_CallbackNOP_Process一行,将它屏蔽。

在usb_endp.c中增加voidEP1_OUT_Callback(void)回调函数

voidEP1_OUT_Callback(void)

{

u16count_tmp;

count_tmp=GetEPRxCount(ENDP1);//获取接收到数据长度

PMAToUserBufferCopy(USB_Receive_Buffer+USB_Receive_DataLen,ENDP1_RXADDR,count_tmp);//拷贝出数据

SetEPRxValid(ENDP1);//完成拷贝后置有效状态,从而EP1发送ACK主机可以进行下一个数据包的发送

…//自行处理

}

7、实现数据发送函数

发送过程就是,UserToPMABufferCopy拷贝要发送的数据至缓冲区,SetEPTxCount设置发送大小,SetEPTxValid启动发送,GetEPTxStatus等待发送完成。

封装发送数据的函数,方便使用。

voidUSB_IO_SendData()

{

USB_Send_Frame=0;

if(USB_Send_DataLen>64)

{

while(USB_Send_DataLen>=64)

{

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 生物学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1