Interfacing with a mouse

From Mech
Revision as of 02:54, 16 February 2009 by Lynch (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

This article documents an unfinished work.
Content may change as the project progresses.

Overview

Ione Lynx-M9 mouse

The goal of the project is to interface the PIC184520 with a PS/2 mouse - specifically, an ione Lynx-M9 Wheel Optical mouse with a USB to PS/2 adapter. The mouse's XY coordinates will be displayed on an LCD screen and will be updated when the mouse moves.

The PS/2 connector is traditionally used to connect mice and keyboards to computer systems. The connector uses six pins: clock, data, 5V, GND and two that are not connected. The PS/2 connector is fully documented here: PS/2 connector. We used a Parallax PS/2 to Breadboard Adapter to connect the optical mouse to the PIC18. Documentation and ordering information for the adapter can be found here: Breadboard Adapter

PS/2 to breadboard adapter

On this page you will find the steps to use a PS/2 mouse's output to meet your needs. The code, circuit diagram, and notes about the interface are included. This is currently a work in progress, but should be a good foundation for those looking to build on it and be able to use a PS/2 mouse in their own projects.

PS/2 Protocol

The PS/2 protocol uses two bidirectional communication lines between the system (in this case, the PIC) and the external device (the mouse). These lines are specified as DATA and Clock and allow for host-to-device transmission and device-to-host transmission. Data is sent as bytes with 11-12 bit frames (11 for device-to-host transmission and 12 for host-to-device). The frames are made up of: A start bit, eight data bits, a parity bit (odd), an end bit, and in the case of host-to-device transmission, an acknowledge bit. This data transmission takes place based on the clock signal generated by the external device.

This is a simplified description of the PS/2 protocol. More thorough/technical explanations can be found at the following links:

Computer Mouse Wiki

Documentation of PS/2 Protocol by Adam Chapweske and Roy Show

Description of PS/2 Protocol by Adam Chapweske

Mouse Interface

Normally, when a mouse first powers on, it will send its device ID information and set default values for its sample rate, resolution and scaling. The mouse also by default disables its ability to report data until it is sent an “Enable Data Reporting” command from the host (in this case the PIC). Once the “Enable Data Reporting” bits are sent, data reporting is enabled, the mouse can send data as long as the clock and data line are not held low by the host. Typically, a PS/2 mouse will send 3 bytes of data in three consecutive data packets as shown in the diagram below:

Mouse Interface Table [1]

YV and XV are overflow flags for the motion in Y and X directions respectively where 0 means negative motion and 1 means positive motion. R is for the right button and L is for the left button where 1 equals pressed and 0 equal unpressed. X0-X7 and Y0-Y7 are binary outputs of 0 to 255, which represent how far the mouse has moved in its respective directions since the last sample (the least significant digit is on the right). Optical mice with wheels and additional buttons generally send a fourth data packet, but for this lab, that data was not needed.

The mouse sends the data within the frames described in the PS/2 protocol section. This is a visual representation of a byte of information being sent from the mouse to the host:

Byte of Data[2]

When the clock is set low, the host will wait 10-25us before reading the data stream. More information on the mouse interface may be found at the following links:
Description of PS/2 Protocol by Adam Chapweske
Description of Connector pinout for PS/2 Mouse/Keyboard by allpinouts.org

Circuit

The relevant part of the breadboard adapter data sheet can be seen below.

Breadboard adapter data sheet[3]










PS/2 circuit[4]

The mouse, as can be seen in the breadboard adapter schematic, now has four conduits indirectly attached to it. In order to operate, the mouse needs power, so the 5v and ground are used to power the mouse. The other two pins are actually used as both inputs and outputs. The mouse needs to first receive a signal before it can output a signal. The mouse also generates its own clock signal. More about this can be found in the PS2 protocol section.

Instead of using the resistors seen in the breadboard adapter schematic, it is actually preferable to use the PS/2 schematic shown at right because the PIC also needs to send data to the mouse.

The clock and data lines connect directly to the clock and data lines of the breadboard adapter. Note: there should be a resistor between the microcontroller outputs C/D and the base of the transistors. We also found that the buffers were unnecessary.

Basically, the microcontroller needs to be able to have two way communication with the mouse. So if the PIC wants to send data to the mouse, data will equal output D inverted, and Clock will equal output C inverted. Once the mouse starts sending data (and the outputs of C/D are set low), the clock and data lines are normally held at 5v, but are then set low if the mouse sends logic low. More information about this operation can be found here: PS2 Protocol

A great way to trouble shoot, debug, and see the final result is to use an LCD screen to display the information that the mouse is sending to the PIC. More information about LCDs and the flex code we used can be found here: C_Example:_Parallel_Interfacing_with_LCDs


A picture of our complete circuit can be found at right.

PS/2 to PIC circuit with LCD












Code

Our code (shown further down) attempts to display X and Y coordinate motion of an optical mouse by doing the following:
1. Set Clock low
2. Wait at least 100 microseconds
3. Set Data low
4. Release Clock (Default is high on an open collector. Setting Data low and Clock high is the host requesting to send command, and this should cause the mouse to start generating clock signals and to wait for commands from the host)
5. Wait for clock to go low (represents beginning of a clock input wave from mouse)
6. Send next bit of “Enable Data Reporting” command to mouse (The “Enable Data Reporting” command is 0xF4, or 244 in binary, sent within the 12 bit frame described in the PS/2 Protocol section)
7. Repeat steps 5 & 6 until the “Enable Data Reporting” command is completely sent and acknowledged by the mouse
8. Release Clock
9. Release Data (Clock high and Data high will put the mouse into idle mode and if Data Reporting has been enabled, the mouse should send a Data and Clock signal to the PIC when it detects button changes or motion)
10. Wait for clock to go low
11. Input Data bit into a 33 member array
12. Repeat steps 10 & 11 until the 33 member array is filled with 3 data packets worth of information (three 11 bit data packets converted into an 33 member array of 1’s and 0’s)
13. Interpret the direction bits (explained in the Mouse Interface section)
14. Interpret the X and Y motion bytes
15. Update cumulative X,Y motion and display on LCD
16. Repeat steps 1-15 indefinitely

Actual Code Used:

#include <18F4520.h>
#fuses HS,NOWDT,PUT,NOLVP
#use delay(clock=40000000)
#include "lcd_flex.c"

lcd_init();
signed int Xdir;
signed int Ydir;
int Xadd;
int Yadd;
int i = 0;
int1 data[33];
int1 interrupt = 0;
int1 enabled = 0;
signed int16 Xpos = 0;
signed int16 Ypos = 0;
int1 enabledata[10] = {0,0,1,0,1,1,1,1,0,1};       //F4, enable sending command


#INT_EXT1             // designates that this is the routine to call 
//when pin RB1/INT1 changes state

void INT1isr() {

lcd_init();  // initialize lcd
   
   if (enabled == 0)                //outputs a data bit to mouse
   {
         if(enabledata[i] == 1)        
         {
            output_low(PIN_B3);
         }
         if(enabledata[i] == 0)
         {
            output_high(PIN_B3);
         }
         i++;
   }
  
 
   if (enabled == 1)
   {
      delay_us(20);
      data[i] = input(PIN_B0);   //read a logical high or low into array
      interrupt = 1; 
   }
                               //to break out of infinite while loop
}

//PIN_B0 = data input/output
//PIN_B1 = clock input/output
//PIN_B2 = clock control         output high sets clock low
//PIN_B3 = data control          output high sets data low

//==========================

void main(){

lcd_init();  // initialize lcd

output_high(PIN_B2);          //sets up mouse for host to mouse communication
delay_us(120);
output_high(PIN_B3);
output_low(PIN_B2);


enable_interrupts(INT_EXT1);
enable_interrupts(GLOBAL);
ext_int_edge(1, H_TO_L); //interrupt on INT1/RB1 pin for high to low  transition
                                

while(enabled == 0)        //mouse data sending initially disabled
{
   if (i > 9)              
   {
      enabled = 1;         //sending from mouse should be enabled at this point
      output_low(PIN_B3);
   }
}

output_low(PIN_B2);
output_low(PIN_B3);               //mouse idle

while (true)
{
   enable_interrupts(INT_EXT1);
   ext_int_edge(1, H_TO_L);      //interrupt on INT1/RB1 pin for high to low 
                                 //transition

   //printf(lcd_putc,interrupt);
   for(i = 0; i <= 32; i++)       //should obtain a 33 member array of 1s and 0s
   {   
      while (interrupt == 0)
      {         //while loop goes until interrupt occurs
      //printf(lcd_putc,"in second while loop\n");
      }
      interrupt = 0;                //reset interrupt
   }
   
   disable_interrupts(INT_EXT1);
   
   output_high(PIN_B2);      //inhibit furthur transmission                  
            
   if (data[4] ==1) 
   {
      Xdir = 1;               //movement in positive x direction
   }   
   
   if (data[4] == 0)
   {
   Xdir = -1;                 //movement in negative x direction
   }
   
   if (data[3] == 1) 
   {
   Ydir = 1;                  //movement in positive y direction
   }
  
   if (data[3] == 0)
   {
   Ydir = -1;                 //movement in negative y direction
   }
   
   for (i = 0; i <=7; i++)
   {
      Xadd = Xadd + data[12+i]*(2)^(i);   //convert x motion binary input to #
   }
   
   for (i = 0; i <=7; i++)
   {
      Yadd = Yadd + data[23+i]*(2)^(i);    //convert y motion binary input to #
   }
   
   Xpos = Xpos + Xadd*Xdir;               //cumulative x motion
   Xadd = 0;
   
   Ypos = Ypos + Yadd*Ydir;               //cumulaive y moution
   Yadd = 0;

   printf(lcd_putc, "\f(X,Y) \n = (%ld,%ld)", Xpos,Ypos); //displays coordinates

   output_low (PIN_B2);    //mouse idle again, ready for more data
}
} 

Unresolved Issues

Our group was unable to display the motion of an optical mouse on an LCD screen. After a great deal of troubleshooting, we have come to the conclusion that our interrupt service routine algorithm or microcontroller is simply not fast enough to receive and send data in time with clock signal generated by the mouse. The mouse clock signal is essentially a 10-16.7 kHz square wave. Each high and each low on the clock signal would last roughly 40 microseconds and our interrupt service routine (which was supposed to trigger every time the clock went from high to low) tended to miss or skip several signals at a time. This problem prevented the mouse from ever receiving an “Enable Data Reporting” from the PIC and thus the mouse never outputted data to the PIC.

Suggested solution: Use a faster microcontroller or develop a more efficient interface program.