|
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
|
|