【STM32】USB HID Mouse

前言

STM32CubeMX的USB HID程式碼是個三鍵滑鼠範例,我們將使用它在STM32F072RBT的公板上執行

然後再用USB HID Descriptor Tool的Mouse描述來覆蓋STM32CubeMX原先的



操作環境

  • Board:32F072BDISCOVERY
  • IDE:STM32CubeIDE
  • Code:STM32CubeMX

1. STM32CubeMX

勾選USB功能

勾選USB Role Device(FS)。有的MCU型號支援HOST/Device/OTG

設定不做修改

勾選USB_DEVICE,選擇Human Interface Device Class(HID)

  • HID_FS_BINTERVAL:主機讀取設備的時間間隔
  • USBD_MAX_NUM_INTERFACE:支援的endpointer數量
  • 這些參數都將存在 usbd_conf.h

Clock Configuration裡,F072的USB時脈使用APB1,改為48Mhz

注意

F072的USB PHY在USB_DP上內建了升壓電阻,所以外部電路無須升壓電位

如果你選用的MCU沒有內建升壓電阻,記得要加上,不然USB插上主機會沒有反應



2. STM32CubeIDE

下列是STM32CubeMX針對HID產生的檔案,

  • usbd_desc.c:USB裝置的列舉,描述
  • usbd_hid.c/.h:HID裝置的描述
  • usbd_conf.h:endpointer技援數量,主機訪問間隔,descriptor size等參數

usbd_hid.c的HID_MOUSE_ReportDesc[]是三鍵的滑鼠descriptor


__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE]  __ALIGN_END =
{
  0x05,   0x01,
  0x09,   0x02,
  0xA1,   0x01,
  0x09,   0x01,

  0xA1,   0x00,
  0x05,   0x09,
  0x19,   0x01,
  0x29,   0x03,

  0x15,   0x00,
  0x25,   0x01,
  0x95,   0x03,
  0x75,   0x01,

  0x81,   0x02,
  0x95,   0x01,
  0x75,   0x05,
  0x81,   0x01,

  0x05,   0x01,
  0x09,   0x30,
  0x09,   0x31,
  0x09,   0x38,

  0x15,   0x81,
  0x25,   0x7F,
  0x75,   0x08,
  0x95,   0x03,

  0x81,   0x06,
  0xC0,   0x09,
  0x3c,   0x05,
  0xff,   0x09,

  0x01,   0x15,
  0x00,   0x25,
  0x01,   0x75,
  0x01,   0x95,

  0x02,   0xb1,
  0x22,   0x75,
  0x06,   0x95,
  0x01,   0xb1,

  0x01,   0xc0
};

上列descriptor可以複製到網站做翻譯,比較好閱讀修改

USB标准请求及描述符在线分析

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x02,        // Usage (Mouse)
0xA1, 0x01,        // Collection (Application)
0x09, 0x01,        //   Usage (Pointer)
0xA1, 0x00,        //   Collection (Physical)
0x05, 0x09,        //     Usage Page (Button)
0x19, 0x01,        //     Usage Minimum (0x01)
0x29, 0x03,        //     Usage Maximum (0x03)
0x15, 0x00,        //     Logical Minimum (0)
0x25, 0x01,        //     Logical Maximum (1)
0x95, 0x03,        //     Report Count (3)
0x75, 0x01,        //     Report Size (1)
0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01,        //     Report Count (1)
0x75, 0x05,        //     Report Size (5)
0x81, 0x01,        //     Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
0x09, 0x30,        //     Usage (X)
0x09, 0x31,        //     Usage (Y)
0x09, 0x38,        //     Usage (Wheel)
0x15, 0x81,        //     Logical Minimum (-127)
0x25, 0x7F,        //     Logical Maximum (127)
0x75, 0x08,        //     Report Size (8)
0x95, 0x03,        //     Report Count (3)
0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              //   End Collection
0x09, 0x3C,        //   Usage (Motion Wakeup)
0x05, 0xFF,        //   Usage Page (Reserved 0xFF)
0x09, 0x01,        //   Usage (0x01)
0x15, 0x00,        //   Logical Minimum (0)
0x25, 0x01,        //   Logical Maximum (1)
0x75, 0x01,        //   Report Size (1)
0x95, 0x02,        //   Report Count (2)
0xB1, 0x22,        //   Feature (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
0x75, 0x06,        //   Report Size (6)
0x95, 0x01,        //   Report Count (1)
0xB1, 0x01,        //   Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0,              // End Collection

// 74 bytes

