STM32 Xbox Controller

Written 8-27-19

Continuing my exploration of USB HID, I decided to try my hand at making a controller. I started with implementing a game pad’s HID descriptor and then firing up joy.cpl to test everything. To my delight, the two joysticks and 16 buttons all showed up. With the coding portion looking promising, I proceeded to make the actual controller.


First, I needed to make a CAD model of the remote. As with any mini project, I wanted to use only parts I already had on hand. The joysticks would be these tiny PSP replacement parts that I got about 8 years ago and would finally find a use for. The buttons would be leftover tactile switches from Mission Possible. Both the STM32 Blue Pill board and the joysticks served as the main restrictions determining the form factor and size of the controller. To determine the size of the D-pad and ABXY button spacing, I took measurements off of my DSi.

stm32xbox cad

Funnily enough, I didn’t take any pictures of me assembling the electronics. The gist of the wiring that went into the controller was gluing the buttons down and soldering wires to every button. After that I sealed everything up with a couple of screws.

stm32xbox assembled


With the hardware done, it was time to finalize the software. I just took my test code from before and remapped all the GPIO that I used. Using joy.cpl, I made sure all the buttons and joysticks were working properly.

Trying to play Rainbow Six Siege with my new controller, I ran into my first problem. The game would not pick up my controller. I tried Battlefield 4 and had the same issue. Googling it, I found out that the problem was the fact that my controller communicated with the DirectInput API instead of XInput. It turns out that these games I was trying to play didn’t support DirectInput.

Doing research on implementing an XInput controller on STM32, I stumbled across nesvera’s STM32-X360-xinput repository. His code did literally everything I needed my controller to do and implemented XInput perfectly, so I decided to use it. I did have to download Keil uVision to open the project, but after changing all the GPIO mappings to match my controller, I was set.

Using Game Controller Tester, I was delighted to see that everything was finally working. I could finally play R6S and BF4 using a controller. Since I’m a PC gamer, I immediately switched back to my trusty mouse and keyboard.

Android Gamepad

Inspired by all the Android gamepad controllers out there, I decided to make my own. I have a Galaxy S4, so I started with making a custom USB OTG cable to connect the microUSB from the GS4 to the microUSB of my controller. After making sure the controller was recognized on the GS4, I proceeded to design a mount.

stm32xbox gs4 cad

If I remember correctly, Retroarch has native support for the Xbox 360 controller, but games like Modern Combat 5 don’t so I used Tincore Keymapper to help with that.

All in all, this was a really fun and cute little project. I’m not much of a console player, so I’ve pretty much used this controller exclusively for retro gaming.


Matt Written by:


  1. Tanner H
    November 2, 2021

    Hi, I’ve successfully implemented the XInput code in my current project but we are encountering a problem. When the host computer is “shut down” the computer will not complete the shutdown cycle until the device is either unplugged or disconnected. Any thoughts or similar problems on your end?

    • November 2, 2021

      I don’t think I’ve ever had that problem but I’d guess that it could be a driver issue or maybe some USB setting in Device Manager.

  2. Piu
    May 24, 2021

    Were you able to properly configure the trigger buttons? I can’t get them to work, they’re always at the middle trigger point, so they go off (or don’t even activate when pressed) randomly.


      • May 26, 2021

        I see! I don’t want to use analog triggers either. I’m setting it up for an arcade controller to use on my X360. If it isn’t much of a hassle, could you tell me which values you’ve used? I’ll change the GPIO pins to ones that aren’t analogs and tinker around in the meantime, thanks for the reply!

        • May 29, 2021

          Yeah for sure the old code maps the ADC value to the range of a uint8_t, which means for a button you either send a 0 or 255 instead. My code did a HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_11)?0:255 instead of the whole map() thing.

  3. Erick Blanco
    April 24, 2021

    Ok I undestand the GPIO part, but never used Keil how I can import this project and upload to my board?

    • April 24, 2021

      Keil costs money but iirc this project is small enough to fit in their free tier. You just need to make an account and download it. The import and compile process should be pretty straightforward once you have the IDE. For flashing the binaries, there’s many ways but I’d say the simplest is using STM32CubeProgrammer.

      • May 29, 2021

        Took a second look the code isn’t really Keil specific since the base was generated using STM32CubeMX. Shouldn’t take too much work to transfer it over to a free IDE like STM32CubeIDE

  4. Erick Valentin Blanco Puerto
    April 23, 2021

    Do you have a tutorial of this project? I like do my own controller using an stm32 and implementing xinput.

    • April 24, 2021

      I don’t have time for a full tutorial but the main thing is once you have your buttons and joysticks attached to your stm32, you can use this guy’s code and modify Src/stm32_xinput/stm32_xinput.c to suit your needs. Good luck!

Leave a Reply