June, 2002

When I worked on the circuitry to "automate" user-input
for "The Elder Scrolls III: Morrowind" video game, I ran
in to a snag: Some game play required moving the mouse!

This is the story of my attempt to automate the movement of 
the PS/2 mouse via another Personal Computer.


FIGURE: Interior of the Microsoft Intellimouse. (NOTE: I replaced the photo-sensors with long wires!) A mouse has two axes: X and Y. When you move the mouse from side to side, the "X" wheel inside the mouse rotates. When you move the mouse forwards and backwards, the "Y" wheel inside the mouse rotates. For arbitrary mouse motion, the "X" and "Y" wheels move according to the "horizontal" and "vertical" components of the mouse motion.
FIGURE: Optical interruptor wheels inside the mouse. Notice the holes in the wheels inside the mouse. When the wheel rotates, Infra-Red (IR) light emitted by an IR L.E.D. (Light Emitting Diode) is interrupted repeatedly, at a rate proportional to the rate of wheel rotation. Thus, the mouse knows how many "ticks" the mouse axis has moved in a given time period. Determining the DIRECTION of movement involves the use of TWO light sensors, placed very close together, along an axis parallel to the movement of the wheel. (Both sensors are in a single 3-pin component shown below.)
FIGURE: Mouse IR Light Sensor (has two IR detectors) (Center Pin: Positive collector voltage) (Left and Right Pins: Left and Right sensor output emitters) Let's call the sensors A and B. Let's say the wheel is at an angle such that the IR light is blocked from reaching both sensors. As the wheel turns, one of the two sensors will appear in the moving hole on the wheel, and will receive light. Let's say that the sensor to start receiving light is sensor A. As the wheel continues rotation in the same direction, the other sensor, say B, starts receiving light. Eventually, if the wheel continues turning, sensor A will be blocked, while sensor B still receives light. Finally, both sensors will be blocked again. Thus, the sequence is: (A,B): ..., (0,0), (1,0), (1,1), (0,1), ... If you turn the wheel in the opposite direction, the 4-term sequence reverses from the current term. With these two sensor signals we can determine rate of rotation, and the direction.
FIGURE: The Microsoft Intellimouse circuit board. (NOTE: I replaced the photo-detectors with long wires.) To understand more about how the mouse circuitry interprets the light sensors and communicates with the Personal Computer (via PS/2 signals), I studied the circuit board. The first thing to note is the microchip: "SPCP05A" (which you can read from the markings on the chip). A "Google" (WWW site) search with the text "SPCP05A" led to a manufacturer WWW site: Sunplus Technology Co. Here's a link to a local copy of the SPCP05A Data Sheet:

SPCP05A Data Sheet (PDF) [WARNING: 1.1MB]


