PS/2 Keyboard to ASCII Converter Logic (top level VHDL for the design): ps2_keyboard_to_ascii.vhd (16.9 KB)
PS/2 Keyboard Interface Logic (must be included in the project): ps2_keyboard.vhd (5.1 KB)
Debounce Logic (must be included in the project): debounce.vhd (2.4 KB)
- VHDL source code of a PS/2 keyboard to ASCII converter
- Outputs the ASCII codes that correspond to key presses on a PS/2 keyboard
- Ignores keys that have no ASCII equivalent
- Sets a flag output when a new ASCII code is available
- Validates parity, start, and stop bits of PS/2 transactions
- Configurable system clock frequency
- Synchronizes between PS/2 and system clock domains
- Debounces incoming PS/2 signals
This details a PS/2 keyboard to ASCII converter component for use in CPLDs and FPGAs, written in VHDL. The component receives data transactions from a PS/2 keyboard and provides the corresponding ASCII codes to user logic over a parallel interface. It provides codes only for key presses (not releases) and ignores keys that do not have ASCII equivalents. It was designed using Quartus II, version 12.1. Figure 1 illustrates a typical example of the PS/2 keyboard to ASCII converter integrated into a system.
Figure 1. Example Implementation
PS/2 (IBM Personal System/2) is an interface for keyboards and mice to PC compatible computer systems via a 6-pin Mini-DIN connector. The computing system must provide the keyboard or mouse with 5V source and ground connections. Communication occurs over a 2-wire serial interface, consisting of a clock line and a data line. Both lines require pull-up resistors (2kΩ shown in Figure 1). The 120Ω series resistors in Figure 1 are required to interface the 3.3V FPGA I/O to the 5V signals.
Once powered, the keyboard goes through a self- initialization sequence. Upon completion, it is ready to communicate keyboard events over the PS/2 interface.
Figure 2 illustrates the transaction format. Both clock and data signals are logic level high when inactive (note pull-up resistors). The keyboard provides both the clock and data. The clock has a frequency between 10 kHz and 16.7 kHz (i.e. a 60-100us period). The data begins with a start bit (logic low), followed by one byte of data, a parity bit, and finally a stop bit (logic high). The data is sent LSB first. Each bit should be read on the falling edge of the clock signal. Once complete, both the clock and data signals return to logic level high.
Figure 2. PS/2 Keyboard Transmission Timing Diagram
The data byte represents part of a keyboard scan code: either a make code (key press) or a break code (key release). Three different sets of scan codes exist, however the vast majority of keyboards use Scan Code Set 2, which is provided in the Appendix on this page. A make code usually consists of either one or two bytes. If a make code uses two bytes, the first byte is x“E0”. A given key’s break code is typically the same as its make code, except that break codes include an additional x“F0” byte as the 2nd to last byte. (The PAUSE and PRNT SCRN keys are exceptions to the above.)
While it is possible to send data to a keyboard (to change its settings, etc.), this is generally unnecessary and is not included in this VHDL component.
ASCII (American Standard Code for Information Interchange) is a prominent standard for encoding characters and control codes into 7-bit binary integers. ASCII defines 128 individual codes (95 characters and 33 control codes). These codes can all be translated from a keyboard, either as direct key presses or as combinations of key presses.
This PS/2 keyboard to ASCII converter handles incoming transactions from the PS/2 keyboard and determines which keys are being pressed at a given time. It then outputs the ASCII encoding that corresponds to these key presses. The appendix lists the ASCII Character Set. All character keys have their respective ASCII codes outputted by the PS/2 to ASCII converter as listed, when those keys are pressed in a standard fashion (with respect to shift, caps lock, etc.). If a control key is held down, the converter outputs the corresponding control code for each key instead (irrespective of shift or caps lock). The converter also outputs control codes for the additional following keys: backspace (BS), tab (HT), enter (CR), escape (ESC), and delete (DEL).
The source code for the PS/2 keyboard to ASCII converter consists of the following three files:
The ps2_keyboard_to_ascii.vhd file is the top level VDHL. It instantiates the PS/2 keyboard interface component (ps2_keyboard.vhd). This internal component handles the transactions with the keyboard. It synchronizes the interface and system clocks domains, debounces the input signals, performs error checking, and provides the codes received from the keyboard. Detailed documentation for the PS/2 keyboard interface is available here. (The PS/2 keyboard interface component in turn instantiates the debounce component, debounce.vhd. Documentation for the debounce component is available here.)
The PS/2 codes provided by the PS/2 keyboard interface component control the converter’s state machine. Figure 3 depicts the operation of the state machine. Upon start-up, the component immediately enters the ready state. It waits in this state until it receives a new PS/2 code. The new_code state builds the PS/2 make or break codes. If the new code received is the last byte in the make/break code, the state machine proceeds to the translate state, otherwise it returns to the ready state to await the next byte. Once in the translate state, the converter determines which key was pressed and translates it into ASCII. If the code is a break code, then no action is needed, so the converter ignores the code and returns to the ready state. However, if a make code was received, the converter proceeds to the output state, where it outputs the resultant ASCII code on the ascii_code bus and sets the ascii_new output flag to indicate that the new code is available. The converter then returns to the ready state to await the next communication from the PS/2 keyboard interface component.
Figure 3. State Diagram
Table 1 describes the PS/2 keyboard to ASCII converter’s ports.
Table 1. Port Descriptions
The system clock speed affects the debounce time and the idle counter timing of the PS/2 keyboard interface component within the converter. The two GENERIC parameters declared in the ENTITY, clk_freq and ps2_debounce_counter_size must be set appropriately for the component to operate correctly. The clk_freq parameter must be set to the system clock clk frequency in Hz. The default setting in the provided code is 50 MHz (the frequency at which the component was simulated and tested). The ps2_debounce_counter_size parameter must be set such that 2^ps2_debounce_counter_size / clk_freq = 5us, as described in the documentation for the debounce component here. For a 50 MHz system clock, ps2_debounce_counter_size = 8.
Figure 4 shows the timing diagram of an example transaction. Once the internal PS/2 keyboard interface finishes receiving the PS/2 transaction, the ascii _new flag deasserts to indicate that a new PS/2 to ASCII conversion is in progress. When the transaction completes, the ascii_new flag asserts to indicate that a new ASCII code has been received and is available on the ascii_code bus. In this case, the PS/2 code received is x“1C” (the make code for the “A” key), and the resulting ASCII code is x“61” (the ASCII code for the “a” character).
Figure 4. Example Transaction
This PS/2 keyboard to ASCII converter is a programmable logic component that receives transactions from PS/2 keyboards and outputs their ASCII equivalents. It synchronizes the PS/2 and system clock domains, debounces the input signals, performs error checking, translates the PS/2 codes into ASCII codes, and notifies the user logic when new ASCII codes are available on its parallel output bus.
Table A1. ASCII Character Set
|Binary||Dec||Hex||Control Code||Key||Control Code Name|
|000 0000||0||0||NUL||^@||Null Character|
|000 0001||1||1||SOH||^A||Start of Header|
|000 0010||2||2||STX||^B||Start of Text|
|000 0011||3||3||ETX||^C||End of Text|
|000 0100||4||4||EOT||^D||End of Transmission|
|000 1001||9||9||HT||^I||Horizontal Tab|
|000 1010||10||0A||LF||^J||Line feed|
|000 1011||11||0B||VT||^K||Vertical Tab|
|000 1100||12||0C||FF||^L||Form Feed|
|000 1101||13||0D||CR||^M||Carriage Return|
|000 1110||14||0E||SO||^N||Shift Out|
|000 1111||15||0F||SI||^O||Shift In|
|001 0000||16||10||DLE||^P||Data Link Escape|
|001 0001||17||11||DC1||^Q||Device Control 1 (oft. XON)|
|001 0010||18||12||DC2||^R||Device Control 2|
|001 0011||19||13||DC3||^S||Device Control 3 (oft. XOFF)|
|001 0100||20||14||DC4||^T||Device Control 4|
|001 0101||21||15||NAK||^U||Negative Acknowledgement|
|001 0110||22||16||SYN||^V||Synchronous Idle|
|001 0111||23||17||ETB||^W||End of Transmission Block|
|001 1001||25||19||EM||^Y||End of Medium|
|001 1100||28||1C||FS||^\||File Separator|
|001 1101||29||1D||GS||^]||Group Separator|
|001 1110||30||1E||RS||^^||Record Separator|
|001 1111||31||1F||US||^_||Unit Separator|
Comments, feedback, and questions can be sent to firstname.lastname@example.org.