PS2/Mouse Interface

Mission Statement

I was given the task of creating a serial bidirectional 2-line interface for a PS2Mouse such that it will be able to talk in PS2Mouse Protocol to the MBED. Eventually this is to be placed on the bottom of the Sumovore, such that it is able to calibrate its motors for straight driving and also to create a distance counter and possibly even a position detector/logger.

source:/PS2Mouse/doc/Internal Mouse Side View.jpg

Pinout

Looking into end of the plug:


          nc --->   o  o   <--- clk
 
       +5V --->   o      o   <--- GND
                     ||
         nc --->   o || o   <--- data

N.B. There is no need to ground the nc pins.

Hello World! - Mouse Style

There isn't currently a class which deals with the bidirectional IO lines used in PS2 mice. When communicating with a PS2mouse, the clocking is always done by the device and the host has to look on; despite this, the host is the one in control! The host and mouse have to do a little dance to each other before they know for sure that data may be transmitted in either direction. In the following program the host (MBED) sends out the command 0xFF which means RESET and the mouse undergoes a BAT (Basic Assurance Test) - a self-diagnostic -. The mouse then replies with 0xAA for SUCCESS or 0xFC for ERROR, followed by its ID (normally 0x00). Thereafter the mouse is plunged into Stream Mode.

#include "mbed.h"
#include "PS2Mse.h"

PS2Mse mse(28, 26);
Serial pc(USBTX,USBRX);
unsigned char rd(void)
{
    unsigned int buf = 0x00;
    _ps2clk = 0;
    _ps2data.direction(0);              //input
    _ps2clk.direction(0);               //input
    for(int i=0;i<11;i++) {             //11 bits for device-to-host communication
        while(_ps2clk);                 //falling edge
        while(!_ps2clk);                //rising edge
        buf = buf >> 1;                 //Bitwise SHIFT RIGHT
        buf |= _ps2data ? 512 : 0;        //if ps2data is high make a high bit
    }
    _ps2clk.direction(1);               //output
    buf &= 0xFF;                        //keep only the 8 data bits
    return(unsigned char)buf;
    //return (unsigned char)buf;
}
void wr(unsigned char cmd)
{
    parity = 0;
    request = cmd;
    _ps2data.direction(1);              //output
    _ps2clk.direction(1);               //output
    _ps2clk = 0;                        //clock low
    wait(0.15);                         //for a dur. of 150ms
    _ps2data = 0;                       //HOST Request-to-send
    _ps2clk = 1;
    _ps2clk.direction(0);               //input
    for(int i=0;i<8;i++) {              //8 data bits
        while(_ps2clk == 1);            //falling edge (device is ready for next bit)
        _ps2data = (bool) (request & 1);    //cast _ps2data
        if(_ps2data == 1) {
            parity++;                   //count the no. of 1's in request
        }
        request = request >> 1;         //next bit ready
        while(_ps2clk == 0);            //rising edge (device reads ps2digi)
    }
        parity_bit = (bool) !(parity & 1);
    while(_ps2clk == 1);
    _ps2data = parity_bit;              //digital the parity bit
    while(_ps2clk == 0);
    while(_ps2clk == 1);
    _ps2data = 1;
    _ps2data.direction(0);              //input
    while((_ps2clk == 1)||(_ps2data == 1));
    while((_ps2clk == 0)||(_ps2data == 0));
}
int main()
{
    mse.wr(0xFF);
    pc.printf("Sent");
    while(1) {
    pc.printf("%X", mse.rd());
    }
}
source:/PS2Mouse/doc/Mouse Com_1.jpg
CodePhoto

As can be seen, the rd() and wr() functions are fairly chunky and not very nice at all, so having included them in the PS2Mse class will come as a relief to many. I have used the printf() function from the serial class to display my data in Tera term, which I highly recommend!

Modes of Operation

The PS2Mouse has four modes of operation;

Reset Mode:: The mouse is in this mode on power up and after receiving the mse.reset() function
Stream Mode:: This is the default mode. Movement Data Packages are sent to the host (MBED) whenever there is a change in status or position. It is entered after reset mode.
Remote Mode:: Here the mouse only ever sends information when requested.
Wrap Mode:: The mouse sends every byte received back to the host.

