This article has been revised to include fixed and up to date
information after I actually plugged the gamepad to an oscilloscope. Now it should
be error-free.
Ever heard of the Gravis Gamepad Pro ? It's a gamepad using the old-fashioned
PC gameport. It looks quite like the original Playstation controller and has a
very solid build quality.
Those of you who know about the gameport limitations will quickly notice that
there must be something non-standard about it: there are 10 buttons, while the
gameport only allows 4. Even better, you can actually use 2 gamepads at the same
time on a single port.
There are several modes accessible with a switch under the gamepad. These are
1-player, 2-player, and GrIP. In 1 player mode, you get 2 axis and 4 buttons.
In 2 player mode, you get 2 axis and 2 buttons, and you can use 2 gamepads.
In GrIP mode, each gamepad can use all 10 buttons, but this is not compatible
with the games expecting a standard joystick.
I have some of these gamepads around, but my PC don't have a gameport anymore.
Since I'm not very happy with replacement hardware (I tried the Logitech Precision
USB gamepad, but it doesn't look as nice and colourful), and the USB version of
the Gravis Gamepad is impossible to find (and less beautiful with the black plastic,
I'm thinking about building an adapter for these gamepads to plug them on an USB port.
Of course, without opening and rewiring them. Not only this would void the long
expired warranty, but I may still want to plug these gamepads to the system they
were intended for (my 1995 Pentium 166 MMX).
There is some information on the internet about the protocol, but it's not easy to find.
Heer is what I could get : a textfile with some info and
the Linux driver for these joysticks.
Since the textfile does not say everything the driver does, here are some notes that duplicate the text file and add the info from the driver.
I checked this with an oscilloscope, so I believe the information to be correct. But I may have missed something.
First, the gameport pinout. It's a SUB-E 15 connector. The following pins are relevant:
- 1,8,9,15: 5V power (my gamepad accepted down to 3V, below that it stops generating the clock signal)
- 4,5,12: GND
- 2,7,10,14: buttons 0,1,2,3
(the other pins are axis 0, 1, 2, 3, they are not used in GrIP mode).
When you use only one gamepad, buttons 0 and 1 are used as data lines. Button 0
is a 20 to 25kHz clock. On each falling edge of this, you can read the state of button 1.
Frames are 24 bits long and is formatted as follows:
0 | 1 | 1 | 1 | 1 | 1 |
0 | Select | Start | R2 | Blue |
0 | L2 | Green | Yellow | Red |
0 | L1 | R1 | Down | Up |
0 | Right | Left |
The frame starts with a start bit, then 5 bits set high. Since the button data
is split in 4-bit words with a 0 interleaved, there can't possibly be 5 set bits
anywhere else, this makes it possible to detect the start of a frame.
Transmitting a full frame at 20KHz will take about 1.2ms (slightly more than 1.5ms on
my test gamepad). This is more than fast enough. It's likely that Gravis drivers on windows
only polled the gameport only 20 or 25 times per second (or even less), and waited up to 2ms
for a frame start. This was the only way for them, because these gameport buttons are not
triggering interrupts.
When there are 2 joysticks connected, the second one uses buttons 2 and 3
exactly the same way. The Gamepad Pro has a pass through connector that swaps
buttons 2 and 3 with 0 and 1 for the second device, like any Y-doubler joystick
cable does.
I'm planning to use an STM32f3 microcontroller to decode this. The protocol
is close to SPI, unfortunately microcontrollers able to handle 24-bit SPI frames
are not common. Moreover, the start of frame is hard to detect so synchronization
could be a problem. Bit banging the protocol is a better solution, we just have to
use the clock line as an external interrupt and read the bits in the interrupt handler.