Skip to content

Instantly share code, notes, and snippets.

@buzztiaan
Created November 1, 2013 20:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save buzztiaan/7271501 to your computer and use it in GitHub Desktop.
Save buzztiaan/7271501 to your computer and use it in GitHub Desktop.
working PS2 mousedriver for LM4F with energia!
// attempt at PS2 implementation
// code stolen from http://hippy.blogs.exetel.com.au/index.php?/archives/24-MA2onPC,-a-Trackball-and-a-Stellaris-Launchpad.html
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
#define PS2_clockpin PE_2
#define PS2_datapin PE_3
// possible signal states
enum
{
PS2_STATE_IDLE,
PS2_STATE_DATA,
PS2_STATE_PARITY,
PS2_STATE_STOP,
PS2_STATE_DONE
};
// PS/2 transmission mode
enum
{
HOST_TO_SLAVE,
SLAVE_TO_HOST
};
// slave states
enum
{
SLAVE_DEAD,
SLAVE_INITIALIZED,
SLAVE_ACK_EXPECTED,
SLAVE_DATA_EXPECTED
};
// ps/2 byte buffers
volatile unsigned long g_ulRXCode = 0; // RX
volatile unsigned char g_ulTXCode = 0; // TX
// state machines
volatile unsigned char g_ucPS2RXState; // current RX state
volatile unsigned char g_ucPS2TXState = PS2_STATE_IDLE; // current TX state
volatile unsigned char g_ucPS2Mode = SLAVE_TO_HOST; // current transmission mode
volatile unsigned char g_ucPS2SlaveState = SLAVE_DEAD; // current state of the slave
volatile unsigned char g_ucPS2ExpectAck = 0; // are we expecting an ACK?
// extraction of the three byte movement message
volatile unsigned char g_ucMovSeq = 0;
volatile unsigned char g_ucMovHeader = 0;
volatile unsigned char g_ucDeltaX = 0;
volatile unsigned char g_ucDeltaY = 0;
unsigned char g_ucParity;
unsigned char g_ucTXParity;
unsigned char g_ucRXDataBitCount;
unsigned char g_ucTXDataBitCount;
// read ps/2 data pin.
char PS2ReadDat(void)
{
if(digitalRead(PS2_datapin))
{
return(1);
}
else
{
return(0);
}
}
// check the parity.
char getParity(unsigned n)
{
char parity = 0;
while (n)
{
parity = !parity;
n = n & (n - 1);
}
return parity;
}
void PS2Send(unsigned char txb)
{
// setup to send a byte to the slave PS/2 device
g_ucPS2Mode = HOST_TO_SLAVE;
g_ulTXCode = txb;
g_ucTXDataBitCount = 0;
g_ucPS2TXState = PS2_STATE_DATA;
// disable interrupts on port a
noInterrupts(); //IntDisable(INT_GPIOA);
// flip pins to outputs
//GPIOPinTypeGPIOOutput(PS2_BASE, CLK_PIN | DAT_PIN);
pinMode(PS2_clockpin, OUTPUT);
pinMode(PS2_datapin, OUTPUT);
// CLK low for 60us
digitalWrite(PS2_clockpin, LOW); //GPIOPinWrite(PS2_BASE, CLK_PIN, 0);
delay(60);
// data low
digitalWrite(PS2_datapin, LOW); //GPIOPinWrite(PS2_BASE, DAT_PIN, 0);
// clk high
digitalWrite(PS2_clockpin, HIGH); ////GPIOPinWrite(PS2_BASE, CLK_PIN, CLK_PIN);
// clock input mode
pinMode(PS2_clockpin, INPUT); //GPIOPinTypeGPIOInput(PS2_BASE, CLK_PIN);
// re-enable interrupts
interrupts(); //IntEnable(INT_GPIOA);
// now the interrupt routine will tx the data with the incoming clock, then flips data pin back to input.
}
void PS2_interrupt() {
switch(g_ucPS2Mode) {
case SLAVE_TO_HOST: // PS2 device talks to us
{
switch(g_ucPS2RXState) {
case PS2_STATE_IDLE: {
if(PS2ReadDat() == 0) {
g_ucPS2RXState = PS2_STATE_DATA;
g_ulRXCode = 0;
g_ucParity = 0;
g_ucRXDataBitCount = 0;
} else {
g_ucPS2RXState = PS2_STATE_IDLE;
}
break;
}
case PS2_STATE_DATA: {
g_ulRXCode >>= 1; // shift
if(PS2ReadDat()) { // read a bit
g_ulRXCode |= 0x80; // set the bit
g_ucParity++; // count highs
}
// last data bit
if(++g_ucRXDataBitCount > 7) {
g_ucPS2RXState = PS2_STATE_PARITY;
}
break;
}
case PS2_STATE_PARITY: {
if((g_ucParity & 0x01) == PS2ReadDat()) {
g_ucPS2RXState = PS2_STATE_IDLE;
} else {
g_ucPS2RXState = PS2_STATE_STOP;
}
break;
} // parity
case PS2_STATE_STOP: {
// check for stop bit (inverted)
if(PS2ReadDat()==0) {
g_ucPS2RXState = PS2_STATE_IDLE;
} else {
g_ucPS2RXState = PS2_STATE_DONE;
}
break;
}
} // select state
}
//------------------------------------------------------------------
case HOST_TO_SLAVE: // we want to talk to the PS2 device
{
switch(g_ucPS2TXState) {
case PS2_STATE_DATA: {
// write data out, LSB first
//g_ulTXCode >>= 1;
if ( g_ucTXDataBitCount > 0) {
if CHECK_BIT(g_ulTXCode, g_ucTXDataBitCount-1) {
digitalWrite(PS2_datapin, HIGH); // GPIOPinWrite(PS2_BASE, DAT_PIN, DAT_PIN);
} else {
digitalWrite(PS2_datapin, LOW); // GPIOPinWrite(PS2_BASE, DAT_PIN, 0);
}
} else {
// not the start bit
digitalWrite(PS2_datapin, LOW); // GPIOPinWrite(PS2_BASE, DAT_PIN, 0);
}
if(++g_ucTXDataBitCount == 9) {
g_ucPS2TXState = PS2_STATE_PARITY;
}
break;
}
case PS2_STATE_PARITY: {
if (!getParity(g_ulTXCode)) {
digitalWrite(PS2_datapin, HIGH); // GPIOPinWrite(PS2_BASE, DAT_PIN, DAT_PIN);
} else {
digitalWrite(PS2_datapin, LOW); // GPIOPinWrite(PS2_BASE, DAT_PIN, 0);
}
g_ucPS2TXState = PS2_STATE_STOP;
break;
} // parity
case PS2_STATE_STOP: {
pinMode(PS2_datapin, INPUT);
g_ucPS2TXState = PS2_STATE_DONE;
} // stop bit
case PS2_STATE_DONE: {
g_ucPS2TXState = PS2_STATE_IDLE;
g_ucPS2ExpectAck = 1;
g_ucPS2Mode = SLAVE_TO_HOST;
}
} // ps/2 tx state
} // host to slave
} // select transmission mode
}// interrupt handler
void setup()
{
Serial.begin(9600);
attachInterrupt(PS2_clockpin, PS2_interrupt, FALLING);
PS2Send(0xF4);
g_ucPS2SlaveState = SLAVE_DATA_EXPECTED;
}
void loop()
{
if (g_ucPS2RXState == PS2_STATE_DONE) {
switch (g_ucPS2SlaveState) {
case SLAVE_DATA_EXPECTED: {
switch (g_ucMovSeq) {
case 0: {
g_ucMovHeader = g_ulRXCode;
// check if this could be the first packet, whose 3rd bit is always 1
if ( CHECK_BIT(g_ulRXCode,3) != 0) { g_ucMovSeq++; }
break;
}
case 1: {
g_ucDeltaX = g_ulRXCode;
g_ucMovSeq++;
break;
}
case 2: {
g_ucDeltaY = g_ulRXCode;
g_ucMovSeq = 0;
/*
UARTCharPut(UART0_BASE, 'm' );
UARTCharPut(UART0_BASE, g_ucMovHeader );
UARTCharPut(UART0_BASE, g_ucDeltaX );
UARTCharPut(UART0_BASE, g_ucDeltaY );
*/
Serial.print("head ");
Serial.println(g_ucMovHeader);
Serial.print("x ");
Serial.println(g_ucDeltaX);
Serial.print("y ");
Serial.println(g_ucDeltaX);
break;
}
}
break;
}
case SLAVE_ACK_EXPECTED: {
g_ucMovSeq = 0;
if (g_ulRXCode == 0xAA) {
// UARTCharPut(UART0_BASE, 0xAA);
// turn off led
// GPIO_PORTF_DATA_R &= ~(GPIO_PIN_1);
PS2Send(0xF2);
g_ucPS2SlaveState = SLAVE_INITIALIZED;
} else {
// UARTCharPut(UART0_BASE, 0xFE); // reset has failed
}
break;
}
case SLAVE_INITIALIZED: {
g_ucMovSeq = 0;
if (g_ulRXCode == 0x00) {
PS2Send(0xF4);
g_ucPS2SlaveState = SLAVE_DATA_EXPECTED;
} else {
// UARTCharPut(UART0_BASE, 0xF4 );
}
break;
}
}
g_ucPS2RXState = PS2_STATE_IDLE;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment