Maybe you want to free up a USB port (especially on Pi-zero or
Pi-aplus).
Maybe you have piles of PS/2 keyboards gathering dust (perhaps
one is a much treasured Model-M).
Maybe you are writing your own OS and want keyboard access without
having to write a full USB stack.
Background
The Raspberry Pi is great for hacking with, but it is hard to get keyboard
input without using USB. If you're running Linux that's not a problem,
but if you're running your
own operating system
it's a problem, especially if you don't feel like writing a complete USB
stack.
The PS/2 keyboard interface is a very simple serial protocol, so I wanted
to design a board that would take a traditional PS/2 keyboard and convert
it to something that could be read with standard Pi GPIOs.
This will be useful for the
Advanced OS course I teach, as it is easy
to get video output going but until now we couldn't get keyboard input,
only serial port which can be a bit awkward (you need another machine
around to use your OS).
The PS/2 Interface
The PS/2 interface is a simple serial interface. It is an open-collector
bus and you can send commands to the keyboard (set repeat rate,
turn on caps-lock LED, etc.) or get values upon keypress.
The values you get are encoded a bit, and you generally get two actions
for each keypress (once when it is pressed and once when released).
The adapter maps the clock and data lines from
the keyboard to two Raspberry Pi GPIOs.
The Pi wants 3.3V I/O, so the board includes a logic level converter
to drop the 5V signals from the keyboard to 3.3V.
The board is designed to be like a "hat" so you can plug the board
to the GPIO header but still have access to all of the GPIO lines.
It uses GPIO 23 and 24 by default, but the connection is jumpered so you can
disconnect from those pins and use jumper wires to manually
use any GPIO.
The keyboard is powered directly by the Pi.
I've seen reports that a
keyboard can draw up to 275mA so you might want to make sure you have a strong
enough power supply.
The connector has a traditional DIN-6 PS/2 connector for the keyboard.
Many USB keyboards support a legacy PS/2 mode (often these will come
with "USB/PS-2 adapters" that are just straight through wiring of the
PS/2 pins to the USB connector). Because of this the adapter has a USB
connector so you can use these types of keyboards without the PS/2 adapter
*NOTE* not all USB keyboards will work in this socket.
Frequently Asked Questions
Can I use a PS/2 mouse instead?
Probably! It is untested and will of course require code
to handle the protocol.
Can I hook up an arbitrary USB device to the port?
No! Only keyboards (and even then only keyboards that handle fall-back
compatibility to PS/2 mode)
Can I use a mouse and keyboard at the same time?
Maybe! The bus is open collector, so in theory you could
put a PS/2 mouse on the PS/2 connector and a supported keyboard on
the USB keyboard and use both. You'd have to write a special
driver to handle this case.
Can I use this on a Pi 2/ Pi B+?
Yes! The header is narrow enough that it fits even on
devices with 40-pin headers.
Is this a full hat, with eprom and autodetection of device-tree files?
No! Maybe if I get really bored someday.
Is there a Linux driver for this?
Yes! It is included with the source code.
Will this work on non-Pi embedded boards?
The board is designed with the Pi GPIO header in mind.
You could in theory hook up 5V, 3.3V and two GPIOs and use
it with any board that has 3.3V GPIO but this is untested.
How much does it cost to build one?
Roughly $11 each assuming you are making them in batches of 12.
This will vary depending how cheaply you can source/scrounge
the parts needed, and if you leave out optional parts.
Can I buy a kit?
No, but I include the parts list and the gerbers in the source
tree and you can order the
board from OSHPark here.
Driver Challanges
The ps/2 protocol is very timing dependent.
The 11 bits are clocked in at a rate of about 60-100usecs each,
so you either have to interrupt on the first bit and then poll (causing
your interrupt handler to have a latency of over 1ms, not good) or else
have an interrupt on each clock signal (but then if you can't guarantee
interrupt latencies of 50us or so you will miss bits and lose sync).
There are a few ways to work around this:
Just hope you can handle a low interrupt latency.
That's what the Linux and VMWos drivers currently do,
and it mostly works.
Use a RTOS that can meet the deadline (probably overkill).
Configure the hardware to gather the packet for you and let you
know when it's ready. That's why other implementations use
the UART interface rather than raw GPIOs.
Make custom hardware that handles the tough timing.
See the i2c, SPI, and external UART converter boards available.
(Also the i8042 keyboard controller used in the original PC)
Source Code
Some sample code for accessing this is available in
my
vmw-meter source repository under the pi-ps2 directory.
Also included are the GEDA design files and gerbers.
There is also a sample linux-kernel driver:
pi-ps2gpio.c
Related Work
There have been similar PS/2 keyboard projects over the
years, but as far as I can tell
none specific to the Pi (most are for PIC and other microcontrollers).
And none use both generic GPIOs while providing a Linux driver.
Karl Lunt Bare-metal PS/2: used resistors for the
voltage drop,
only has bare-metal support (no Linux driver)
Linux driver using an LED for the voltage drop and the UART interface
(unusable for me because I want a serial connection at the same
time). Confusingly there are two similar pages for more or less
the same project, possibly
by the same person?
The Pirow,
The Pi Hacker.
My Linux driver is based off of the one by the Pi Hacker.
For those of you who only interact with the world through videos,
I've created a video for the project. It's hard making keyboard
usage interesting.
8 January 2016
Working on driver for
VMWos.
Complicated as it involved writing
a GPIO library, and then migrating the UART code to be interrupt driven
and then providing a console input abstraction layer.
It now works when using a serial port for output. Using the HDMI console
is troublesome as current code spends so much time drawing characters to
the screen that interrupts are missed and the keycodes get corrupted.
Real solution is probably to enable L1-cache/MMU but that might be a bit
of work.
7 January 2016
Linux driver is a bit hackish but it works.
6 January 2016
Working on writing a Linux kernel driver. Turns out to be easier
than I thought it would be.
4 January 2016
The boards are back already! That was quick.
Here it is assembled, front and back:
And here it is hooked up to a Pi-Bplus. Remarkably it worked first try!
Well, mostly works. I'm actually impressed trying to bitbang the interface
from userspace works at all. Need to get one of the existing gpio/ps2
kernel drivers installed, or else write a driver for
my OS.
22 December 2015
Made a PCB via GEDA and sent it off to OSH Park to get made.
We'll see how that goes. Some annoying complications as the
DIN6 footprint I made was using the pin numbers from the top whereas
the datasheet was labeling from the bottom, but I think I got it all
sorted out properly before sending it off. We'll find out in 2-4 weeks.
18 December 2015
Got keyboard input working via the GPIO lines! Adding external
pullup resistors helped a lot.
17 December 2015
Hooked up the board to the oscilloscope to make sure it all worked
at least at the hardware level.
Success! Here it is showing the proper output when a 'V' is pressed.
Now just need to get the Pi reading this over the GPIO ports.
16 December 2015
Soldered together a prototype of the adapter board.
Ruined a PS/2 connector trying to solder the tiny wires, in the end
used an IDC connector/socket even though it's more expensive that way.