Arduino UNO Keyboard HID Part 1

I received my Arduino UNO from Sparkfun on Thursday, and I've been blown away by how easy it is to use. I've created Keyboard HID firmware for the UNO's atmega8u2 so I thought I'd document how to do that here. The same approach should work for other device types, e.g. mouse, joystick, etc.

The first step was getting everything needed to build the standard Arduino USB Serial firmware. I'm running on OSX, so the initial setup is specific to that OS.

Set up an AVR build environment

  • Install avr-binutils. I've got macports installed so this is as simple as running the command "sudo port install avr-binutils". You can install macports from The MacPorts Project.
  • Build and install avr-gcc. For this I downloaded gcc-4.5.2 from gcc.gnu.org. To build gcc you'll need to have XCode installed (from developer.apple.com). Do the following to build avr-gcc:
    • sudo port install gmp
    • sudo port install mpfr
    • sudo port install libmpc
    • export PATH=/opt/local/bin:/opt/local/sbin:$PATH
    • tar xjf gcc-4.5.2.tar.bz2
    • cd gcc-4.5.2
    • mkdir build
    • cd build
    • CFLAGS="-g -O2 -I/opt/local/include" LDFLAGS="-L/opt/local/lib" ../configure --prefix=/opt/local --target=avr --with-gcc --with-gnu-as --enable-languages=c,c++ --disable-nls --disable-libssp --with-dwarf2
    • make
    • sudo make install
    • cd ../..
  • Build and install avr-libc.
    • Download the latest avr-libc source from the AVR-Libc Project, e.g. avr-libc-1.7.1.tar.bz2
    • tar xjf avr-libc-1.7.1.tar.bz2
    • cd avr-libc-1.7.1
    • mkdir build
    • cd build
    • CFLAGS=-Os ../configure --prefix=/opt/local --build=`../config.guess` --host=avr
    • make
    • sudo make install
    • cd ../..

Get the Arduino and LUFA source

The Arduino source has the firmware source code for the UNO's atmega8u2 processor. Its based on the LUFA USB library project which provides source code for AVR USB drivers.
  • If you don't have git installed, use macports to install it now: "sudo port install git".
  • Get a copy of the Arduino source code:
    • git clone git://github.com/arduino/Arduino.git
  • Download a copy of LUFA 100807, unzip it and copy the LUFA subdirectory to the Arduino source tree:

Build and install dfu-programmer

The atmega8u2 is provided with DFU boot code that lets you load new firmware to it via USB. The dfu-programmer application lets you update the firmware in the atmega8u2 when its put into DFU mode.
  • Install libusb-compat: sudo port install libusb-compat
  • Download the latest dfu-programmer package from Sourceforge (e.g. 0.5.4) and do the following:
    • tar xzf dfu-programmer-0.5.4.tar.gz
    • cd dfu-programmer-0.5.4
    • ./configure
    • make
    • sudo make install
    • cd ..

Do a test build of Arduino-usbserial

The Arduino-usbserial firmware is the default firmware that the UNO comes installed with on its atmega8u2. It implements a serial interface over USB. Build this firmware to check that your avr-gcc toolchain and avr-libc are working.
  • cd Arduino/hardware/arduino/firmwares/arduino-usbserial
  • edit the makefile and make sure that MCU = atmega8u2 and ARDUINO_PID = 0x0001
  • make
  • You should have an newly built Arduino-usbserial.hex file.
Next time: Flashing Arduino-usbserial.hex to your UNO, and how to make your own Keyboard HID USB firmware.


Comments

mtinker (unauthenticated)
Apr 12, 2011

Darran,
Thanks for you work. I am having a little trouble compiling avr-gcc and was wondering if you could help. I'm also on a mac. Followed the steps, but got the following error when trying to make gcc:

checking for avr-gcc... /Users/mtinker/gcc-4.5.2/build/./gcc/xgcc -B/Users/mtinker/gcc-4.5.2/build/./gcc/ -B/opt/local/avr/bin/ -B/opt/local/avr/lib/ -isystem /opt/local/avr/include -isystem /opt/local/avr/sys-include
checking for suffix of object files... configure: error: in `/Users/mtinker/gcc-4.5.2/build/avr/libgcc':
configure: error: cannot compute suffix of object files: cannot compile
See `config.log' for more details.
make[1]: *** [configure-target-libgcc] Error 1
make: *** [all] Error 2

Got any ideas to what could be wrong?
Thanks,

mtinker (unauthenticated)
Apr 12, 2011

Never mind, must have done something wrong. went through it all again, and it seemed to work.

darran
Apr 12, 2011

Good to hear that the toolchain is working for you. Are you planning to develop a USB driver?

mtinker (unauthenticated)
Apr 13, 2011

Mostly just playing around. I'm building a footswitch to advance sheet music displayed on a computer. I found your project and thought it would be perfect. The midi application looks very attractive too.