上述HID descriptor描述了 三個按鈕+XY方向 4個bytes的裝置

  • 第一個byte,bit0為左鍵,bit1為右鍵
  • 第二個byte為X軸(0~127向右,-1~-127向左)
  • 第三個byte為Y軸(0~127向下,-1~-127向)
  • 第四個byte為scroll軸(0~127向上,-1~-127向下)

在main.c加入應用程式,按下User按鍵(PA0)後,鼠標將向執行 右>下>左>上 頁面上>下 按下右鍵


/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usbd_hid.h"
/* USER CODE END Includes */

int main(void)
{
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == 1)
	  {
		  extern USBD_HandleTypeDef hUsbDeviceFS;
		  int8_t data[4] = {0,0,0,0};

		  //X-right
		  data[1] = 127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
		  HAL_Delay(500);

		  //Y-down
		  memset(data, 0, 4);
		  data[2] = 127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
		  HAL_Delay(500);

		  //X-left
		  memset(data, 0, 4);
		  data[1] = -127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
		  HAL_Delay(500);

		  //Y-up
		  memset(data, 0, 4);
		  data[2] = -127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
		  HAL_Delay(500);

		  //scroll-up
		  memset(data, 0, 4);
		  data[3] = 127/2;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
		  HAL_Delay(500);

		  //scroll-up
		  memset(data, 0, 4);
		  data[3] = -127/2;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
		  HAL_Delay(500);

		  //key-right
		  memset(data, 0, 4);
		  data[0] = 2;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
		  HAL_Delay(15);

		  memset(data, 0, 4);
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);

		  //HAL_Delay(200);
	  }
  }
}


3. USB HID Descriptor Tool

這是USB協會提供用來編輯HID描述的工具

執行它並且開啟dt2_4_HID Descriptor Tool\MSDEV\Projects\test\mouse.hid

mouse.hid描述了一個 三鍵+XY 的滑鼠;少了Page Scroll "Usage (Whell)",HID package 3 bytes

把mouse.hid覆蓋usbd_hid.c的HID_MOUSE_ReportDesc[]


    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,                    // USAGE (Mouse)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x05, 0x09,                    //     USAGE_PAGE (Button)
    0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
    0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x95, 0x03,                    //     REPORT_COUNT (3)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x05,                    //     REPORT_SIZE (5)
    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
    0x75, 0x08,                    //     REPORT_SIZE (8)
    0x95, 0x02,                    //     REPORT_COUNT (2)
    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
    0xc0,                          //   END_COLLECTION
    0xc0                           // END_COLLECTION
    // 50 bytes

然後把usbd_hid.h的HID_MOUSE_REPORT_DESC_SIZE 長度改為50

main.c的應用程式,傳輸封包改為3 bytes,取消Page Scroll


  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if(HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == 1)
	  {
		  extern USBD_HandleTypeDef hUsbDeviceFS;
		  int8_t data[4] = {0,0,0,0};

		  //X-right
		  data[1] = 127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
		  HAL_Delay(500);

		  //Y-down
		  memset(data, 0, 4);
		  data[2] = 127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
		  HAL_Delay(500);

		  //X-left
		  memset(data, 0, 4);
		  data[1] = -127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
		  HAL_Delay(500);

		  //Y-up
		  memset(data, 0, 4);
		  data[2] = -127;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
		  HAL_Delay(500);

		  //scroll-up
//		  memset(data, 0, 4);
//		  data[3] = 127/2;
//		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
//		  HAL_Delay(500);

		  //scroll-up
//		  memset(data, 0, 4);
//		  data[3] = -127/2;
//		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 4);
//		  HAL_Delay(500);

		  //key-right
		  memset(data, 0, 4);
		  data[0] = 2;
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);
		  HAL_Delay(15);

		  memset(data, 0, 4);
		  USBD_HID_SendReport(&hUsbDeviceFS,(uint8_t*)&data, 3);

		  //HAL_Delay(200);
	  }
  }


留言

2024

