PS/2 keyboard driver IP core

for Xilinx EDK

Martin Týma, FEL »VUT



This application note describes a PS/2 keyboard driver EDK IP core which handles the physical and electrical part of the PS/2 protocol and provides a command based, high-level interface for communication with a PS/2 keyboard.



#include <ps2_kbd_driver.h>

void ps2_kbd_init(PS2KbdInst *instance,
  Xuint32 baseaddr, PS2KbdMode opmode)
void ps2_kbd_set_irq_handler(PS2KbdInst *instance,
  ps2_kbd_irq_handler hndlr)
Xuint8 ps2_kbd_get_code(PS2KbdInst *instance)
void ps2_kbd_set_code(PS2KbdInst *instance, Xuint8 code)
void ps2_kbd_irq_handler(void *instance)
XStatus ps2_kbd_selftest(PS2KbdInst *instance)


The ps2_kbd_init() function initializes an instance of the driver for the device given by it's base address. It also sets the operation mode of the device which can by either PS2_KBD_POLLING_MODE or PS2_KBD_IRQ_MODE.

If interrupt mode set, the function ps2_kbd_set_irq_handler sets the user interrupt handler for the device. Received data is automaticaly stored in drivers FIFO. If you want to handle the received scancode in the interrupt handler self, you can call ps2_kbd_get_code() in the handler.

The ps2_kbd_get_code() function returns the last scancode/response command sent by the keyboard if a new scancode/command has arrived since the last function call, zero otherwise. When the received scan code is not valid (parity error), the function initializes sending a repeat command (0xFE) to the device and returns 0. If in interrupt mode, data is read from the internal FIFO.

The ps2_kbd_set_code() function sends a command with the value code to the keyboard. This function always succeeds as the host is the bus master in the PS/2 protocol. If another one send operation is still in progress while the function is called, the function waits until the previous transmission is finished.

If the device is in interrupt mode, ps2_kbd_irq_handler() has to be registred as the interrupt handler for the device in Xilkernel or on the IRQ controller on standalone systems.

Design Files

The accompanying ZIP file ( contains the following files:



Microprocessor Peripheral Definition file (MPD). Describes bus and external port connections of the peripheral device.
Peripheral Analyse Order file (PAO). Dictates the correct order of synthesis for the VHDL source files.
Peripheral top level design. Instantiates the IPIF and user logic.
Connects the PS2 driver main module to the OPB throught the IPIF.
PS2 driver main module.
PS2 driver main FSM - switches between the transmit and the recieve module.
PS2 driver clock module. Filters PS2 clock and detects falling/rising edge on it.
PS2 driver receive module. Handles incoming PS2 communication.
PS2 driver transmit module. Handles outgoing PS2 communication.
Microprocessor Driver Definition file (MDD). Lists the peripherals that are able to use the software driver.
TCL script used by EDK for #define statements generation (e.g. baseaddress) in the xparameters.h header file.
Makefile used for building the SW driver.
Software driver source file.
Software driver header file.
Software driver low-level macros & definitions.
Peripheral self-test. Contains code to test the correct operation of the peripheral.

Design Implementation

This section describes how to create a simple EDK project to see a working demo of the peripheral driver.

  1. Start EDK and create a new project with the Base System Builder (BSB). You can find detailed instructions how to do this in the EDK tutorial [1]. In the peripheral selection part of the wizard leave all devices exept RS232 (will be used as STDIN and STDOUT) unchecked. Also disable the creation of all sample applications (Memory test, Peripheral SelfTest).
  2. Copy both top directories (pcores, drivers) of the accompanying archive to the root directory of your new EDK project.
  3. In the main EDK menu select: "Project"->"Rescan User Repositories".
  4. In the "Project Information Area" select "IP Catalog". Under "Project Local pcores" you should see "PS2_KBD_DRIVER". Double click on it to add the IP to the design. A ps2_kbd_driver_0 item should now appear in the System Assembly View window.
  5. Connect the IP to the OPB bus by selecting mp_opb as the bus connection for the SOPB connector of ps2_kbd_driver_0 in the System Assembly View window.
  6. Switch the "Filters" radio button to "Ports" and connect the IP ports. Set ps2_kbd_driver_0_PS2_clk net for PS2_clk and ps2_kbd_driver_0_PS2_data for PS2_data. If you intend to use the device in interrupt mode, also connect the interrupt port to the interrupt port of the processor (or the interrupt controller when used).
  7. Switch the "Filters" radio button to "Addresses" and click on the "Generate Addresses" button.
  8. If other Processor-Bus clock frequency then 50 MHz is used, a matching C_OPB_Clk_FREQ_HZ generic value must be chosen in the IP core configuration ("System Assembly View window"->"ps2_kbd_driver_0"->"Configure IP").
  9. Edit the UCF file. You can open it from the "Project Information Area" window under the "Project" bookmark. Add constraints for the PS2 clock and PS2 data pins. Name the pins PS2_clk and PS2_data. The constraints are board-specific and you can find them in the documentation for your board. For example for the Spartan-3E Starter board you need to add the following to the UCF file:
    NET PS2_clk LOC = G14 | IOSTANDARD = LVCMOS33;
    NET PS2_data LOC = G13 | IOSTANDARD = LVCMOS33;
  10. Edit the MHS file. Add the following two lines at the end of the file:
    PORT PS2_clk = ps2_kbd_driver_0_PS2_clk, DIR=IO
    PORT PS2_data = ps2_kbd_driver_0_PS2_data, DIR=IO    
  11. In the main menu click on "Hardware"->"Generate Bitstream". The HW part of the project should now successfully synthetize.
  12. In the "Project Information Area" select "Applications" and click on "Add Software Application Project" to create a new SW project.
  13. Add a new source to the created SW project with the following content:
    #include "xparameters.h"
    #include "ps2_kbd_driver.h"
    void main() {
        PS2KbdInst kbd;
        ps2_kbd_init (
  14. Select the SW project to initialize the BRAM in the "Project Information Area". Disable any other application (microblaze_0_bootloop, microblaze_0_xmdstub) to initialize the BRAM.
  15. In the EDK main menu select "Software"->"Build All User Applications". The SW project should successfully compile.
  16. Select "Device Configuration"->"Download Bitstream" to program the device.

A keyboard connected to the FPGA board should blink with its leds like start lights as soon as the FPGA finishes its configuration. Informations about the process of the selftest are also writen to STDOUT (RS232).

Implementation notes

Although the IP core/driver was primary designed for a ps2 keyboard, it can be used (except the self-test function of course) for any PS2 device, for example a mouse, since it only handles byte transfers from/to device which are independent on the upper layer protocol.




1. - A ZIP archive containing the sources