mtinker (unauthenticated)
Apr 13, 2011

One thing I caught when installing the dfu programmer. libusb-compat must be installed
"sudo port install libusb-compat"

darran
Apr 13, 2011

I've updated the directions to include libusb-compat - thanks!

filoteo (unauthenticated)
Apr 17, 2011

Darran/mtinker Im experiencing the same problem you did, however going through it all again aint working.

checking for avr-gcc... /Users/filoteo/gcc-4.6.0/build/./gcc/xgcc -B/Users/filoteo/gcc-4.6.0/build/./gcc/ -B/opt/local/avr/bin/ -B/opt/local/avr/lib/ -isystem /opt/local/avr/include -isystem /opt/local/avr/sys-include
checking for suffix of object files... configure: error: in `/Users/filoteo/gcc-4.6.0/build/avr/libgcc':
configure: error: cannot compute suffix of object files: cannot compile
See `config.log' for more details.
make[1]: *** [configure-target-libgcc] Error 1
make: *** [all] Error 2

A look at config.log and searching for error gives....

configure:3028: /Users/filoteo/gcc-4.6.0/build/./gcc/xgcc -B/Users/filoteo/gcc-4.6.0/build/./gcc/ -B/opt/local/avr/bin/ -B/opt/local/avr/lib/ -isystem /opt/local/avr/include -isystem /opt/local/avr/sys-include -V >&5
xgcc: error: unrecognized option '-V'
xgcc: fatal error: no input files

and another one..

xgcc: error: unrecognized option '-qversion'
xgcc: fatal error: no input files
compilation terminated.
configure:3039: $? = 1
configure:3055: /Users/filoteo/gcc-4.6.0/build/./gcc/xgcc -B/Users/filoteo/gcc-4.6.0/build/./gcc/ -B/opt/local/avr/bin/ -B/opt/local/avr/lib/ -isystem /opt/local/avr/include -isystem /opt/local/avr/sys-include -o conftest -g -O2 -I/opt/local/include conftest.c >&5
conftest.c:1:0: internal compiler error: in dwarf2out_frame_init, at dwarf2out.c:4260

Darran (unauthenticated)
Apr 20, 2011

Hi Filoteo. I haven't had that error before. Can you send me your config.log file? Darran [at] hunt [dot] net [dot] nz

Jay (unauthenticated)
Jun 12, 2011

