Library 34- STM32F4 as USB HID Device

With USB HID Device library, you can turn STM32F4 to be a keyboard, mouse or gamepad device. It also supports all three settings at the same time. Device is shown to computer as “Keyboard; Mouse; Game controller“. This library allows you to use 2 gamepads at the same time, one keyboard and one mouse.

For mouse you can use left, middle and right buttons, X and Y cursor axes and wheel vertical rotation.

For gamepads, you can implement 16 buttons and 2 joysticks, like on PS2 gamepad device.

Also, if you use keyboard, you have enabled all special keys (SHIFT, CTRL, ALT and GUI), in combination with other keys.

You can of cource make a device, which implement everything listed here in one piece. Your imagination is the limit.



  • Interface STM32F4 with computer as keyboard, mouse or gamepads
  • Supports up to 2 gamepads, 1 keyboard and 1 mouse
  • Keyboard supports all special keys
  • Mouse supports 3 main buttons, cursor movement and wheel vertical rotation
  • Each of 2 gamepads supports up to 16 buttons and 2 joysticks
  • Library works in USB FS or USB HS in FS mode
  • Just plug USB in computer and works. No need for drivers


    • STM32F4xx
    • STM32F4xx RCC
    • STM32F4xx GPIO
    • STM32F4xx EXTI
    • misc.h
  • TM
    • defines.h
  • USB HID Device stack provided by STMicroelectronics (included in library)
Data + PA12 PB15 USB Data+ line
Data – PA11 PB14 USB Data- line
ID PA10 PB12 USB ID pin
VBUS PA9 PB13 USB activate

By default, USB FS mode is used, also used on STM32F4-Discovery board. If you want to enable USB HS in FS mode for STM32F429 Discovery board, open project’s defines.h file and add lines below:

That’s all. You are now ready to work as USB HID device.

Clock was set down to 168MHz for STM32F429 because you can not get 48MHz for USB from 180MHz core clock.


USB HID Device library is configured to support keyboard, mouse and 2 gamepads at the same time. You can send HID report for for mouse and keyboard one by one at the same time. Also, this library allows you to create a device to support 2 gamepads and create a console where you and your friend can play games with one STM32F4 device.

You have to know that when you send a report when some button is pressed, computer will detect button pressed. But after you release the button or everything, you have to also send HID report that you have released button. In one word: You have to send HID report every time each button is changed (pressed or released) or joysticks are moved.

Everywhere with joystick and movement (mouse, gamepad) where you have X and Y axis, you send each time a relative movement. So if you send one time cursor movement, and if you next time send the same value, cursor will be moved for twice length. You always sends relative movement according to position right now. There is no absolute movement for cursor.

Below, you have structure on how reports looks for USB HID report. Everywhere you have buttons, you have to set bit to 1 when button is pressed or 0 when button is released.

Also, keyboard buttons ARE NOT ascii values. To get proper HEX value for pressed key, you should look here.

  1. Keyboard
    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
    Byte 0 Report ID = 0x01
    Byte 1 Right GUI Right ALT Right SHIFT Right CTRL Left GUI Left ALT Left SHIFT Left CTRL
    Byte 2 Padding = Always 0x00
    BYTE 3 Key 1
    BYTE 4 Key 2
    BYTE 5 Key 3
    BYTE 6 Key 4
    BYTE 7 Key 5
    BYTE 8 Key 6
  2. Mouse
    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
    Byte 0 Report ID = 0x02
    Byte 1 Middle button Right button Left button
    Byte 2 Cursor movement X axis
    BYTE 3 Cursor movement Y axis
    BYTE 4 Wheel vertical movement
  3. Gamepad 1
    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
    Byte 0 Report ID = 0x03
    Byte 1 Button 8 Button 7 Button 6 Button 5 Button 4 Button 3 Button 2 Button 1
    Byte 1 Button 16 Button 15 Button 14 Button 13 Button 12 Button 11 Button 10 Button 9
    BYTE 3 Left joystick X axis
    BYTE 4 Left joystick Y axis
    BYTE 5 Right joystick X axis
    BYTE 6 Right joystick Y axis
  4. Gamepad 2
    Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
    Byte 0 Report ID = 0x04
    Byte 1 Button 8 Button 7 Button 6 Button 5 Button 4 Button 3 Button 2 Button 1
    Byte 1 Button 16 Button 15 Button 14 Button 13 Button 12 Button 11 Button 10 Button 9
    BYTE 3 Left joystick X axis
    BYTE 4 Left joystick Y axis
    BYTE 5 Right joystick X axis
    BYTE 6 Right joystick Y axis

