on 2025-04-17 6:30 AM
This guide helps you migrate an STM32 application from a USB HID mouse to a USB HID keyboard using the STM32 legacy library. Below are the steps to achieve this.
You can start by obtaining the project from the mouse device project using classic middleware. The direct link to GitHub for the project is: https://github.com/stm32-hotspot/CKB-STM32-HID-KEYBOARD-C0
Here are the steps:
Modify the USBD_HID_CfgDesc in usbd_hid.c to configure it for a keyboard.
Add a macro conditional definition to handle both mouse and keyboard configurations:
__ALIGN_BEGIN static uint8_t USBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_HID_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
#if (USBD_SELF_POWERED == 1U)
0xE0, /* bmAttributes: Bus Powered according to user configuration */
#else
0xA0, /* bmAttributes: Bus Powered according to user configuration */
#endif /* USBD_SELF_POWERED */
USBD_MAX_POWER, /* MaxPower (mA) */
/************** Descriptor of Joystick Mouse interface ****************/
/* 09 */
0x09, /* bLength: Interface Descriptor size */
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x01, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID */
0x01, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
#ifdef keyboard
0x01, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#elif mouse
0x02, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#endif
0, /* iInterface: Index of string descriptor */
/******************** Descriptor of Joystick Mouse HID ********************/
/* 18 */
0x09, /* bLength: HID Descriptor size */
HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID */
0x11, /* bcdHID: HID Class Spec release number */
0x01,
0x00, /* bCountryCode: Hardware target country */
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
0x22, /* bDescriptorType */
#ifdef keyboard
HID_KEYBOARD_REPORT_DESC_SIZE, /* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
#elif mouse
HID_MOUSE_REPORT_DESC_SIZE, /* wItemLength: Total length of Report descriptor */
#endif
0x00,
/******************** Descriptor of Mouse endpoint ********************/
/* 27 */
0x07, /* bLength: Endpoint Descriptor size */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType:*/
HID_EPIN_ADDR, /* bEndpointAddress: Endpoint Address (IN) */
0x03, /* bmAttributes: Interrupt endpoint */
HID_EPIN_SIZE, /* wMaxPacketSize: 4 Bytes max */
0x00,
HID_FS_BINTERVAL, /* bInterval: Polling Interval */
/* 34 */
};
#endif
Add the following definitions in usbd_hid.h:
#define HID_MOUSE_REPORT_DESC_SIZE 74U
#define HID_KEYBOARD_REPORT_DESC_SIZE 63U
To complete the implementation of a USB HID keyboard device starting from a USB HID mouse application, follow these steps to update the user application code:
Add the following code in your user application to define the necessary structures and variables for the keyboard:
#ifdef keyboard
extern USBD_HandleTypeDef hUsbDeviceFS;
typedef struct
{
uint8_t MODIFIER;
uint8_t RESERVED;
uint8_t KEYCODE1;
uint8_t KEYCODE2;
uint8_t KEYCODE3;
uint8_t KEYCODE4;
uint8_t KEYCODE5;
uint8_t KEYCODE6;
} keyboardHID;
keyboardHID keyboardhid = {0, 0, 0, 0, 0, 0, 0, 0};
extern uint8_t keyboardpressed;
uint8_t hello_sequence[5] = {0x0B, 0x08, 0x0F, 0x0F, 0x12}; // Keycodes for 'H', 'E', 'L', 'L', 'O'
#endif
In usb_device.c, after defining extern PCD_HandleTypeDef hpcd_USB_DRD_FS; add the following code to handle keyboard-specific variables:
#ifdef mouse
uint8_t HID_Buffer[4];
#define CURSOR_STEP 5
#elif keyboard
uint8_t keyboardpressed = 0;
#endif
In the same file, update the EXTI interrupt handler to set the keyboardpressed flag when an interrupt is detected and the device is configured:
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == BUTTON_USER_Pin)
{
if ((((USBD_HandleTypeDef *) hpcd_USB_DRD_FS.pData)->dev_remote_wakeup == 1) &&
(((USBD_HandleTypeDef *) hpcd_USB_DRD_FS.pData)->dev_state ==
USBD_STATE_SUSPENDED))
{
if ((&hpcd_USB_DRD_FS)->Init.low_power_enable)
{
HAL_ResumeTick();
}
/* Activate Remote wakeup */
HAL_PCD_ActivateRemoteWakeup((&hpcd_USB_DRD_FS));
/* Remote wakeup delay */
HAL_Delay(10);
/* Disable Remote wakeup */
HAL_PCD_DeActivateRemoteWakeup((&hpcd_USB_DRD_FS));
/* change state to configured */
((USBD_HandleTypeDef *) hpcd_USB_DRD_FS.pData)->dev_state = USBD_STATE_CONFIGURED;
/* Change remote_wakeup feature to 0 */
((USBD_HandleTypeDef *) hpcd_USB_DRD_FS.pData)->dev_remote_wakeup = 0;
remotewakeupon = 1;
}
else if (((USBD_HandleTypeDef *) hpcd_USB_DRD_FS.pData)->dev_state ==
USBD_STATE_CONFIGURED)
#ifdef mouse
{
GetPointerData(HID_Buffer);
USBD_HID_SendReport(&hUsbDeviceFS, HID_Buffer, 4);
}
#elif keyboard
keyboardpressed=1;
#endif
}
}
In the main loop, add the following code to handle the keyboard input when the keyboardpressed flag is set:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
#ifdef keyboard
if (keyboardpressed == 1)
{
for (int i = 0; i < 5; i++)
{
keyboardhid.MODIFIER = 0x00; // No modifier keys
keyboardhid.KEYCODE1 = 0x4E; // Press 'Page Down' button
keyboardhid.KEYCODE2 = hello_sequence[i]; // Press 'H', 'E', 'L', 'L', 'O'
USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&keyboardhid, sizeof(keyboardhid));
HAL_Delay(500);
}
keyboardpressed = 0;
}
else
{
keyboardhid.MODIFIER = 0x00; // No modifier keys
keyboardhid.KEYCODE1 = 0x00; // Release key
keyboardhid.KEYCODE2 = 0x00; // Release key
USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)&keyboardhid, sizeof(keyboardhid));
HAL_Delay(500);
}
#endif
}
To define the predefined symbol in compiler settings (IAR Workbench is used in our case), follow these steps:
When opening a text editor, notepad for example, then pressing the USER button on the board, you get the following result as shown in the screenshot below:
By following these steps, you will successfully migrate the user application to implement a USB HID keyboard device starting from a USB HID mouse application.