Arduino UNO Big Joystick HID firmware
I've extended the joystick firmware to present a much larger joystick to the host PC. The new firmware has:



- 8 analog axis supporting values from -32768 to 32767.
- 40 buttons
This should be handy for building large control systems like the flight controls for a flight simulator, Firefly console, Viper console, or other large control system.
Background
A little background for anyone new to creating USB devices with the Arduino UNO or MEGA2560.
The USB interface on the UNO and MEGA2560 boards is implemented in a small AVR. For R1 and R2 boards that AVR is an Atmega8U2, and for R3 boards it is an Atmega16U2. These chips are programmed with firmware that presents a USB Serial interface to the host PC, and they connect to the Arduino's main Atmega MCU via its TTL Serial port (digital pins 0 and 1).
The 8U2 and 16U2 can be reprogrammed using DFU (Device Firmware Upgrade mode). This means that the USB Serial firmware can be replaced with other USB firmware to turn the Arduino all sorts of USB devices, like a mouse, a keyboard, a joystick, or a MIDI device.
More info on DFU mode:
Big Joystick Firmware
Serial Report Format
| Byte | Type | Description |
|---|---|---|
| 0,1 | int16_t | Analog Axis 0 (X) value. -32768 to 32787 |
| 2,3 | int16_t | Analog Axis 1 (Y) value. -32768 to 32787 |
| 4,5 | int16_t | Analog Axis 2 value. -32768 to 32787 |
| 6,7 | int16_t | Analog Axis 3 value. -32768 to 32787 |
| 8,9 | int16_t | Analog Axis 4 value. -32768 to 32787 |
| 10,11 | int16_t | Analog Axis 5 value. -32768 to 32787 |
| 12,13 | int16_t | Analog Axis 6 value. -32768 to 32787 |
| 14,15 | int16_t | Analog Axis 7 value. -32768 to 32787 |
| 16 | uint8_t | Buttons 0-7. Bit 0 = button 0, bit 7 = button 7 |
| 17 | uint8_t | Buttons 8-15. Bit 0 = button 8, bit 7 = button 15 |
| 18 | uint8_t | Buttons 16-23. Bit 0 = button 16, bit 7 = button 23 |
| 19 | uint8_t | Buttons 24-31. Bit 0 = button 24, bit 7 = button 31 |
| 20 | uint8_t | Buttons 32-39. Bit 0 = button 32, bit 7 = button 40 |
This table describes the format of the 21 byte report that the Arduino sends to the 8U2/16U2. This allows the Arduino to emulate a large joystick, sending axis positions and the value of 40 buttons to the Host PC.
HID Descriptor
This is the HID descriptor for the joystick. You can learn more about them from the USB HID Usage Tables.
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x04, /* Usage (Joystick) */
0xa1, 0x01, /* Collection (Application) */
0x09, 0x01, /* Usage (Pointer) */
/* 8 axes, signed 16 bit resolution, range -32768 to 32767 (16 bytes) */
0xa1, 0x00, /* Collection (Physical) */
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x30, /* Usage (X) */
0x09, 0x31, /* Usage (Y) */
0x09, 0x32, /* Usage (Analog1) */
0x09, 0x33, /* Usage (Analog2) */
0x09, 0x34, /* Usage (Analog3) */
0x09, 0x35, /* Usage (Analog4) */
0x09, 0x36, /* Usage (Analog5) */
0x09, 0x37, /* Usage (Analog6) */
0x16, 0x00, 0x80, /* Logical Minimum (-32768) */
0x26, 0xff, 0x7f, /* Logical Maximum (32767) */
0x75, 16, /* Report Size (16) */
0x95, 8, /* Report Count (8) */
0x81, 0x82, /* Input (Data, Variable, Absolute, Volatile) */
0xc0, /* End Collection */
/* 40 buttons, value 0=off, 1=on (5 bytes) */
0x05, 0x09, /* Usage Page (Button) */
0x19, 1, /* Usage Minimum (Button 1) */
0x29, 40, /* Usage Maximum (Button 40) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 1, /* Report Size (1) */
0x95, 40, /* Report Count (40) */
0x81, 0x02, /* Input (Data, Variable, Absolute) */
0xc0 /* End Collection */
Example Sketch
Here's a sketch demonstrating how to send joystick data to the host.
/* Arduino USB Joystick HID demo */
/* Author: Darran Hunt
* Released into the public domain.
*/
#define NUM_BUTTONS 40
#define NUM_AXES 8 // 8 axes, X, Y, Z, etc
typedef struct joyReport_t {
int16_t axis[NUM_AXES];
uint8_t button[(NUM_BUTTONS+7)/8]; // 8 buttons per byte
} joyReport_t;
joyReport_t joyReport;
void setup()
{
Serial.begin(115200);
delay(200);
for (uint8_t ind=0; ind<8; ind++) {
joyReport.axis[ind] = ind*1000;
}
for (uint8_t ind=0; ind<sizeof(joyReport.button); ind++) {
joyReport.button[ind] = 0;
}
}
// Send an HID report to the USB interface
void sendJoyReport(struct joyReport_t *report)
{
Serial.write((uint8_t *)report, sizeof(joyReport_t));
}
// turn a button on
void setButton(joyReport_t *joy, uint8_t button)
{
uint8_t index = button/8;
uint8_t bit = button - 8*index;
joy->button[index] |= 1 << bit;
}
// turn a button off
void clearButton(joyReport_t *joy, uint8_t button)
{
uint8_t index = button/8;
uint8_t bit = button - 8*index;
joy->button[index] &= ~(1 << bit);
}
uint8_t button=0; // current button
bool press = true; // turn buttons on?/* Turn each button on in sequence 1 - 40, then off 1 - 40
* add values to each axis each loop
*/
void loop()
{
// Turn on a different button each time
if (press) {
setButton(&joyReport, button);
} else {
clearButton(&joyReport, button);
}
/* Move all of the axes */ for (uint8_t ind=0; ind<8; ind++) { joyReport.axis[ind] += 10 * (ind+1); } sendJoyReport(&joyReport); button++; if (button >= 40) { button = 0; press = !press; } delay(100); }
Upload the sketch to the Arduino first, then flash Arduino-big-joystick.hex to the 8U2/16U2. Unplug the Arduino and plug it back in, and will look like a joystick to the host and the host will receive the joystick updates from the sketch.
If you want to upload another sketch, flash Arduino-usbserial.hex to the 8U2/16U2 first, unplug the Arduino and plug it back in. You can now upload the sketch.
Downloads
Demo sketch, joystick firmware, usbserial firmware.



Here's a python test application for checking that your Arduino joystick is behaving correctly. It requires pygame and ocempgui.

Source code is available on Github. See my earlier blog posts for directions on how to build the firmware.
Loading the firmware
For the Atmega8u2 (UNO R1, R2, MEGA2560 R1, R2):
- Put the UNO into DFU mode.
- dfu-prgrammer at90usb82 erase
- dfu-programmer at90usb82 flash --debug 1 Arduino-big-joystick.hex
- dfu-programmer at90usb82 reset
- Unplug the UNO's USB cable for a few seconds and plug it back in
For the ATMEGA16U2 (UNO R3, MEGA2560 R3)
- Put the UNO into DFU mode.
- dfu-prgrammer atmega16u2 erase
- dfu-programmer atmega16u2 flash --debug 1 Arduino-big-joystick.hex
- dfu-programmer atmega16u2 reset
- Unplug the UNO's USB cable for a few seconds and plug it back in
Use the same steps to to load Arduino-usbserial.hex when you want to restore the normal functionality to your UNO (e.g. to load a new sketch).
Note: You will need version 0.5.5 of dfu-programmer to program the ATMEGA16U2. Get the latest version here.
















I purchased a USB Host shield from 