i don't get it.. are you an apple user??.. will this also work in windows??.. please help.. I'm new in arduino... :(

darran
Jun 21, 2011

Hi Jay,

I use apple, linux, netbsd, and occasionally windows. For development I prefer the first 3 operating systems. The initial part of this blog post is about setting up the OS X environment to be able to build firmware for the atmega8u2 so you can make your own USB firmware.

On windows you can use a tool called flip from atmel to load the hex file onto your Uno's atmega8u2. You can download it from atmel here: http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3886. There's a helpful guide here: http://andrewmemory.wordpress.com/2011/04/14/upgrading-the-arduino-uno-8u2-using-flip/.

Cheers,
Darran.

matt (unauthenticated)
Jun 30, 2011

Was there a resolution for filoteo's compile error. I'm seeing the same error. Thanks!

matt (unauthenticated)
Jul 10, 2011

Thanks, Darran! These instructions are a great help. I ran through on a fresh machine and I have a couple of minor corrections that will hopefully be helpful to some.

Before building gcc, run:
sudo port install avr-binutils

The command to install git is:
sudo port install git-core

Thanks again,
Matt

Ben (unauthenticated)
Aug 11, 2011

Newbie here,
I am looking to make a composite keyboard/mouse HID device and have seen that there is a demo in LUFA but I have not been able to successfully load it after I have compiled it.
Is there a learning resource you can point me to? I would follow your lead directly on the compiling however I am running a windows system.

darran
Aug 23, 2011

Hi Ben,

sorry for the slow response, I've been on holiday. Since you're using windows you probably want to use flip rather than dfu-programmer. You can download it here: http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3886.

Advancer (unauthenticated)
Oct 14, 2011

Hi I keep getting the following when trying to make the avrlibc

In file included from ../../../../../common/macros.inc:39:0,
from ../../../../../crt1/gcrt1.S:38:
../../../../../include/avr/io.h:428:6: warning: #warning "device type not defined"
../../../../../crt1/gcrt1.S: Assembler messages:
../../../../../crt1/gcrt1.S:53: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:54: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:55: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:56: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:57: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:58: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:59: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:60: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:61: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:62: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:63: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:64: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:65: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:66: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:67: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:68: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:69: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:70: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:71: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:72: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:73: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:74: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:75: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:76: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:77: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:78: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:79: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:80: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:81: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:82: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:83: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:84: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:85: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:86: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:87: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:88: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:89: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:90: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:91: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:92: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:93: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:94: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:95: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:96: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:97: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:98: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:99: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:100: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:101: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:102: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:103: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:104: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:105: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:106: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:107: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:108: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:109: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:110: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:111: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:112: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:113: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:114: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:115: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:116: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:117: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:118: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:119: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:120: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:121: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:122: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:123: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:124: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:125: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:126: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:127: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:128: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:129: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:130: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:131: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:132: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:133: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:134: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:135: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:136: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:137: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:138: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:139: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:140: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:141: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:142: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:143: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:144: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:145: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:146: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:147: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:148: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:149: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:150: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:151: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:152: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:153: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:154: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:155: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:156: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:157: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:158: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:159: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:160: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:161: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:162: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:163: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:164: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:165: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:166: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:167: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:168: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:169: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:170: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:171: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:172: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:173: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:174: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:175: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:176: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:177: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:178: Error: non-constant expression in ".if" statement
../../../../../crt1/gcrt1.S:179: Error: non-constant expression in ".if" statement
make[5]: *** [gcrt1.o] Error 1
make[4]: *** [all-recursive] Error 1
make[3]: *** [all-recursive] Error 1
make[2]: *** [all-recursive] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

Any ideas on what went wrong? I'm new to the MAC side of things so this is mostly greek to me.

Advancer (unauthenticated)
Oct 14, 2011

I installed the latest gcc and went through the same steps and it worked this time... weird...

rut216 (unauthenticated)
Dec 28, 2011

I tried compiling gcc-4.6.2 on OSX Lion 10.7.2 with XCode 4.1 and ran into the same error as a few others:

...
configure: error: cannot compute suffix of object files: cannot compile
See `config.log' for more details.
make[1]: *** [configure-target-libgcc] Error 1
make: *** [all] Error 2

This appears to be caused by a bug in llvm-gcc-4.2. Check http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49919 for more info. To get around it just add "CC=gcc-4.2 CXX=g++-4.2" or "CC=clang CXX=clang++" to your ./configure args.

Cheers

rut216 (unauthenticated)
Dec 28, 2011

Try https://github.com/larsimmisch/homebrew-alt for a painless gcc env installation.

Jonathan (unauthenticated)
Jun 7, 2012

Thanks. I have windows and use the program above.
(http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3886)

rich (unauthenticated)
Jul 22, 2012

I have just gone through the process listed above and for the most part it worked fine. I did get a little stuck building Arduino-usbserial. It turns out that, quoting from http://old.nabble.com/VUSB-problem-td32560584.html, "Any data that are placed into progmem are required to be declared `const' now."

not doing so led to this sort of error.

Descriptors.c:57:33: error: variable 'DeviceDescriptor' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

It was fixed by declaring these as const so line 57 changed from

USB_Descriptor_Device_t PROGMEM DeviceDescriptor =

to

const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =

rince and repeat for the other PROGMEM declarations (I think there were 5).

After that it all compiled without a hitch.

fer (ferslash@gmail.com) (unauthenticated)
Apr 11, 2013

dear Darran:

I would love to use your info to construct the pedals of a driving sim, i would like to use the analog axis of your program to apply them to a "clutch, brake and trottle" pedals, the question is, how do i connect the potentiometers to the arduino, to wich pins??? i hope you can help me.

best regards

Fernando mtz

(unauthenticated)
Apr 21, 2013

hi fer,

you can connect potentiometers to any of the analog input pins on the arduino.

Leo (frem.alexander@gmail.com) (unauthenticated)
Jun 2, 2013

Hey there, I am working on a school project, and I am trying to follow these instructions; however, I am stuck on:
Build and install dfu-programmer
>make

In there, I get the following error:
make all-recursive
Making all in src
gcc -DHAVE_CONFIG_H -I. -I.. -Wall -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c
main.c:27:20: error: libusb.h: No such file or directory
main.c:42: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘*’ token
main.c: In function ‘main’:
main.c:58: warning: implicit declaration of function ‘libusb_init’
main.c:58: error: ‘usbcontext’ undeclared (first use in this function)
main.c:58: error: (Each undeclared identifier is reported only once
main.c:58: error: for each function it appears in.)
main.c:79: warning: implicit declaration of function ‘libusb_set_debug’
main.c:108: warning: implicit declaration of function ‘libusb_release_interface’
main.c:126: warning: implicit declaration of function ‘libusb_close’
main.c:136: warning: implicit declaration of function ‘libusb_exit’
make[2]: *** [main.o] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2

I am unsure on how to proceed, any help will be greatly appreciated. Thanks..

darran
Jun 19, 2013

Leo, it looks like libusb is not installed. Did you do the "sudo port install libusb-compat" step?

Chris (unauthenticated)
Oct 27, 2014

Guys, the HID USage Tables have been updated. The new link is http://www.usb.org/developers/hidpage/Hut1_12v2.pdf