FIGURE: SPCP05A (PS/2 3D Mouse) chip signals. The SPCP05A is actually a tiny computer! It has an instruction set, RAM and ROM, and internal timers, etc. In fact, the Sunplus Co. data sheet for this part hardly refers to the possible mouse application for this fairly versatile microcontroller. I studied the circuit traces on the mouse circuit board to arrive at the following rough schematic:
FIGURE: Approximate schematic of the Microsoft Intellimouse. (NOTE: I'm missing a few capacitors, but this is nearly perfect.) The circuit is very simple. Mouse buttons ("Left", "Middle", "Right") go directly to inputs on the chip. The three pairs of light sensors ("X", "Y", and "Z" (middle mouse wheel)) send signals directly to other inputs on the chip. The PS/2 signals "DATA" and "CLK" (clock) also correspond to I/O lines on the chip. I understood the schematic as soon as I finished drawing it (by following traces on the circuit board). BUT the one thing I didn't appreciate (at first) was the way the IR L.E.D.'s were connected to the microchip (pin 16: "PB1"), instead of their negative terminals (cathode) simply being connected directly to ground. THIS IS SIGNIFICANT, but I didn't realize it for several hours...
FIGURE: PS2 Mouse Schematic submitted by Bui Van Chu from Australia FIRST ATTEMPT TO CONTROL MOUSE MOVEMENT: ======================================== NOTE: The following discussion refers to motion along a single axis (such as the "X" (side-to-side) axis). The first thing I tried was moving an object between the IR LED and the sensor pair (i.e., simulating the effect of the wheel). This worked; I could move the cursor around the screen by sweeping an obstacle through the beams repeatedly (in the same direction). Then I removed the 3-pin sensor part from the mouse circuit board, and attached wires to circuit board in place of the sensor. I manually connected wire to the positive voltage to simulate sensor activity. I connected the two signals to the power according to the following pattern: (0,0), (1,0), (1,1), (0,1), ... [0==Off, 1==On] This worked. I could move the mouse cursor by this tedious connecting and disconnecting terminals in this pattern. Reversing the pattern from the current term in the sequence would move the cursor in the opposite direction. Since things were going so well, I decided to connect the wires to relays (controlled by RS-232 -- described in my first "Morrowind automation" WWW page). This would essentially allow me to do exactly what I did with loose wires: connect the sensor signals to the power terminal in the appropriate sequence. The only difference would be the fact that the human (me) wouldn't have to do the tedious connecting and disconnecting. But...IT DIDN'T WORK! After lots of tweaking of resistors and capacitors, etc, and after the passing of a couple frustrating hours, I made a weird discovery: If I was TOUCHING certain terminals in the circuit, it worked perfectly! Ah, so there must be some resistance or capacitance that needs adjusting. After another hour of trying to simulate the "equivalent circuit" for my human touch (like a Mega-ohm resistor here and there), I was stumped. It really seemed to want ME in the circuit. I tried one last thing: Connecting the circuit to a large metal object (the frame of my conference table). This didn't work directly: I had to add a dish of water, and drape three wires in the water (one wire being connected to the metal frame of the conference table), and the other wires were related to the sensor output signals. This worked perfectly. The mouse moved completely smoothly across the sceen under the control of the relays (controlled by an application running on my other PC). BUT THIS WAS MADNESS!! A dish of water? The metal frame of my conference table? I was frustrated by the insanity of it all, so I quit for the day. NEXT ATTEMPT TO CONTROL MOUSE MOVEMENT: ======================================= My next thought was that the sensors had very narrow electrical requirements. Instead of connecting a single sensor (with its two output signals) to the two chip inputs, I connected HALF of one sensor to a chip input, and connected HALF of a second sensor to the other chip input (for the same axis). This worked. I could move the mouse cursor by interrupting the light from the two separate sensors in the special pattern described earlier. The interesting new piece of information was that this worked even though I was exposing the sensors just to the ambient light of my halogen floor lamp. Apparently there was enough IR light. NEW THEORY: IR LIGHT IS MODULATED (FLASHING) After some other frustrating experiments I had a new thought: The IR light may be pulsing at a high frequency, and the chip may expect to receive this frequency. Constant light (or my simulated constant sensor output) may be rejected. I was somewhat perplexed by the fact that the ambient light of the halogen floor lamp was okay, but I knew that even incandescent lamps had detectable modulation. I tried duplicating the two-sensor experiment above, but I dimmed the halogen lamp and instead used the light of the huge flame of a gas lighter. This failed! There should have been plenty of constant IR light. Hmmmm... I tried a bright IR LED, with constant voltage, and hence constant light. This failed, too. Hmmmm... Then I tried pulsing an IR LED at high frequency and blocking the sensors according to the expected pattern. IT WORKED! That was it! The IR LED's on the mouse circuit board must be flashing at high speed, and the microchip must expect this flashing in addition to the relatively low speed of the light interruption pattern. This made total sense. By pulsing the IR LED's, and expecting this pulsing in an unblocked sensor output signal, the chip can reject any ambient IR signals from interfering with mouse operation. For example, stray light from other (constant) IR sources won't interefere with the mouse. Still, I wasn't a complete believer until I connected an audio amplifier to the sensor output, and then I let the sensor take in the ambient light cast by my halogen floor lamp. I heard a distinct tone (60 Hz). When I dimmed the lamp, the tone grew faint and finally stopped when the light was off. So, this sensor easily picks up the 60 Hz modulation in the incandescent bulb of my halogen floor lamp! When I looked at my sketch of the PS/2 mouse circuit board diagram, the significance of the IR LED's being connected to a pin on the microchip (instead of to direct current) was clear to me. The microchip controls the flashing of the IR LED's through the I/O pin, and the chip can correlate its intention to flash the ID LED's with the received sensor inputs, and thus reject any stray signals (due to non-flashing IR light). (NOTE: Correlation isn't necessary. Simply detecting a minimum number of flashing counts can be a threshold for accepting sensor input.) The weird effect of me touching the wires, or connecting wires to the metal frame of the conference table, now made sense: Ambient 60 Hz electrical noise was picked up by these large objects, and thus entered the sensor circuitry, essentially providing the "flashing" modulation required by the microchip. ALTERNATIVE IR SENSOR DEVICES: You can find special IR sensors, packaged in transistor-like form with three leads, that are "tuned" to specific modulated IR light frequencies (e.g., 38 kHz).
FIGURE: Tuned IR Light Sensor (maximum sensitivity to 38 kHz light modulation) They must have some sort of low-frequency bandpass circuitry built in to the package, along with the IR photo-transistors. Thus, you can pulse an IR LED at a very low rate (e.g., 100 pulses per second), but when the IR LED is pulsed you can have the light flashing at a much higher frequency (e.g., 38 kHz). The low pulse rate reduces the chance for transmission errors, since you have each "bit" of data for a long time. Meanwhile, the higher frequency "carrier" will prevent low-frequency IR noise (ambient light changes), and constant ambient IR light, from being mistaken for the pulses. Anyhow, I verified that the IR sensors in the Microsoft Intellimouse do NOT have such modulation filters. (I tested the response of the sensor to sunlight, far away from any electrical equipment, and the sensor responded exactly as it did with incandescent lamps and (un-)modulated IR LED's. Darkness: High resistance, high voltage difference; Light: Low resistance, low voltage difference). So, any modulation checking must be done by the microchip in the mouse circuitry. The following sketch illustrates the difference in sensor signals for constant IR LED light and flashing IR LED light for the different phases of mouse wheel turning.
FIGURE: Sensor output signals for the constant IR light case and the flashing IR light case. TOTALLY NEW APPROACH TO SIMULATING MOUSE INPUT: =============================================== When I first bought the "BASIC Stamp 2" board (described on one of my other WWW pages), I intended to connect digital outputs somewhat directly to the mouse sensor signals. Thus, I could do exactly what the sensors were doing, without the electrical noise of mechanical relays. (This was before I realized that it wasn't the noise of relays that was the problem, but a lack of modulation on the sensor lines.) After figuring out all of the stuff mentioned above, I was all set to use the "BASIC Stamp 2" board to precisely control the mouse circuit board (by simulating sensor signals). But then I had a new idea: The "BASIC Stamp 2" board is so "smart", why not talk to the PC directly (i.e., through the PS/2 mouse port). THE PS/2 PROTOCOL: ================== The majority of personal computers made today have "PS/2 ports" for the mouse and keyboard. The PS/2 port has 4 signals: (1) CLOCK; (2) DATA; (3) +5V; (4) GROUND. The PS/2 port allows devices to send data to the host, and the host may send data to the devices. All parties on a PS/2 port (typically just a device and the host) must share the signals and must detect if another party is currently using the signals. How can signals be shared? A signal (such as CLOCK or DATA) is usually "floating" high, meaning that the signal is connected to a positive voltage through a resistor with high resistance (e.g., 4 kilo-Ohms). Thus the signal is interpreted as a logical "high" by all listening parties. Any party can pull the line low (via TTL logic) when the party intends to send data. When a party finishes sending a packet, it lets go of the signals indefinitely, so they float high again. To send data from a device (e.g., mouse or keyboard) to the personal computer, you must send data in 11-bit packets, consisting of the following bits: (1) Start Bit ("0"); (2) 8 data bits (LSB first); (3) Parity Bit ("odd" parity); (4) Stop Bit ("1"). Note that "odd parity" is when the total number of "1"'s in the data bits and parity bit combined is an odd number. The following diagram illustrates the transmission of a single data packet:
FIGURE: PS/2 Protocol: Device to Host (PC) Packet The DATA line should be set to the proper value before bringing the CLOCK line low. The DATA value should remain set until the CLOCK line is returned back to high. When the CLOCK line is confirmed to be high, the DATA value can be changed to the next bit value. The typical clock speed is relatively slow, about 10 kHz to 17 kHz. That's 100 microseconds down to 70 microseconds for each clock period. The scenario of the host (PC) sending data to a device is similar to the device sending data to the host, but in all cases the DEVICE controls the CLOCK signal during data transmission itself. Also, a data bit sent from the host (upon device setting CLOCK low) should be latched when the device lets the CLOCK signal make a transition to high. A "Google" search turns up plenty of references to PS/2 signals and details about the protocol. PS/2 MOUSE DATA PACKETS: ======================== When the computer boots up, the operating system starts and eventually communicates with the mouse to determine the type of mouse. By default the mouse may behave like a generic PS/2 mouse. However, if the operating system determines that the mouse is actually a "3D PS/2 mouse" (e.g., mouse with a wheel), it can tell the mouse to change to the 3D PS/2 mouse protocol. When you move the mouse, or press or release mouse buttons, the mouse circuitry sends data to the host (PC), indicating what state changes have occured since the previous state indication. The generic PS/2 mouse sends the following three packets to the host:

------------------------ D7 D6 D5 D4 D3 D2 D1 D0 (NOTE: D0 bit (LSB) sent first) ------------------------ (1) YV XV YS XS 1 0 R L (overflow, sign, buttons) (2) X7 X6 X5 X4 X3 X2 X1 X0 (X movement; -128 to +127) (3) Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 (Y movement; -128 to +127) L = Left Button State (1 = pressed down) R = Right Button State (1 = pressed down) XS = Direction of X movement (1 = LEFT) YS = Direction of Y movement (1 = UP) XV = Overflow of X movement value (1 = X overflow occured) YV = Overflow of Y movement value (1 = Y overflow occured) X7,...,X0 : X movement; 8-bit 2's-complement signed byte (-128 to +127) Y7,...,Y0 : Y movement; 8-bit 2's-complement signed byte (-128 to +127) Here are examples of data sent to the host (PC): ------------------------------------------------ (NOTE: Least-significant bit of each data byte is sent first.) Move Left 1 unit : 0x18, 0xFF, 0x00 Move Right 1 unit : 0x08, 0x01, 0x00 Move Down 1 unit : 0x28, 0x00, 0xFF Move Up 1 unit : 0x08, 0x00, 0x01 Press Left Button : 0x09, 0x00, 0x00 Release Left Button : 0x08, 0x00, 0x00 Press Right Button : 0x0C, 0x00, 0x00 Release Right Button : 0x08, 0x00, 0x00 It is very common to have a "3D PS/2 mouse" (e.g., with a mouse wheel that also acts as a middle button). Such a mouse sends four data packets to the host (PC). ------------------------ D7 D6 D5 D4 D3 D2 D1 D0 (NOTE: D0 bit (LSB) sent first) ------------------------ (1) YV XV YS XS 1 M R L (overflow, sign, buttons) (2) X7 X6 X5 X4 X3 X2 X1 X0 (X movement; -128 to +127) (3) Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 (Y movement; -128 to +127) (4) Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 (Z movement; -128 to +127) This is very similar to the generic PS/2 mouse, with a few additions: M = Middle Button State (1 = pressed down) Z7,...,Z0 : Mouse wheel movement; 8-bit 2's-complement signed byte (NOTE: Z value forced to a range of -8 to +7)





MY FIRST CIRCUIT TO SIMULATE PS/2 MOUSE:
========================================

The following schematic was my first working technique
to get my "BASIC Stamp 2" computer to send PS/2 mouse
data to the host (PC).


FIGURE: Schematic of circuit to allow BASIC Stamp computer to send PS/2 packets to the host (PC). Note that this circuit electrically isolates my BASIC Stamp computer from the host (PC) computer. Also note that this circuit is just to satisfy the ELECTRICAL requirements of PS/2 data transmission (from device to host). Thus, I can send PS/2 KEYBOARD messages using this same circuit if I plug in to the PS/2 keyboard port on the host (PC)! Since RECEIVING signals is generally non-invasive (i.e., listening doesn't interfere with electrical signals), the only thing required to allow the BASIC Stamp computer to receive the PS/2 CLOCK and DATA signals is a direct connection from those signals to other BASIC Stamp I/O pins (configured to be inputs). I'd try some kind of buffering -- but I definitely can't use an opto-isolator directly, since that would put a load on the "floating" signals (thus "sinking" them!). I could use the +5V to power a buffer, then then use the buffer output to drive opto-isolators that ultimately send signals to the BASIC Stamp I/O pins (configured as inputs). The following image shows my BASIC Stamp 2 computer connected to a circuit matching the schematic above.
FIGURE: BASIC Stamp 2 connected to PS/2 mouse port via opto-isolator circuit. The following BASIC Stamp 2 program (PBASIC) was my first successful attempt to control the PS/2 mouse via the BASIC Stamp 2 computer. The program just makes the mouse move back and forth along a small diagonal line.

'==================================================================== '{$STAMP BS2} 'STAMP directive (specifies a BS2) DIR0 = %1 'Set pin 0 to OUTPUT DIR1 = %1 'Set pin 1 to OUTPUT OUT0 = %0 'Set DATA line high (pin low) OUT1 = %0 'Set CLOCK line high (pin low) tempData VAR BYTE tempParity VAR BYTE '-------------------------------------------------------------------- MainLoop: tempCounter VAR WORD FOR tempCounter = 0 TO 10 tempData = $28 GOSUB TransmitPacket tempData = $01 GOSUB TransmitPacket tempData = $ff GOSUB TransmitPacket tempData = $00 GOSUB TransmitPacket PAUSE 100 NEXT FOR tempCounter = 0 TO 10 tempData = $18 GOSUB TransmitPacket tempData = $ff GOSUB TransmitPacket tempData = $01 GOSUB TransmitPacket tempData = $00 GOSUB TransmitPacket PAUSE 100 NEXT GOTO MainLoop STOP '-------------------------------------------------------------------- TransmitPacket: GOSUB ComputeParity 'First, compute parity tempData = ~tempData 'Invert data bits tempParity = ~tempParity 'Invert parity bit '==== Start Bit ==== OUT0 = %1 'Set data line low (output high) PULSOUT 1, 25 ' Pulse line 1 for (25*2) = 50 usec '==== Data Bits ==== OUT0 = tempData.BIT0 PULSOUT 1, 25 OUT0 = tempData.BIT1 PULSOUT 1, 25 OUT0 = tempData.BIT2 PULSOUT 1, 25 OUT0 = tempData.BIT3 PULSOUT 1, 25 OUT0 = tempData.BIT4 PULSOUT 1, 25 OUT0 = tempData.BIT5 PULSOUT 1, 25 OUT0 = tempData.BIT6 PULSOUT 1, 25 OUT0 = tempData.BIT7 PULSOUT 1, 25 '==== Parity Bit ==== OUT0 = tempParity.BIT0 PULSOUT 1, 25 '==== Stop Bit (high) ==== OUT0 = %0 ' pin low is DATA high PULSOUT 1, 25 PAUSE 1 ' Necessary? Provides 1 msec gap between packets... RETURN '-------------------------------------------------------------------- ComputeParity: tempParity = $01 tempParity = tempParity + tempData.BIT0 tempParity = tempParity + tempData.BIT1 tempParity = tempParity + tempData.BIT2 tempParity = tempParity + tempData.BIT3 tempParity = tempParity + tempData.BIT4 tempParity = tempParity + tempData.BIT5 tempParity = tempParity + tempData.BIT6 tempParity = tempParity + tempData.BIT7 tempParity = tempParity & $01 RETURN '====================================================================



This program works perfectly.  I let it run for hours, and it
flawlessly made the mouse cursor move between two exact locations on
the screen.  This is what I was looking for:  precise control
of the mouse so that I can interact with software (like the
"Elder Scrolls III: Morrowind" video game).  Crazy, man!

After roaming the WWW I discovered that someone else used
a BASIC Stamp computer to interface PS/2 (simulating a 
keyboard).  This person used the PBASIC instruction 
"SHIFTOUT" to handle the CLOCK and DATA signals, which
is really great.  This would make my "TransmitPacket"
subroutine much shorter, perhaps 5 lines of code total!

I also saw that other people used TTL buffers, with
inputs connected directly from PS/2 signals (CLOCK 
and DATA), and outputs connected directly to pins
on the microcontroller chip.  In the same circuit,
output lines from the microcontroller went directly
to the base pins on transistors which had their
collectors connected directly to the PS/2 signals.
All of this direct coupling of different circuits
seems like a bad idea to me, lest one circuit fry
the other.  I don't know what I'd do if I fried
the PS/2 port on my PC.  Buy a new motherboard,
I guess!  An excuse to upgrade.  I don't think
a PS/2 port motherboard meltdown is likely, but I
did instantly shutdown my computer when I accidentally
short-circuited the +5V and GROUND signals going
to the PS/2 mouse.  Maybe it's a feature!  I could
add a new button to the mouse that just 
short-circuits the mouse power for instant shutdown
of the PC. ;-)


  Here's the link to the information regarding
the use of SHIFTOUT for the PS/2 protocol:

http://ourworld.compuserve.com/homepages/steve_lawther/keybinfo.htm

Look for the link:

" KEYBTST.ZIP gives a very basic program for the parallax ----------- BASIC stamp II, to send key-codes to the PC's keyboard port. It also gives a write-up of the XT and AT keyboard interfaces (although IMO some details could be wrong / different to the keyboards I've looked at). " LOCAL CACHED COPY: keybtst.zip [10.4 KB]



Another good link is this one about PS/2 mouse interfacing:

http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/PS2/ps2.htm

That's all for this installment of my grand adventure
to automate gameplay for "The Elder Scrolls III:
Morrowind".  It would be insanity if that were my
true objective, but at least I have some wacky goal to
motivate me to learn more about some pretty interesting
things.

--- Colin
cpfahey@earthlink.net
http://www.colinfahey.com