11-27SPI Flash 操作 (Read/Write/Erase)
11-19Rotary Encoder Switch 旋轉編碼開關
11-14Command Line Interface - CLI via UART
11-14【STM32】USB HID - Volume Control
11-13【STM32】USB Custom HID
11-12【STM32】USB HID Keyboard + Mouse
11-12【STM32】USB HID Keyboard
11-12【STM32】USB HID Mouse
10-15SSD1306 128x64 OLED 【五】Wokwi Animator
09-2432F429IDISCOVERY - - LTDC [3] + FMC (SDRAM) + FatFS
09-2432F429IDISCOVERY - - LTDC [2] + FMC (SDRAM)
09-20STM32 + FatFs + SD card via SPI【三】FatFS指令操作II
09-19STM32 + FatFs + SD card via SPI【二】FatFS指令操作
09-18STM32 + FatFs + SD card via SPI【一】移植FatFS
09-0232F429IDISCOVERY - - LTDC [1]
04-17SSD1306 128x64 OLED 【四】Adafruit / GFX Library
04-17Arduino - Serial Plotter繪圖儀
04-16SSD1306 128x64 OLED 【三】
04-15SSD1306 128x64 OLED 【二】 Datasheet
04-12SSD1306 128x64 OLED 【一】I2C版本
03-20【freeRTOS】vTaskDelay 與 vTaskDelayUntil 的差異
03-19【freeRTOS】API功能列表
03-18【freeRTOS】Day1
03-08MBR和Blank project的差別
03-05刪除註冊檔registry的資料
02-27DFU over Bluetooth Low Energy
02-27nRF Util - 使用手冊
02-26nRF Command Line Tools
02-20建立BootLoader settings
02-19Secure DFU packet (ZIP) build 建立含袐鑰的Zip檔
02-19Secure DFU via BLE
02-19Secure DFU via UART
02-16nRF Util 安裝
01-16nRF52840 ic升級成nRF52840 Dongle的程式

2023

11-21[ SEGGER Embedded Studio ] 新增header files
11-21[ SEGGER Embedded Studio ] 編譯nRF52840時遇到的問題
11-07Arduino Nano ESP32 - Debugging除錯模式
11-03Git快速入手 - 使用Git GUI
10-30Git快速入手 - 使用Git Bash
10-12程式碼高亮顯示 -- google-code-prettify

2022

11-30[EZ-PD] CCG6DF CCG6SF的Host SDK遇到編譯錯誤(一)

2019

05-27[ Eagle PCB ] 合板成品
05-23#CASE_001_USB_TOOL_RL78_G12
05-22[ Eagle PCB ] 初次洗板
05-21[ Eagle PCB ] Panelize 併板
05-20[ Eagle PCB ] 建立自己的Library及元件
05-20[ Eagle PCB ] 添加library及元件
05-20[ Eagle PCB ] Introduce

2018

04-25[ TCP test Tool ] 好用的TCP Server/Client工具
01-16RZ/A1H -[0]- Renesas RZ/A1H YR0K77210S009BE BSP環境架設

2017

12-11EZ USB Suit使用JLink online debug FX3
10-20RL78 -[12]- CS+_CACX_Lab5_LowPower mode
10-16RL78 -[11]- CS+_CACX_Lab4_ADC_溫度感測
10-13RL78 -[10]- CS+_CACX_Lab4_ADC_內部參考電壓
10-13RL78 -[9]- CS+_Lab3_I2C + MPU6050
10-13RL78 -[8]- CS+_Lab2_Uart transmit
10-12RL78 -[7]- Renesas Flash Programmer 獨立燒錄軟體
10-12RL78 -[6]- CS+_雜記
10-12RL78 -[5]- CS+_tracking variables on debug mode
10-12RL78 -[4]- CS+_顯示ROM與RAM的使用size
10-12RL78 -[3]- CS+_Lab1_Led blinking
10-12RL78 -[2]- CS+專案建立
10-12RL78 -[1]- 開發環境介紹
10-06ESP-01 -[0]- 硬體設置
10-06LinkIt 7688 program Renesas RL78/G12 by 1-wire
10-06LinkIt Smart 7688 -[3]- Build the firmware from source codes
10-06LinkIt Smart 7688 -[2]- 使用UART進入bootloader / kernel console
10-06LinkIt Smart 7688 -[1]- 使用SSH連接kernel console
10-06LinkIt Smart 7688 -[0]- 初次使用
07-14LinkIt Smart 7688 -[9]- Using MRAA SPI in Python
07-13LinkIt Smart 7688 -[8]- Using MRAA UART in Python
07-12LinkIt Smart 7688 -[7]- Using MRAA I2C in Python
07-12LinkIt Smart 7688 -[6]- Using MRAA PWM in Python
07-12LinkIt Smart 7688 -[5]- Using MRAA GPIO in Python
07-10LinkIt Smart 7688 -[4]- 雜記
06-29輕乳酪蛋糕 Cotton Cheesecake
06-26VirtualBox 的 Ubuntu與Windows 共用資料夾

2015

04-29偵測USB PnP