PS/2 Controller

The PS/2 Controller is a peripheral that allows for communication between the DE1-SoC Board and a PS/2 Device (Mouse or keyboard).

DevicePS/2 Controller
Configuration2 32-bit mapped registers
Input/OutputEither
Address BaseController 1: 0xFF200100. Controller 2: 0xFF200108
Address Map
AddressR/W/CDescription
baseR/W31:16 Number of characters left to be read (before this read)
15 - read data valid
7:0 The data itself
base+4R/CControl/status bits:
10 - indicates an error has occured
8 - read interrupt pending
0 - read interrupt enable
InitializationNone, but mouse or keyboard may require initialization (see references)
Interrupts
TriggeredOn data received
IRQ LineController 1: IRQ 7. Controller 2: IRQ 23
EnableBit 0 of control register
AcknowledgeRead data to acknowledge the interrupt
Hardware SetupPlug a PS/2 Device into the PS/2 port on the DE1-SoC Board.
ReferenceFull Documentation of controller from Altera
PS/2 Mouse Protocol
PS/2 Keyboard Protocol
PS/2 Non-device-specific Documentation (hardware)

Notes

Use bit 15 (data valid) to determine if a read is valid. The "Number of bytes available" field (Data[31:16]) is unreliable when used for polling, as it returns the state of the queue one cycle earlier than when the bytes are actually available. For example, reading the data register in the same cycle as a byte is received will result in "1 byte available", but the byte will not be valid, and no bytes will be dequeued from the FIFO.

The PS/2 Controller only provides a method for communication of bytes between the board and the device. The style of communication that will take place (protocol) depends on the device in question.

For specific information on interacting with a PS/2 Mouse or Keyboard, see the references for details.

Assembly Example: A subroutine to send a command to the mouse

# Sends the command stored in r2, then waits for the response values stored in r3 and/or r4 (if there are any values greater than 0xff in those registers mean to not expect a response.) 
EXECUTE_COMMAND:
   movia r7, 0xFF200100
   stwio r2, 0(r7) # Send command in r2 

   movui r5, 0xff
   bgt r3, r5, return_from_execute # If r3 is > 0xff, finished 

Exec_Loop_1:
   ldwio r6, 0(r7) # Since r3 < 0xff, wait for the response 
   andi r6, r6, 0xff
   bne r3, r6, Exec_Loop_1

   bgt r4, r5, return_from_execute # If r4 is > 0xff, finished 

Exec_Loop_2:
   ldwio r6, 0(r7) # Since r4 < 0xff, wait for the response 
   andi r6, r6, 0xff
   bne r4, r6, Exec_Loop_2

return_from_execute:
   ret 


C Example: Reading from PS/2 and displaying on LEDs


#define RLEDs ((volatile long *) 0xFF200000)

int main() {
	unsigned char byte1 = 0;
	unsigned char byte2 = 0;
	unsigned char byte3 = 0;
	
  	volatile int * PS2_ptr = (int *) 0xFF200100;  // PS/2 port address

	int PS2_data, RVALID;

	while (1) {
		PS2_data = *(PS2_ptr);	// read the Data register in the PS/2 port
		RVALID = (PS2_data & 0x8000);	// extract the RVALID field
		if (RVALID != 0)
		{
			/* always save the last three bytes received */
			byte1 = byte2;
			byte2 = byte3;
			byte3 = PS2_data & 0xFF;
		}
		if ( (byte2 == 0xAA) && (byte3 == 0x00) )
		{
			// mouse inserted; initialize sending of data
			*(PS2_ptr) = 0xF4;
		}
		// Display last byte on Red LEDs
		*RLEDs = byte3;
	}
}