Functions and enumerations


This is one simple example. If you press the blue button, then “WIN+R” command will be send to computer. In picture below, new device is found under Devices and Printers section.

USB HID Device result

USB HID Device result


This sketches are made for copy/paste inside project, where you have comments “Simple sketch start” and “Simple sketch end“.

Everything you can test, if you open Control panel and the Devices and printers. If you have properly set values you will see a new device. If you use sketch for gamepad simulation, then make a right click on new device and hit “Game Controller settings“. You will get a new windows when you have 2 devices with same name. First is gamepad 1 and second is gamepad 2. Select one and click “Properties“. You will get a new window, where you can look, which buttons are pressed when you press the button on discovery board.

  1. This sketch is used in main example. If you press the button od Discovery board, it will send command “WIN + R” and when you release the button, it will send command that all buttons are released.
  2. If you press the button on discovery board, then you simulate left mouse key. If you hold button, and move your mouse around, you will see option “Select“.
  3. Each time you press the button, you will write “Tilen” to the some file or somewhere else in your computer.
  4. Next example simulates 2 gamepads. If you press the button, you activate buttons 3, 10 on gamepad 1 and left joystick rotation. Also, if you set window for gamepad 2, you will activate button 5 and 13 with left and right joysticks.

  5. If you press the button, you will move file, or website, or everything used with mouse wheel for 10 units.

Project is available at my Github account, download library below.

TM STM32F4 USB HID Device Library


Owner of this site. Also electronic enthusiasts, web developer, 3D printer fan, handball player and more. Big fan of STM32F4 devices. In anticipation of the new Discovery board for STM32F7 lines.

You may also like...

Read before commenting!

Before you make a new comment, make sure you agree with things listed below:

  • - Read post to make sure if it is already posted what you are asking for,
  • - Make sure you have the latest version of libraries used in your project,
  • - Make a clean and grammatically correct written message,
  • - Report as many details as possible, including what have you done so far,
  • - Do NOT post any code here. Use Pastebin,
  • - Do NOT post any error codes here. Use Pastebin,
  • - Specify STM32Fxxx family and used Discovery/EVAL/Nucleo or custom made board,
  • - Make sure your clock is set correct for PLL,
  • - If you are using my HAL drivers, please check this post how to start.
Comment will be deleted on breaking these rules without notification!
  • LeMoussel


    Very interesting and informative article.

    By default, the send keyboard report (TM_USB_HIDDEVICE_KeyboardSend(…)) use QWERTY format. How can send in AZERTY keyboard format ?

    • Hi.

      Well there is not special in this case. You have to send other characters by yourself.

      • LeMoussel

        Hummmm …. I have a small problem.
        I have a PC with an azerty keyboard.
        On my STM32 board, when I send “a” ( Keyboard.Key1 = 0x04; ) , I got “q” on my PC.

        • Understand you. You have to manually change this.
          So, when you want to send “a”, you have to send “q” to computer, because “q” and “a” are changed in AZERTY vs QWERTY. Understand?

          If you want to send “w” character from QWERTY, you have to send “z” character for AZERTY to get “q”. Understandable?

          • LeMoussel


            So I have to do a translation table AZERTY QWERTY

          • That’s correct.

  • Tesung Mao Fang

    Hi, thanks for your sample code.

    I have one question.
    Why It does not work for dragging an icon on the desktop with a mouse?
    I send the data like below

    (0x02,, 50,0,0)

    Actually, I did the same data (press and then move ) on the mspaint.exe, and I think it work because it will paint a line on the canvas.


    • It works, you just need to make correct combination.

      • Tesung Mao Fang

        Sorry, can you tell me what is the correct combination for dragging an icon on desktop? I though that dragging an icon should like this (left button click and move ) …Maybe I misunderstand to drag icon action?

        • Try this:

          Send reports:
          first: left button clicked:
          second: left button clicked, move X or Y
          third: left button released.

          I’m not sure, must test this, but this lib has nothing to do with actions on computer. You will need to ckeck for HID how to properly send data for your action. My library just send data you tell to it 😀

          • Tesung Mao Fang

            OK! Thanks for your reply. I will try your recommendation.
            Thank you~

  • Tesung Mao Fang

    Sorry, I modified this example code, and found another problem again…
    I have tried to find the bug for two days, but I can’t find the reason.

    I inserted usart3 function “void USART3_IRQHandler()” in this example code.
    and then tried to use the usart interrupt for receiving the mouse data.
    Finally, use “TM_USB_HIDDEVICE_MouseSend(&Mouse)” to transfer mouse data.

    step 1. I will send Mouse.leftbutton click
    step 2. I will send Mouse.leftbutton click and move 50,50
    step 3. I will send Mouse.leftbutton released

    target is complete an action for dragging.

    I showed my code (main.c) to

    Above mention I can work in this example code in while loop (line 57~76).

    But I can not work in my USART3_IRQHandler().

    In first time doing it, I found out that it wouldn’t click left button and just move cursor(50,50). And in the step 3,
    it doesn’t release the leftbutton.

    From the second time, it just only moved the cursor(50,50) but not doing step 1. Actually I’m not sure step 3 had been done.

    I’m sure that usart3 receive the right mouse data when it called the “TM_USB_HIDDEVICE_MouseSend(&Mouse)” function;

    If explanation is not clear, just tell me. Thank you!

  • Onur Akgün

    Hi Majerle,

    Is there any way that STM communicate with PC just like in UART? I want to send data to PC. Can I use this lib?

    Thank you

  • joejs

    Hi Majerle,

    Description files you provided are Input Report, if I want to change how Feature Report to change? I want to work on the PC side ReadFile / WriteFile, can be attached to a paradigm? Thank you

    • HI,

      I’m not sure I correctly understand your question. Please make it more clear.

      • joejs

        I want to design a AP tool on my pc,
        this tool can send data to stm32f4 and receive data from stm32f,
        but you provided sample was Input Report, so the AP can only read data,

        i hope pc and stm32f can communicate each other,

        can you provide examples, (output report, feature report?)

    • joejs

      I want to design a AP tool on my pc,
      this tool can send data to stm32f4 and receive data from stm32f,
      but you provided sample was Input Report, so the AP can only read data,

      i hope pc and stm32f can communicate each other,

      can you provide examples, (output report, feature report?)

  • Amai

    hey, when I try to compile your code (after importing all the needed libs) I get a shitload of errors (full ist here: Why’s that?

    • Shitload?
      I don’t see nothing on your pastebin!

      • Amai

        The bracket ‘)’ broke the link. 😛 Fixed it ^^

        • Well, that “shitload” errors are problems because your programming skill. You have some int8_t variable, but function needs uint8_t! Make a cast or change variable uint8_t.

          Better is that you show your code here 🙂 I mean, use pastebin 😉

          • Amai

            I’ve tested my code and it works perfectly fine, but that’s not the case here as I’m not using my code at all, it’s all purely your code (well, aside from RCC, GPIO, EXTI and MISC, these come from the standard Repository available in the CooCox). Here’s how the code looks like:

          • Amai

            Ah, sorry I didn’t post this earlier, but exams are occupying my mind lately. 😛 I’ve fixed these problems quite easily. There are 2: first one is you need to include some standard libraries (namely gpio, rcc, exti, syscfg and misc) in the usb_bsp.c file. The second problem is with tm_stm32f4_delay.c file, precisely the 225th line irq = __disable_irq(); That function has no return value, so just erase the irq variable there. After that, the code worked perfect. ^^

          • Redownload delay lib please.

  • Thomas Gauthier-Caron

    Will this library work on the STM32F3 Discovery? If not, is it hard to port?

    • It should.
      You have to init low level stuff, so gpio pins and nvic for f3.
      Also, you will have to include standard peripheral drivers for f3.

  • Maurycy Graclik

    Hello Majerle,
    Your website is amazing!
    How do I change detection by the computer, mouse instead of a game controller? I’m trying everyting.

    • Hi,

      computer will always detect “Mouse, keyboard and 2 gamepads” always. How you will act is done by your application which commands will be sent from your side.

      Technically, HID descriptor is used to set what will computer see and what won’t.

      • Maurycy Graclik

        Thank you for such a quick response :). You right, there are 3 devices. So, should I look for solution in descriptors? Changing VID and PID?

        • Not VID nor PID. You have to change descriptor array.

          • Maurycy Graclik

            Yey! thank you! 🙂

  • ddudas


    I have a strange problem with the STM HID implementation. I created a PID device, and after several successful minutes of working the PC issues one of its regular report to the device but it won’t be completed according to USBlyzer. After that the application on PC side hangs but my device can send its reports. Is it possible to have some strange bug in USB stack which stops working the receiver state machine? Or how is it possible that an issued report is not completed by the device?

    • Hello,

      I’ve never tested so hard this, but when I did, i never got errors like this.
      But I believe that this is USB stack problem. I’ve didn’t check that.

      • ddudas

        Thank you for the fast answer, I think I have to instrument the ISR to check if interrupt was called or not (if it is called than it is definetly stack problem). Do you have any idea which HW buffer should I store in an array to compare it with USBlyzer log? Maybe is there a register with the raw URB data?

        • FrancisCO

          Hi! I have the same problem!!!! I am totally stucked!!

          Have you solve it?

          • ddudas

            Hi FrancisCO, it was a few month ago when I had this problem, and the root cause is in ST’s improper error handling implementation in the Cube USB drivers. -> thats why the old firmware package didn’t had this problem, and thats why there are almost no answers on the web.

            So long story short: I’ve just made a quick&dirty workaround instead of correcting the driver 🙂 you can detect in the main loop, when the communication stops with a simple timestamp, and when the error occurs you can simply do what I did. You can try my “solution”:

            if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)) {

            USBD_LL_PrepareReceive(&hUsbDeviceFS, CUSTOM_HID_EPOUT_ADDR , hhid->Report_buf,
            That workaround will be executed when you push the button on the F4 discovery, so you can see if it helps or not. Don’t forget to init the button and maybe you’ll need some includes for USBD_LL_PrepareReceive. If it helps just let me know, I’m quite curious if it helps or not!

          • You are talking aboit hal usb but library is about std libraries!!!

          • ddudas

            Originally I asked you here because I thought you can help in my problem 😀 My original question was about the HAL, I’m not using your library, and from FrancisCO’s question I think nor does he. Sorry for hijacking this topic 😉

  • mahmud istiaq


    It seems you worked pretty good in USB HID. I am working on a joystick of USB. I attached the Physical Interface Device Descriptor. With feature report I am facing problem. That is, while initializing it reads the feature I sent. But when I reinitialize it, it always reads some other report. And the feature report is sent with a default value unless I reset the device. I flushed the Control Endpoint before sending, but it didn’t effect any. Would you please discuss the matter with me? Thank you.

  • Amir

    Good Evening everyone. i want to ask u about how to read gamepad(joystick) and show the value on the display. i’ve tried my program, but it’s just show the value on the displa. But actually it’s doen’t work. The value is 255 and not change even if i pressed or released the gamepad button.. if everyone can help me. thanks a lot.

  • Cullen


    I have a Nucleo STM32-F411RE and compiled and built your library just fine on Keil. I am trying to port it over to either Eclipse or mbed and keep having compilation issues due to redefinement errors between the usb drivers and HAL. I read on your site that you need to update the drivers to hal but im not sure which usb drivers to use with this project. any help would be appreciated. Thanks

    • I’m not sure what USB drivers makes you problems?

      • Cullen

        Sorry I misspoke. It is not a driver but a .c file. The problem is in usb_core.h, which gets called by usb_dcd.h.

        In file included from ../include/usb_dcd.h:33:0,
        from ../include/usbd_core.h:33,
        from ../include/usbd_ioreq.h:35,
        from ../include/usbd_hid_core.h:33,
        from ../include/tm_stm32f4_usb_hid_device.h:124,
        from ../src/main.c:5:
        ../include/usb_core.h:85:3: error: redeclaration of enumerator ‘HC_IDLE’

  • winston1777

    Hi! When installing sketch to your Board stm32f429, I was faced with 2 problems. The first hid gamepad1 when you press the button a few quick times, the device hangs and does not respond. The second problem gamepad2 just do not respond to the touch of a button.

  • winston1777

    Help add multimedia key device. Mute, Volume Up, Volume Down.

  • thang

    Hi,I can use PS3 usb controller with this code?