FPGA chips provide a nice way to learn digital electronics and make some projects, however very often they lack prewritten libraries, thus every external module must be carefully analysed to write a library/driver for them.
Thus today for people who want to use a PS2 (old fashioned connection) type keyboard for their project I will provide a little manual with the written code!
For the project I will use Verilog language and Xilinx Basys 2 Board, which now is quite old... But still does the job for such applications.
Step 1: Some Background
Strictly speaking, PS2 type connection uses 2 wires to transmit data, which are called DATA and CLOCK. When you press the button on the keyboard, the microcontroller which is inside the keyboard sends packets of 11 bits of information on DATA wire. Each bit is accompanied by a falling CLOCK edge signal, meaning that you must only read the data when CLOCK signal falls down and not the other time. The first bit is START bit, then there are 7 bits for DATA0-6, then a PARITY bit and finally STOP bit. After the data is received, and checked that it is correct (START, PARITY and STOP bits have adequate values) you only need to keep DATA0-6 bits and get rid of the rest.
Now looking broader, when a button is pressed, the keyboard sends one packet of 11 bits to tell which button was pressed. If the key is pressed and held then it starts repeatedly send the same packet. Finally if you release the button it sends another 2 packets, telling that the button was released and which button was released. This is a little different for different for so called extended buttons, where it sends one more packet and to know what code must be received you can read manual or lets say here.
The frequency it transmits data is quite low and can vary from 10 kHz to 16.7 kHz. This becomes important, when you use an FPGA with speeds of 50 MHz and larger. You have to scale the frequency down by some factor, otherwise you will be reading the wrong CLOCK signal (for example you will be reading data while the CLOCK signal is still changing...). Scaling the FPGA board to around 30-50 kHz should do the job, but again this will depend on the keyboard.
Finally it is important to describe what will happen if you receive less than 11 bits as sometimes this happens as well. Very rarely, but still happens... What I did here is put a timer to tell if enough time has passed from receiving the bit and if the time period is too long until receiving the next bit, it flushes everything that it received until this point.
You can always read more about the protocol in here or simply google 'PS2 type Protocol', which will give you better insight about it works. I really recommend you reading more about it if you want to implement the drivers yourself! Basys 2 board manual also provides information about how such thing could be implemented on page 5-7 of the manual.
Step 2: Connections
If you look into the manual of Basys 2 page 6 you can find that DATA pin is on C3 connection of the board and CLOCK is on B1. To test the keyword which the board receives I used the LEDs (LD0 - LD7) that are on the board. Adding the connection file KeyboardConstrains.ucf.
Step 3: Verilog Code
To test the code in the test bench before actually connecting the keyboard you can use wrapper.v and TestingKeyboard.v modules.
There is only one module, called Keyboard.v, where all the code is. It might be little difficult to understand the code but if you read the PS2 interface manual and the previous section, everything should clear out.
The pseudo code for this module is:
Two counters are used within this module:
-> DOWNCOUNTER is used to bring the frequency 250 times as TRIGGER is triggered wether that happens.
-> count_reading counts up if not a full packet of 11 bits is received yet. (later it checks if this number reached 4000...)
This module receives the information and checks if it OK.
-> If the TRIGGER is triggered, then check if the PS2_CLK changed its state
--> If the state changed and if the clock is on falling edge do:
---> Add up the DATA bit that was currently received to the previous bits
----> Mark down that one more bit was received
-----> If 11 bits were received, trigger out another signal, telling that it finished reading
--------> Check the parity bit if the received information is OK
-----> If 11 bits were not received check if it took more than 4000 times for count_reading to count up after it received the previous bit.
-------->- and reset everything if it took more. Else skip this.
Another little module extracts the information:
-> Wait for the trigger, which checks if the full pack of 11 bits was received
--> If there was an error in the received packet, discard everything.
---> However extract the DATA bits if the information was OK.
Now you can do whatever you want with the extracted data. For example, you can look for arrow presses and then add up/down some LED register, which light up LEDs... Or use the arrow presses to control Snake Game :)