User Tools

Site Tools


Sidebar

Go Back

Refresh

You are not allowed to add pages

Direct Link

library:stm32:usb_hid

STM32 USB HID

1. 前言

2. USB描述符

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

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

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

3. USB HID

  • 为了把一个设备识别为HID类别,设备在定义描述符的时候必须遵守HID规范。
  • 除了USB标准定义的一些描述符外,HID设备还必须定义HID描述符。
  • 设备和主机的通信是通过报告的形式来实现的,所以还必须定义报告描述符;
  • 物理描述符不是必需的
  • HID描述符是关联于接口(而不是端点)的,所以设备不需要为每个端点都提供一个HID描述符。

3.1 HID描述符

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

3.2 报告描述符

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

3.3 物理描述符

该描述符不是必须的

4. STM32实现USB HID

4.1、USB库简介 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.1 描述符

4.1.1 设备描述符

4.1.2 配置描述符集合

  0x09, /* bLength: Configuation Descriptor size */  
  USB_CONFIGURATION_DESCRIPTOR_TYPE,  /* bConfigurationType */ 
  CUSTOMHID_SIZ_CONFIG_DESC, /* wTotalLength: Bytes returned */ 
  0x00,  
  0x01,        /* bNumInterfaces: 1 interface */  
  0x01,        /* bConfigurationValue: Configuration value */ 
  0x00,      /* iConfiguration */  
  0xC0,          /* bmAttributes: Bus powered */ 
  0x96,          /* MaxPower 0x96*2=300 mA */ 
  /*接口描述符*/  
  0x09, /* bLength: Interface Descriptor size */  
  USB_INTERFACE_DESCRIPTOR_TYPE,  /* bInterfaceType */  
  0x00,          /* bInterfaceNumber: Number of Interface */ 
  0x00,          /* bAlternateSetting: Alternate setting */ 
  0x02,          /* bNumEndpoints */  
  0x03,          /* bInterfaceClass: HID */  
  0x00,          /* bInterfaceSubClass : 1=BOOT, 0=no boot */ 
  0x00,          /* nInterfaceProtocol : 0=none */  
  0,             /* iInterface: Index of string descriptor */ 
  /*HID描述符*/  
  0x09, /* bLength: HID Descriptor size */  
  HID_DESCRIPTOR_TYPE,  /* 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 */ 
  CUSTOMHID_SIZ_REPORT_DESC,/* wItemLength: Total length of Report descriptor */  
  0x00,  
  /*端点描述符*/  
  0x07, /* bLength: Endpoint Descriptor size */  
  USB_ENDPOINT_DESCRIPTOR_TYPE,  /* bDescriptorType: */ 

  0x82,          /* bEndpointAddress: Endpoint Address (IN) */                
                 // bit 3...0 : the endpoint number 
                 // bit 6...4 : reserved  
                 // bit 7     : 0(OUT), 1(IN)  
  0x03,          /* bmAttributes: Interrupt endpoint */ 
  0x40,          /* wMaxPacketSize: 64 Bytes max */ 
  0x00,  
  0x02,          /* bInterval: Polling Interval (2 ms) */ 
    
  0x07, /* bLength: Endpoint Descriptor size */  
  USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */ 

  0x01, /* bEndpointAddress: */  
  /* Endpoint Address (OUT) */  
  0x03, /* bmAttributes: Interrupt endpoint */ 
  0x40, /* wMaxPacketSize: 64 Bytes max  */ 
  0x00,  
  0x02, /* bInterval: Polling Interval (2 ms) */ 

4.1.3 字符串描述符

4.1.4 报告描述符

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,0x40, // REPORT_COUNT (64Byte)  
0x81,0x02, // INPUT (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,0x40, // REPORT_COUNT (64Byte)  
0x91,0x02, // OUTPUT (Data,Var,Abs)   

0xc0 /* END_COLLECTION */  

4.1.5 端口初始化

/* Initialize Endpoint 1 */ 
SetEPType(ENDP1, EP_INTERRUPT); 
SetEPRxAddr(ENDP1, ENDP1_RXADDR); 
SetEPRxCount(ENDP1, REPORT_COUNT); 
SetEPRxStatus(ENDP1, EP_RX_VALID); 

/* Initialize Endpoint 2 */  
SetEPType(ENDP2, EP_INTERRUPT); 
SetEPTxAddr(ENDP2, ENDP2_TXADDR); 
SetEPTxCount(ENDP2, REPORT_COUNT); 
SetEPTxStatus(ENDP2, EP_TX_NAK); 
…  

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

4.1.6 数据接收函数

void EP1_OUT_Callback(void)  
{  
  u16 count_tmp; 
 
  count_tmp = GetEPRxCount(ENDP1);  //获取接收到数据长度  
  PMAToUserBufferCopy(USB_Receive_Buffer+USB_Receive_DataLen, 
  ENDP1_RXADDR,count_tmp);//拷贝出数据  
  SetEPRxValid(ENDP1);//完成拷贝后置有效状态,从而EP1发送ACK主

机可以进行下一个数据包的发送 自行处理

}  

4.1.7 数据发送函数

void USB_IO_SendData()  
{  
  USB_Send_Frame = 0; 
 

  if(USB_Send_DataLen>64) 
  {  
    while(USB_Send_DataLen>=64) 
    {  
      USB_Send_DataLen = USB_Send_DataLen - 64;  
      UserToPMABufferCopy((USB_Send_Buffer+(USB_Send_Frame<<6)), ENDP2_TXADDR, 64);  
      USB_Send_Frame ++;  
      SetEPTxCount(ENDP2, 64); 
      SetEPTxValid(ENDP2);  
      while(GetEPTxStatus(ENDP2)!=EP_TX_NAK);// 
    } 
    
    if(USB_Send_DataLen>0) 
    {  
      memset(sendtemp,0,64);  
      memcpy(sendtemp,(USB_Send_Buffer+(USB_Send_Frame<<6)),USB_Send_DataLen);  
      UserToPMABufferCopy(sendtemp, ENDP2_TXADDR, 64); 
      USB_Send_Frame ++;  
      SetEPTxCount(ENDP2, 64); 
      SetEPTxValid(ENDP2); 
      USB_Send_DataLen=0; 
    } 
  } 
  else 
  {  
    if(USB_Send_DataLen==64) 
    {  
      UserToPMABufferCopy(USB_Send_Buffer, ENDP2_TXADDR, 64); 
      SetEPTxCount(ENDP2, 64); 
      USB_Send_DataLen = 0; 
      USB_Send_Flag = 1; 
      SetEPTxValid(ENDP2); 
    }  
    else if(USB_Send_DataLen>0) 
    {  
      memset(sendtemp,0,64);  
      memcpy(sendtemp,(USB_Send_Buffer+(USB_Send_Frame<<6)),USB_Send_DataLen);  
  
      UserToPMABufferCopy(sendtemp, ENDP2_TXADDR, 64); 
      SetEPTxCount(ENDP2, 64);  
      USB_Send_DataLen = 0; 
      SetEPTxValid(ENDP2);  
    }  
  }  
}  
library/stm32/usb_hid.txt · Last modified: 2022/05/02 00:32 (external edit)