AVRHID: USB HID for the Atmega32u4 (Arduino)

Copyright (C) 2017 Laszlo Menczel (laszlo.menczel@gmail.com)

DISCAIMER: AVRHID is provided free of charge with NO WARRANTY. You use it at your own risk. Licensing terms are stated at the beginning of each source file.

Last modified: 11/03/2017

Table of Contents


This program implements USB HID devices (mouse, keyboard and joystick). The target is the Atmega32u4 MCU used in the Arduino Leonardo and Micro boards. At present the following devices are implemented:

  keyboard with 101 keys including 8 modifier keys

  mouse with three buttons and a wheel
  joystick with 16 buttons, X and Y axis, throttle and rudder controls
  and an 8-position HAT switch

The code is supposed to be compiled by the avr-gcc compiler suite. There is a Makefile for building the program from the command line. I have tested the build process only under Linux (Xubuntu 64-bit 16.04). In principle it should work under other operating systems as well provided that the avr-gcc toolchain is installed.

This program is for serious developers who prefer the traditional way of making software and don't want to use the simplistic Arduino IDE made for beginners. A nice tutorial by Ashley Mills about the use of C/C++ (avr-gcc) for AVR programming can be found at the following WEB site:



I have put together this package because I noticed that it is quite difficult to find simple and easy to understand C code that would implement the HID devices keyboard, mouse and joystick on Atmega MCUs. Good quality joystick implementations are especially rare. You can find a lot of code on the WEB for implementing a USB joystick but most of it is IMHO garbage. These are usually perfunctorily stiched together packages using code from several different sources and contain lots of unneeded code that makes the whole stuff difficult to understand. In most cases documentation is non-existent or very sketchy. And some of these packages simply don't work at all (cannot be compiled or run).

HID devices are implemented in the Arduino and Teensyduino IDEs but if you want to do traditional programmming by using the avr-gcc you are out of luck. People on forums suggest to use the LUFA library. Well, it does work but IMHO it is far from being simple (concerning either code or usage) regardless of claims to the contrary made on different forums.


Keyboard and mouse code are based on the following two code packages from the PJRC.COM company:

Keyboard example for the Teensy USB Development Board
Mouse example with debug channel for Teensy USB Development Board

HID report descriptor examples for joysticks were taken from code I have downloaded from the following site:


I got two files (HID.cpp and USBAPI.h) to which joystick code was added by Peter Barrett and extracted the joystick descriptor to use in my HID code.

Device configuration

You can configure the program for different boards and HID devices.

Board type
At present two Arduino boards are supported: Leonardo and Micro. Set BOARD_TYPE in the Makefile to the desired value by uncommenting the appropriate statement. Configuring the board type will automatically set the product ID of the HID device to the correct value.

HID device type
You may specify one of the HID types HID_MOUSE, HID_KEYBOARD or HID_JOYSTICK by uncommenting the appropriate statement in the Makefile. Please note that only one type may be defined. Consequently any compiled instance of the program supports exactly one HID type depending on the setting of this value. Composite USB devices (e.g. mouse + keyboard) cannot be handled by this program.

Adding code for new joystick types

If you need a custom joystick with a different number of buttons, controls and axis you have to modify two source files: hid_joy.c and hid_joy.h.

In hid_joy.c you should edit the HID report descriptor structure to correspond to the number of controls (buttons, axis, etc.) you want to implement. You should also modify the function copy_report_to_buf so that it correctly copies the actual values from joy_state to the hardware USB buffer of the MCU.

In hid_joy.h you should set the constant HID_REPORT_SIZE to the new size of the structure you edited in hid_joy.c. The joy_state_t structure must also be modified so that it corresponds to your new setup.

You should also revise the test program dev_joy.c for possible code changes.


1. Similar modifications should be made to the hid_kbd or hid_mou source files if you want to implement a different keyboard or mouse device.

2. The maximum size of report that can be copied to the hardware buffer (i.e. the number of bytes sent, NOT the size of the HID report descriptor) is 8 bytes for a keyboard or a mouse and 64 bytes for a joystick. Please do not exceed these limits!

Building the program

You must have the avr-gcc package installed on your computer. You should get it from the software repository of your distribution.

In a terminal navigate to the directory where the Makefile of the program is located and run the command make. If everything is OK the program is created in the subdirectory build. The name of the program will be usb_keyboard.hex, usb_mouse.hex or usb_joystick.hex depending on your device setting.

Three other make targets are available:

  make clean --> removes all files created by the build process except the
                 dependency files

  make xclean -> removes all files created by the build process

  make blink --> builds the minimal LED blinking program 'blink'

blink.hex can be used to reset the board to its factory state (i.e. loaded with a a blink sketch and USB connection activated).

Burning the program to the board

Connect your board to an USB port. Open a terminal and navigate to the directory where the Makefile is located. Start the burning script:

  ./burnhex image-name
where image-name is the name of the HEX file created by the build process (in the subdirectory build) w/o the .hex extension.

After the script starts you have to press the reset button of the board and then immediately press ENTER (these instructions are displayed on the screen).

You can start your burned program by disconnecting the board and connecting it again.


1. You have to specify in the burnhex script the serial port to which the board connects when it is reset. Currently it is set to /dev/ttyACM0. You can find the name of the port in the following way:

  - Connect the board to an USB port

  - In a terminal run tail -f /var/log/syslog

  - Press the reset button on the board

  - tail will display a couple of new lines about a new USB device

  - In the text printed by tail find the name of the port used 
    (mine was /dev/ttyACM0 but it may be different on your machine)

  - Edit the file burnhex to set the variable port to this value

2. You should have python and python-serial installed because the burnhex script uses the python script reset_board.py to set up the board for programming (see the content of the script if you want to know what is done).

3. The subdirectory bin contains the avrdude programmer utility and its configuration file. That's all you need to burn a HEX image. This is a 64-bit Linux program (from Ubuntu). If you run a 32-bit Linux you have to get the 32-bit version of avrdude. Then you can either replace the file avrdude in bin or modify the variables conf and burn in the burnhex script to point to the newly installed program and config files.


1. Try building the program under Windows 7/8 using winavr (the main hurdle here will be finding out which COM port the board uses when it is reset for programming)

2. Extend the set of boards usable with the program. This could include the Teensy2 and Teensy3 as well as Arduino boards that have an MCU with built-in USB support similar to the Atmega32u4.