Make a good PS/2 keyboard to USB adapter from an ATmega32u4 [Adafruit breakout board]
C Makefile
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


 This file is part of ps2_kbd_to_usb_adapter,
 copyright (c) 2014 Nicolas S. Dade

 ps2_kbd_to_usb_adapter, is free software: you can redistribute it
 and/or modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.

 ps2_kbd_to_usb_adapter, is distributed in the hope that it will be
 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with ps2_kbd_to_usb_adapter.  If not, see



This code uses an ATmega32u4 as a PS/2 keyboard to USB keyboard converter, to
allow using a good ole IBM Model M (or Northgate Omnikey Ultra) AT or PS/2
keyboard with modern computers which now (2014) lack any PS/2 ports at all.



To use this, install the AVR toolchain ('apt-get install gcc-avr avrdude avr-libc'),
fetch the LUFA library (
(version 140302 is the one I am using), edit the LUFA_PATH in Makefile to point
to where the LUFA library source as been unpacked, and type 'make'.

If you are using the Adafruit ATmega32u4 breakout board then 'make flash' while
the bootloader is running (red light is pulsing) will program it. Otherwise use
whatever mechanism you usually use and the 'adapter.hex' (or .bin) file.

You should enjoy customizing the USB descriptor as described below.



I wrote this after trying two commercial adapters and finding neither worked
very well. Keys would remain stuck down (or rather, the UP keystroke from PS/2
didn't register).  In this code PS/2 receive is done in hardware using the
ATmega's UART set in a mode which matches what PS/2 uses (externally clocked,
odd-parity, 1 stop-bit). In addition the code asks the keyboard for resends
(0xFE command) when a parity error occurs. The combination of these two
features is what makes this code more reliable than the commercial adapters and
other low level PS/2 libraries I've tried.

I like the low latency of PS/2 (~1 msec for DOWN, ~2 msec for UP). The typical
polling rate of USB keyboards is 10 msec. This was the rate suggested by the
keyboard example in the USB 1.1 HID spec back in 1997 and nearly everyone
copied it verbatim.  The exception is the so-called "gaming" keyboards.  A
polling interval of 10 msec means your keystroke waits inside the keyboard for
up to 10 msec before the computer polls the keyboard and learns the key has
moved.  I can't do anything about the extra latency caused by sending
keystrokes first over PS/2 and then over USB, but I can minimize the USB
latency by upping the polling interval to 2 msec. This faster polling is of no
consequence on modern PCs and USB busses, which all run may times faster than
anything from 1997 could. The fast polling also helps if you enjoy configuring
the keyboard to have rapid repeat rates and short repeat delays, a
configuration combination where prompt and accurate UP events are necessary.
Myself I use 88 chars/sec after a 175 msec delay because I'm not so young

I like using the Adafruit ATmega32u4 breakout board
( because its bootloader (accessed by
pressing the reset button) allows for quick and easy reflashing over USB,
without requiring connecting to the 6-pin ICSP header. But any board with an
ATMega32u4 will do, for example the Teensy 2.0 or even an Arduino Leonardo
should do (you're on your own, though).  Just be sure the XCLK1 signal is
easily available. Some ATmega32u4 boards don't bring it out to a header.
For example the SparkFun Pro Micro board uses the XCLK1 pin (which is also
PD5) to drive an LED.  You can tap into it anyway, but it's more delicate
work than would otherwise be necessary.

The make target 'flash' (as in "make flash") and the configured target in
the makefile are setup for the Adafruit ATmega32u4 breakout board.  Edit
as needed.



In order to use this code you should customize a few things. Specifically in the
USB descriptor you should set your own strings for the manufacturer, device and
serial number of your keyboard.  I like to set these to the exact keyboard I am
building the adaptor into, just for fun. The constants are named
usb_manufacturer_str, usb_product_str and usb_serial_str.

The keyboard and descriptor describe an US English keyboard. With help from
kreijack non-US keyboards should be supported. However all I know is English
and Italian keyboards work. That is because I don't have anything else to test
with. If you want to use this with a different language you should edit the
CountryCode field in the descriptor (google for the USB 1.1 HID spec for the
value you need, or use 0 like most keyboards do), AND you must edit the mapping
from PS/2 scan-code set 3 keycodes to USB keycodes in keycodes.c. The latter
step will be tedious. Tough.  It was for me as well.  :-)  Scan code information
can be found at

If you have measured it you can set the correct power requirement in the
descriptor in the MaxPowerConsumption field.

Do note that PS/2 ports supplied ample power (5V/275mA) and the older the
keyboard the more of that it used. So if you are plugging the adapter into an
unpowered USB hub you might get an error (see dmesg on linux) that the device
requires too much power to operate. In that case you can use a combination of
two things: use a USB port on the PC itself or on a powered hub (the right
thing to do), or in a pinch, hack the value of MaxPowerConsumption to something
the PC will accept. However if you do the latter and don't supply the needed
power the keyboard can become erratic, or the USB port can notice the extra
power draw and shut off, or any sort of undocumented behavior. So never-mind
my mentioning it :-)

  Nicolas S. Dade
  <you can find my email by googling my name>