- VHDL source code of a PS/2 host transceiver
- Outputs the PS/2 codes received from a PS/2 device
- Sets flag output when a new received code is available
- Validates parity, start, and stop bits of received data
- Accepts and transmits commands to a PS/2 device
- Notifies user when the transmit operation is in progress/complete
- Configurable system clock frequency
- Synchronizes between PS/2 and system clock domains
- Debounces incoming PS/2 signals
This details a PS/2 host transceiver component for use in CPLDs and FPGAs, written in VHDL. The component receives data transactions from a PS/2 device and provides the PS/2 data to user logic over a parallel interface. It also accepts commands from user logic over a parallel interface and transmits them to the PS/2 device per the PS/2 protocol. It was designed using Quartus II, version 13.1. Figure 1 illustrates a typical example of the PS/2 host transceiver integrated into a system. The PS/2 Mouse Interface available here implements this PS/2 Host Transceiver to stream data from a standard PS/2 mouse. The PS/2 Keyboard Interface available here implements a simplified version of this PS/2 host transceiver design (using only receive logic with no transmit functionality).
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.
Figure 2 illustrates the receive transaction format. Both clock and data signals are logic level high when inactive (note pull-up resistors). The device 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 Receive Timing Diagram
Figure 3 shows the transmit transaction format. The host first requests to transmit data by pulling the clock line low for 100us. This inhibits the PS/2 bus. Following this 100us inhibit, the host releases the clock and outputs a low start bit on the data line. The device then begins generating clock pulses. On each falling edge, the host shifts out the data bits, LSB first, followed by the parity bit. On the next clock, the host releases the data line, which is pulled high by its pull-up resistor to signal a stop bit. Having read each of these signals on the rising clock edges, the device issues a logic low acknowledge bit to communicate back to the host that it has received the data. The host reads this acknowledge bit on the last falling edge, and the device proceeds to release both the clock and data lines, which return to logic level high.
Figure 3. PS/2 Transmit Timing Diagram
Figure 4 depicts the PS/2 host transceiver’s state diagram. The component resides in the receive state whenever it is not executing a transmit transaction. While in this state, it can detect transactions initiated by the device, receive the data, and output it to the user logic. If the user logic requests a transmit transaction by asserting the tx_ena signal, the host latches in the data and proceeds through a series of states that executes the transmit transaction. It first enters the inhibit state, where it inhibits the PS/2 clock line for 100us. Following this period, it advances to the transact state, where it sends the data and parity bit and also evaluates the device’s acknowledge bit. Finally, it proceeds to the tx_complete state, where it waits for the device to release the PS/2 bus before returning to the receive state.
Figure 4. State Diagram
Figure 5 conceptually illustrates the PS/2 host transceiver’s operation. Incoming signals from the PS/2 clock and data ports are synchronized and debounced. (The debounce component VHDL is provided above and documentation is available here.) The resultant internal PS/2 data signal is then serially loaded into a shift register on falling edges of the PS/2 clock. In the receive state, an idle counter determines when the transaction is finished, defined by the PS/2 clock remaining at a high logic level for more than 55us, i.e. longer than half of the worst-case PS/2 clock period. Combinational error checking logic verifies the start bit, stop bit, and parity bit with the corresponding data. When the PS/2 port is idle and the data is valid, the component outputs the received PS/2 code and sets the ps2_code_new signal high to indicate that a new code is available on the ps2_code bus. The code remains available on the bus until another code is received. The ps2_code_new signal remains high until another PS/2 transaction begins (when a low PS/2 clock signal clears the idle counter).
Figure 5. Conceptual Architecture
When a transmit transaction is requested, the transmit data and parity, provided on the tx_cmd bus, are loaded into the shift register. The inhibit state outputs a logic low on the PS/2 clock line to inhibit the bus. During the transact state, the PS/2 clock is released, and the command in the shift register is serially shifted out to the PS/2 data line on falling PS/2 clock edges. The bits are counted, and the data line is released at the appropriate time to receive the device’s acknowledge bit.
Table 1 describes the PS/2 host transceiver’s ports.
Table 1. Port Descriptions
|clk||1||in||standard logic||user logic||System clock.|
|reset_n||1||in||standard logic||user logic||Asynchronous active low reset.|
|tx_ena||1||in||standard logic||user logic||Transmit enable. ‘1’ latches the tx_cmd into the PS/2 transceiver, which then sends it to the PS/2 device. tx_ena is ignored if a transmit operation is already in progress (indicated by tx_busy = ‘0’).|
|tx_cmd||9||in||standard logic vector||user logic||Command to be transmitted to the PS/2 device. The MSB is the odd parity bit, and the 8-bit command follows, MSB first.|
|tx_busy||1||out||standard logic||user logic||‘1’: a transmit transaction is in progress. ‘0’: a transmit transaction is not in progress.|
|ack_error||1||out||standard logic||user logic||‘1’: the PS/2 host transceiver did not receive the proper acknowledge bit during the last transmit. ‘0’: the device responded with an acknowledge during the last transmit.|
|ps2_code_new||1||out||standard logic||user logic||New code available flag. The flag is low during PS/2 receive transactions, and a low-to-high transition indicates that a receive transaction has completed. A new PS/2 code is available on the ps2_code bus unless an rx_error is present.|
|ps2_code||8||out||standard logic vector||user logic||8-bit PS/2 code received from the device.|
|rx_error||1||out||standard logic||user logic||‘1’: a start bit, stop bit, or parity bit error was detected during the last receive. ‘0’: no errors detected during the last receive.|
|ps2_clk||1||inout||standard logic||PS/2 device||Clock signal line from the PS/2 device.|
|ps2_data||1||inout||standard logic||PS/2 device||Data signal line from the PS/2 device.|
The system clock speed affects the timing operations of the host transceiver. The two GENERIC parameters declared in the ENTITY, clk_freq and 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 debounce_counter_size parameter must be set such that 2^debounce_counter_size / clk_freq = 5us. For a 50 MHz system clock, debounce_counter_size = 8.
Figure 6 shows the timing diagram of an example receive transaction. Once the PS/2 clock signal goes low, the ps2_code_new flag deasserts to indicate that a new PS/2 receive transaction is in progress. When the transaction completes, the ps2_code_new flag asserts to indicate that a new PS/2 code has been received and is available on the ps2_code bus. In this case, the PS/2 code received is x“35”. The rx_error signal remains low, indicating that no errors were detected during the transaction.
Figure 6. Example PS/2 Receive Transaction
Figure 7 shows the timing diagram of an example transmit transaction. Once the user logic asserts the tx_ena input, the PS/2 host transceiver latches in the command on the tx_cmd port. The tx_busy signal goes high to indicate that the transmit transaction is in progress and that the user logic is free to deassert the tx_ena signal. The transceiver executes the transaction. When complete, it deasserts the tx_busy output signal to indicate that the transaction is finished and the transceiver is again available. The ack_error signal remained low, indicating that the PS/2 device issued the expected acknowledge bit at the end of the transaction.
Figure 7. Example PS/2 Transmit Transaction
This PS/2 host transceiver interface is a programmable logic component that handles transactions with PS/2 devices. It synchronizes the clocks domains, debounces the input signals, performs error checking, sends commands, receives data, and notifies the user logic when new data from the device is available on its parallel output bus.
Comments, feedback, and questions can be sent to firstname.lastname@example.org.