This is a work in progress. Trying to make a working arcade button to USB interface with the Nucleo F411RE.

Dependencies:   USBDevice mbed

This project was inspired by USB Joystick Device

The goal of this project is to build an simple interface that I will connect numerous Arcade buttons and joysticks to the Nucleo board, and the Nucleo will present itself as a USB Gamepad to Windows or Linux. The joysticks are Arcade joysticks that have four switches, up/down/left/right. It is not an analog joystick, just a set of switches. These will be connected to the Nucleo's pins configured as inputs.

The code will then continuously loop and test which buttons are closed, and transfer this data to the host via USBGamepad protocol.

Much thanks to Wim Huiskamp for his original project, documentation, and later reaching out to me to guide me to solving a last minute problem. Wim clued me into the fact that I needed a 1k5 pullup resistor between the 3v3 pin and the PA_12/D+ pin. Once I did this Windows detected the device as a Gamepad and registered it correctly! Yay!

Connecting USB cable to the board is as follows:

You will need a USB data cable (the one I used had a micro usb on one end and regular usb on the other). I cut off the micro USB end, and cut the insulation back about 30mm. This exposed four wires, Red, Black, White and Green. You will then either crimp some header connectors or solder directly to the Nucleo header pins as follows:

  • Green USB D+ to PA_12
  • White USB D- to PA_11
  • Red USB 5V to E5V (with jumper JP5 set to E5V)
  • Black USB GND to GND

As an extra debugging measure, you can connect both the ST/Link USB and the PA_12/11 USB to the Windows machine to run both at the same time, and you can see printf messages from within ST/Link.

We can verify the HID Vendor and Product IDs by looking at the Device Manager, and look for the HID Game Controller:


I used to register my own Vendor_ID and Product_ID

If you go to the USB Game Controller control panel widget, you will see the new entry for Arcade Gamepad:


And here we can see all 32 buttons:


On the Nucleo board you may have difficulties depending on the revision. The board I am using is an STM32F411RE Revision C03, which has resistors and solder joints (bottom) to allow the use of the Crystal on the STLink board for USB purposes. After programming via STLink, remove the USB cable from the STLink, the jumper must be set to E5V to power the board from the PC's usb port. Plug the new cable into the PC.

When you're ready to install it in the arcade cabinet, or project, just remember to setup the jumper JP5 to E5V and you only need the single USB connection to the host.

Here are some useful links that I used to grasp all the little things involved in this project:



File content as of revision 6:29a04fe27b5e:

#define TARGET_STM32F4XX
#define NUM_OF_BUTTONS 32
#define SYSTEM_CLOCK_HZ                 96000000  // 96MHz 

// Joystick button input pin assignments.  
// You can wire up to 32 GPIO ports to buttons (equipped with 
// momentary switches).  Connect each switch between the desired 
// GPIO port and ground (J9 pin 12 or 14).  When the button is pressed, 
// we'll tell the host PC that the corresponding joystick button is 
// pressed.  We debounce the keystrokes in software, so you can simply 
// wire directly to pushbuttons with no additional external hardware.
// Note that we assign 24 buttons by default, even though the USB
// joystick interface can handle up to 32 buttons.  VP itself only
// allows mapping of up to 24 buttons in the preferences dialog 
// (although it can recognize 32 buttons internally).  If you want 
// more buttons, you can reassign pins that are assigned by default
// as LedWiz outputs.  To reassign a pin, find the pin you wish to
// reassign in the LedWizPortMap array below, and change the pin name 
// there to NC (for Not Connected).  You can then change one of the
// "NC" entries below to the reallocated pin name.  The limit is 32
// buttons total.
// (If you're using TLC5940 chips to control outputs, many of the
// GPIO pins that are mapped to LedWiz outputs in the default
// mapping can be reassigned as keys, since the TLC5940 outputs
// take over for the GPIO pins.  The exceptions are the pins that
// are reassigned to control the TLC5940 chips.)
// Note: PTD1 (pin J2-12) should NOT be assigned as a button input,
// as this pin is physically connected on the KL25Z to the on-board
// indicator LED's blue segment.

PinName buttonMap[] = {
    PA_3,      // button 1
    PA_2,      // button 2
    PA_10,     // button 3
    PB_3,      // button 4
    PB_5,      // button 5
    PB_4,      // button 6
    PB_10,     // button 7
    PA_8,      // button 8
    PA_9,      // button 9
    PC_7,      // button 10
    PB_6,      // button 11
    PA_7,      // button 12
    PA_6,      // button 13
    PA_5,      // button 14
    PB_9,      // button 15
    PB_8,      // button 16
    PC_9,      // button 17
    PB_4,      // button 18
    PB_13,     // button 19
    PB_14,     // button 20
    PB_15,     // button 21
    PB_1,      // button 22
    PB_2,      // button 23
    PC_5,      // button 24
    PC_6,      // button 25
    PC_8,      // button 26
    PH_1,      // button 27
    PH_0,      // button 28
    PC_15,     // button 29
    PC_14,     // button 30
    PC_13,     // button 31
    PB_7       // button 32

// STANDARD ID SETTINGS.  These provide full, transparent LedWiz compatibility.
const uint16_t USB_VENDOR_ID = 0x1209;      
const uint16_t USB_PRODUCT_ID = 0xACDE;     
const uint16_t USB_PRODUCT_VER = 0x0001;