Electronic – converting STM32F4 discovery USB mouse example to gamepad

hidmouseusb

I own a stm32f4 discovery board, for which a demonstration project can be downloaded here:
http://www.st.com/web/en/catalog/tools/PF257904

This demo consists of software to use the board as a usb hid mouse, using the accelerometer to control the mouse movement. I want to change this into a gamepad, for now I'm leaving the other parts of the descriptor the same, so I only changed the usage from 0x09,0x02 (usage: mouse) to 0x09 , 0x09 (usage: gamepad). (these values can be found in the usb_hid_core file)

But after this change the computer still sees it as a mouse, but one that is not functioning correctly. What else should I change?

Any help would be greatly appreciated, I have been trying all kinds of things for weeks now, but nothing seems to work.

the usb_hid_core file can be found in this file at this location:

stsw-stm32068\STM32F4-Discovery_FW_V1.1.0\Libraries\STM32_USB_Device_Library\Class\hid\src

(i was under the impression that all that i would have to change would be this line in the descriptor to make it look as a gamepad, since the data that is send will still comply with the descriptor then, i also tried changing it to a very simply device that sends just one byte before changing it into a a gamepad, and i tried changing various other things like hid class). This is how it shows up after i change it to a gamepad (but is doens't work then): http://hmsprojects.com/USB-invoerapparaat.html

Best Answer

You need to change few others things to make it work as a gamepad. In usbd_hid_core.c you need to change :

 0x02,         //nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse

to the 0x00 value.

Other thing, the report descriptor has to be changed, this is mine for a 3-buttons 2-axis gamepad, (you can change it to add button or anything else with the HIDtool) :

__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
  0x05,   0x01, // USAGE_PAGE (Generic Desktop)
  0x09,   0x05, // USAGE (Game Pad)
  0xA1,   0x01, // COLLECTION (Application)

  0xA1,   0x00, // COLLECTION (Physical)
  0x05,   0x09, // USAGE_PAGE (Button)
  0x19,   0x01, // USAGE_MINIMUM (Button 1)
  0x29,   0x03, // USAGE_MAXIMUM (Button 3)

  0x15,   0x00, // LOGICAL_MINIMUM (0)
  0x25,   0x01, // LOGICAL_MAXIMUM (1)
  0x95,   0x03, // REPORT_COUNT (3)
  0x75,   0x01, // REPORT_SIZE (1)

  0x81,   0x02, // INPUT (Data,Var,Abs)
  0x95,   0x01, // REPORT_COUNT (1)
  0x75,   0x05, // REPORT_SIZE (5)
  0x81,   0x07, // INPUT (Cnst,Var,Rel)

  0x05,   0x01, // USAGE_PAGE (Generic Desktop)
  0x09,   0x30, // USAGE (X)
  0x09,   0x31, // USAGE (Y)

  0x15,   0x81, // LOGICAL_MINIMUM (-127)
  0x25,   0x7F, // LOGICAL_MAXIMUM (127)
  0x75,   0x08, // REPORT_SIZE (8)
  0x95,   0x02, // REPORT_COUNT (2)

  0x81,   0x02, // INPUT (Data,Var,Abs)
  0xC0,   0xC0  // END_COLLECTION x2
}; 

The size of the report descriptor has changed so modify it in usbd_hid_core.c :

#define HID_MOUSE_REPORT_DESC_SIZE    48

Now the gamepad would be recognized. You only need to send a 3 bytes report (the first for the button, et the two others for the axis). For a test you could do it by using this code in stm32xx_it.c :

static uint8_t *USBD_HID_GetPos (void)
{
static uint8_t HID_Buffer[3] = {0};

static int8_t val_abs_x=0;
static uint8_t sens_x=0;

HID_Buffer[1] = 0;
HID_Buffer[2] = 0;

// X move
if (val_abs_x > 120)
{
    sens_x = 0; // --
    HID_Buffer[0]=0;
}
else if (val_abs_x < -120)
{
    sens_x = 1; // ++
    HID_Buffer[0]=1;
}

if (sens_x == 1)
    val_abs_x = val_abs_x + 3;
else
    val_abs_x = val_abs_x - 3;

HID_Buffer[1] = val_abs_x;
HID_Buffer[2] = 0;

return HID_Buffer;
}

Anf finally change the line (in the same file) :

  USBD_HID_SendReport (&USB_OTG_dev, buf, 4);

to :

  USBD_HID_SendReport (&USB_OTG_dev, buf, 3);

This should work well on the STM32f4 discovery board. If not try change the PID by adding 1 (like 0x5711) in usbd_desc.c).