STM32 And Custom USB HID Device? Yes Please!

Update (Feb 2018): As this post seems to be quite popular, I decided to write a new post for STM32 USB beginners with example code/project where we port CubeMX generated USB HID mouse to USB HID keyboard.

Update 2 (Feb 2018): Here is another post about making STM32 USB CDC device.

I (Domen) finaly managed to set up USB HID device on STM32L1 Discovery board. It is not a simple HID Keyboard. It is a composite USB HID device consisting: keyboard, system power controls, consumer device controls (multimedia buttons), application launcher/handler buttons and gamepad.

Pattern mode

Image 1 of 9

Setup menu for pattern mode, selecting 1 - 5 slots and delay time.

Base code and initialization was generated using CubeMX code generation tool and afterwards modified to suit all “hid usages” as mentioned before. We can send keys, control audio/video player, launch apps (and more) with four available buttons. Imagine the possibilities with multiple buttons, each sending custom report.
Currently, there is a setup menu managed with LCD, rotary encoder and setup button, supporting:

  • shortcut mode: CTRL + ALT + DEL, (send in one command)
  • pattern mode: WIN KEY, 1, CTRL, A,  DELETE (sending each key separate, with specified delay).

A Really Quick Guide

This is USB HID device with one configuration descriptor, one interface description and one endpoint (besides EP0). All reports are merged in single report descriptor separated with ReportID() attributes. Currently STM CubeMX doesn’t support multiple interface descriptors and it is definitely not easy to implement new endpoint. But, for simple tasks like implementing a keyboard, mouse or other simple hid devices, base code is satisfactory. To make your own USB HID device:

  • Generate USB HID DEVICE with CubeMX (not CUSTOM USB HID DEVICE).
    • VID, PID.
      You are kind of screwed here. There are some cheap options, but for anything serious, you have a costly bussiness with  How to get a VID/PID. 
  • You need to edit these files to implement your custom report descriptor:
    • “usbd_hid.c”
      • Edit: USBD_HID_CfgDesc[…] to implement specific device.
        0x00, /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
        0x00, /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/ 
        Here is where your custom report descriptor should be.
    • “usbd_hid.c”
  • Change endpint IN size according to your report size: HID_EPIN_SIZE 
  • “main.c”
    • Include “usbd_hid.h”
    • Set up report arrays according to the report descriptor in “usbd_hid.c”
    • Send reports using: USBD_HID_SendReport(&hUsbDeviceFS, …, …);

I know, this “guide” is quite useless for complete beginners. It is hard to start programming USB without at least basic knowledge, so here is a couple of things you can read in advance. You should really know at least something about general USB structure, configuration, interface, device class and report descriptors, USB HID transfer protocol (bulk, interrupt, …), …