I have only decided to include Reset and Stream modes, since they are the two most commonly used. Despite this, I may later include a PS2Mse_extension class to cater for the plethora of functions less used.

Example Program

#include "mbed.h"
#include "PS2Mse.h"

PS2Mse mse(28, 26);
Serial pc(USBTX,USBRX);
int main()
{
    mse.initialise();
    while(1)
    {
        pc.printf("x = %f,       ", mse.metric_x(1));
        pc.printf("y = %f\n\r", mse.metric_y(1));
    }
}
source:/PS2Mouse/doc/Stream Mode.jpg
This program demonstrates the most important functions metric_x(bool) and metric_y(bool). metric_x() returns the value of the x-coordinates in millimetres and metric_y does likewise but for the y-axis. The boolean parameters have the following effect:Here is an example of the MBED collecting data from the mouse in stream mode and using the metric_x(1) and metric_y(1) functions to log the overall coordinates of the mouse in Tera term.
0 = return the instantaneous movement vector - how far the mouse has moved since the last reading
1 = return the total movement vector - the overall coordinates of the mouse in reference to a set origin defined as the position upon resetting/initialising.

N.B.

Before any of the data may be taken from the mouse the initialise(void) function MUST be stated in the coding. If this is not done the mouse may not return the data wanted. It really depends on the type of mouse!

Default Settings

The set_defaults(void) function set the following settings:

Sample Rate100 samples/sec
Resolution4 counts/mm
Scaling1:1
Data reportingOFF

To alter the above settings you will either have to follow the link to http://www.computer-engineering.org/ps2mouse/ where the commands are stated, whereupon you may simply write the hex command into the wr() function i.e.

wr(0xE9);         //status request

(you will have to edit the metric_ x or y() function in order to accommodate for a different conversion value to convert from counts to millimetres) or wait till I write and upload an extension to the PS2Mse class, however, for the current time I doubt there will be a great need for the PS2Mse_extension class.

Cool Mini-Project

Cursor

The following program takes the mouse coordinates and uses them to plot a cursor on a small Nokia LCD Screen, which in effect is using the primary function of the mouse, as a pointer.

#include "mbed.h"
#include "PS2Mse.h"
#include "MobileLCD.h"

PS2Mse mse(28, 26);
MobileLCD lcd(5, 6, 7, 8, 9);
Serial pc(USBTX, USBRX);
int last_x = 0;
int last_y = 0;
int main()
{
    mse.initialise();
    lcd.background(0x000000);
    while(1)
    {
        int x = (int)mse.metric_x(1);
        int y = (int)mse.metric_y(1);
        y = -y;
        if((x < 2)||(y < 2))
        {
            continue;
        }
        lcd.pixel(last_x, last_y, 0x000000);
        lcd.pixel((last_x+1), last_y, 0x000000);
        lcd.pixel(last_x, (last_y+1), 0x000000);
        lcd.pixel((last_x+1), (last_y+1), 0x000000);
        lcd.pixel(x, y, 0xFFFFFF);
        lcd.pixel((x+1), y, 0xFFFFFF);
        lcd.pixel(x, (y+1), 0xFFFFFF);
        lcd.pixel((x+1), (y+1), 0xFFFFFF);
        last_x = x;
        last_y = y;
    }
}

The following link is to a video of the cursor http://mbed.co.uk/projects/cookbook/svn/PS2Mouse/doc/Mouse%20cursor.avi

API

Follow this link to the PS2Mse library:

http://mbed.co.uk/projects/cookbook/svn/PS2Mouse/trunk

PS2Msea PS2 Mouse interface
Functions
PS2MseCreates an instance of the PS2Mse class.
rdread a single byte without ignoring parity and START/STOP bits
wrwrite out a command
rd_movementread the movement vectors and button statuses
resetreset mouse
set_defaultsset mouse defaults
enable_data_reportingenable movement data packages to be sent from the mouse
initialiseconfigure the mouse
metric_xconverts x-axis movement vectors into metric
metric_yconverts y-axis movement vectors into metric
button_statusturns the various button flags on and off depending on the status of the buttons

More Info

For some more information on how a mouse works, take a look at the following sites:

Have Fun!

Dan W