PS2 controller timing details

Hi Beth, Jim,

I found and re-read your “PS2 Robot Control: Establishing Communication” paper.

lynxmotion.com/images/html/build036.htm

As I mentioned on another thread, I was able (amazing how fast) to slightly modify Jim’s BS2 code and compile it (PBP) for my 18F4550 board.

I see clock, command and select (att) signals, but no DATA!

At least I got to see the timing signals (from the 'bot uP side). But if I’m not seeing incoming data on the 'scope, are they really correct since the PS2 is not responding??

The timing agrees with other descriptions I’ve read. Command data changes correctly in reference to the clock. Select is active low for the exchange. Your diagrams leave the Ack line disconnected.

Your example is for a WIRED PS2 Robot Controller. Does that make a difference? Also, I didn’t connect 7.2v; I assume it’s just for the vibration motors?

I’ve rechecked my wiring, I’ve got good 5v, a 1K pull-up resistor on the data line (the MOD mentioned on another thread), and turning on the joystick causes the xcvr module to stop flashing the right LED, and go to steady ON.

I’m beginning to think the PS2 is bad. Any Ideas?

Best regards,

Alan KM6VV

Some but not all wireless PS2 controlers need the accesory power connected. You can ussually just attach it to 5v instead of 7.2v.

Sorry I missed this yesterday. I can tell you the Lynxmotion PS2 controller does not use the green wire. We have opened the receiver and the pad that the green wire goes to doesn’t go anywhere. But I agree with Acidtech I have used some brands that required it.

The only advise I can give you is to maybe get a controller that can talk to the PS2 controller to monitor the pulses sent and received as a learning tool.

Hi Jim,

No problem, you have enough to watch!

I tried 7.2 volts on that 2nd power pin. No difference. I was almost ready to open it up and chase out the trace.

I probably just need to run on a slower processor! Even the PBP code may be too fast (humm, it’s compiled too). I think SHIFTOUT runs at full tilt of the processor speed, it appeared to ignore my OSC DEFINE. I’m thinking of getting a Radio Shack (uck) PS2-to-USB adaptor. Maybe I can get that to talk. As a last resort, and as you also advise; get a full playstation!

I’m obviously missing something! If I can just SEE SOME data ('scope), then I can easily work out the timing.

Was there a shift between 'bot boards with an inverter in the clock lead (I tried inverting the clock too)?

When using '595 and '597 shift registers to do SPI, I found that I had to use an inverter on the receive (74HCT597) side’s clock line, I couldn’t use the same clock for both!

Thanks for your help,

Alan KM6VV

The inverter was only for basic stamp processors because the stamps version of shiftin didn’t have the ability to invert the clock. The BS2 only worked with true blue Sony tethered controllers, and aftermarket versions were hit and miss at best. Even when it worked the right vertical stick would never read accurately due to another shiftin limitation. To add to the confusion the inverter on the Bot Board’s PS2 port was too slow to use with an atom (out of convenience) so we dropped it.

Well I’m starting to see some data. Turns out I needed an initial delay after taking the select line low. I’m only getting the mode back, and an occasional 5Ah as I modify some of the timing delays.

I suspect it has something to do with the “idle” command (?) that needs to be sent after the 01h and 43h commands. I’m working on it!

Alan KM6VV

Wee Hoo! :wink:

Hi Jim,

My PS2 is now working on a 40MHz PIC18F4550! Funny I couldn’t just compile and run your BASIC PS2 examples with PBP. I guess they may do their SHIFTIN/OUT differently. Maybe if I get time, I’ll go back and figure that out. Anyone on the Lynxmotion list using PBP (PIC BASIC PRO) and interested in the PS2 (joystick) controller?

I’ve also gotten my port of the BASIC Atom code over to C working. At least, I can see the detection of various commands, and the operation of the IK calculations. the joint angles are generated, and I’ve got SSC32 messages being generated. Nothing to compare it to yet, so I’m hoping later this week to run some servos with them!

Alan KM6VV

KM6VV, could you post your code?

I have been trying to get two different wireless ps2 controllers running with another microcontroller (prop), and I have had no luck with it yet. I have my code emulating a playstation almost exactly, with nearly exactly 2us half clock cycles. I also tried applying voltage to the +7.2V/9V line (depending on where you look for the pinout) but my two wireless controllers still don’t send any data. It works fine with two different wired controllers (regular dualshock, chameleon wired), but not with my two other wired controllers (predator wireless, chameleon wireless w/ channel selector). Right now I am looking for other ideas to try to get these wireless controllers working.

Hi (?),

Here’s the critical PS2 routines in Hi-Tech C on an 18F4550 PIC.
I’ve only run the “Official” Lynxmotion PS2 controller; and a Pelican I bought at Circuit City. (The Lynxmotion is better). Both are wireless.

The information on timing I’d read and implemented previously (change data on low-going clock edge) for the PS2 was not working for me (CLK low BEFORE setting up CMD bit). I’d get the ID, but that’s about all, perhaps an occasional glimpse of the following data.

Taking the CLK line low AFTER setting CMD works for me. As there are conditional statements in the ShiftInOut() routine, I choose to keep them as balanced as possible so that waveforms are more observable on a 'scope.

You can put a call to the ShiftStringOut() routine in a tight loop (PS2_SPItest()) and trigger on the SEL line (low going edge). Take out the 50 uS delay to speed things up (easier viewing on the 'scope). I just send the data out to the comm port in a printf().

Hope this helps!

Alan KM6VV

[code]/----------------------------------------------------------------------/
/* DualShock SPI bit defines */

#define DAT PORTBbits.RB0
#define CMD PORTBbits.RB1
#define SEL PORTBbits.RB2
#define CLK PORTBbits.RB3

#define DELAY 2 /* changed from 1 (Lynxmotion) to 2 for Pelican */

#define ClockHi 1
#define ClockLow 0

/* Mode Numbers

  • 41 --> Digital mode
  • 73 --> analog mode
  • F3 --> DS2 native mode
  • data comes back [0x73, 0x5A, 0xFF, 0xFF, 0x80, 0x80, 0x80, 0x80]
    /
    /
    ----------------------------------------------------------------------*/
    void ShiftStringOut(char *StrOutPtr, char *StrInPtr, unsigned char Length)

/*

  • Routine to shift out a number of PS2 SPI command bytes and

  • simultaneously read back responses.

  • call with pointer to string of CMD bytes (StrOutPtr) and number of

  • command bytes in Length.

  • Returns data in StrInPtr.

  • 08/09/07 alm
    */
    {
    unsigned int i;

    SEL = 0; /* Select Controller /
    delayMicrosec(20); /
    initial “wakeup” */

    for(i = 0; i < Length; i++)
    {
    *StrInPtr++ = ShiftInOut(StrOutPtr++);
    delayMicrosec(40); /
    between cmd bytes */
    }

    SEL = 1; /* Deselect Controller */

    delayMicrosec(50); /* between cmd delay (need?) */
    }

/----------------------------------------------------------------------/
unsigned char ShiftInOut(unsigned char SendChr)

/*

  • Routine to send commands and receive data from PS2 via SPI

  • Shift out (LSB first) a byte to SPI

  • and simultaneously shift in (LSB first) a byte

  • Call with byte to send.

  • Returns byte read.

  • 09/02/07 data changes BEFORE negative going clock edges

  • Observed 312K clock rate, 1 uS clock pulse width
    */

    {
    unsigned char i, mask;
    unsigned char RcvChr;

    RcvChr = 0;
    CMD = 1;

    for(i = 0, mask = 1; i < 8; i++, mask <<= 1)
    {
    if(SendChr & mask) /* output a data bit */
    CMD = 1;
    else
    CMD = 0;

     CLK = ClockLow;		/* generate 1 uS clock pulse */
    
     delayMicrosec(DELAY);
    
     CLK = ClockHi;		/* Clock the Bit */
    
     if(DAT)			/* input a data bit */
       	RcvChr |= mask;
     else
       	RcvChr &= ~mask;	/* for balance of inst time */
    
     delayMicrosec(DELAY);
     }
    

    CMD = 1;

    return(RcvChr);
    }

/--------------------------------------------------------------------/
void PS2_SPItest(void)

/*

  • Test Loop Function for PS2 routines
    */

{
int i, j, loc;
unsigned char data[9];
unsigned char cmd[9] =
{0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

do
{
i = 9; /* end of the list */

ShiftStringOut(cmd, data, i);

/* print the data, start with mode (data[0] is ignored) /
/
use last index to stop at */

for(loc = 0, j = 1; j < i; j++)
	loc += sprintf(&buff[loc], "%02X ", data[j]);

sprintf(&buff[loc], "\r\n");
PutString(buff);

for(i = 0; i < 40; i++)		/* 10 mS */
	delayMicrosec(250);
}

while(1);

}

/----------------------------------------------------------------------/
[/code]

I tried timing it like this but it still doesn’t seem to work.

pseudocode for shift in/out subroutine:
delay 1us
load CMD bit
delay 1us
CLK LOW
delay 2us
CLK HIGH
sample DAT
(loop again)

Before, I had the data sampled 1us into the clk LOW period (half way between clk LOW and clk HIGH). Both seemed to work the same: they both worked with wired controllers, but not with wireless.

I believe this faster routine I am using (written in assembly) is helping. Before, with the slower routine, the light on my receiver would stay constantly on. On a playstation, this light flickers when the unit is turned on, and remains off, turning on when a button is pressed on the controller. With the slower routine, the receiver was probably “timing out” and “restarting”, hence the constantly lit LED.

Right now I get the correct Status and ID bytes, but no button data. I am guessing that there is some init/startup command given to the receiver that links it with the controller, since it links fine on my playstation almost instantly after I plug it in.

HI,

I was getting the same results initially, mode, but no button or joystick data on Lynxmotion and Pelican joystick controllers. I played with delays everywhere. No luck. Then I shifted the clock pulse AFTER setting the CMD bit, and got data. Go figure. Other notes I’ve read say to set the data on the clock going low edge. My code is in C, which with delays should be pretty close to ASM. I haven’t looked at the generated ASM to see what it looks like yet.

Interesting what you’re saying about the LED indicators on a Playstation (console?). I’ve never seen one, but that does suggest we are not talking to it correctly. My xcvr LED goes steady on when being sent commands. I’m running at about 350K.

There IS an ACK line (1K pull-up?); I suppose One could watch it instead of using delays. BUT, that’s a good way to get “locked up”, waiting for an event that never happens. I suppose one could do a timeout instead of a delay. (or do early out in a delay when ACK is received).

If you have a 'scope, it would be interesting to know what baud or clock rate the PS console likes to talk at. And what “frame” rate (re-occurring data commands) is observed.

I’m interested to hear anything additional you find out!

Alan KM6VV

P.S. I don’t recall if you stated what uP you’re using? Or compiler? What all are you doing in your code, any IK?

The LED indicator I was talking about is the one on the wireless receiver. It flashes when I plug it into the PS console, and then remains off until a button/joystick is pressed/moved on the wireless controller, in which case the indicator LED starts flickering. My guess is that the controller doesnt send any data unless buttons are being pressed. This would explain why I am reading the ID and status of the wireless controller, but not getting any button info from the wireless controller (it isn’t sending it!). Currently I don’t have any “enter config” commands in my ASM version of the code. I will add that and see if the combination of config commands AND fast shift routines will work with the wireless controller.

I don’t have a scope, but I am using one of my propellers as a logic analyzer, and I can see most of what is going on. During regular transmission, the data is sent/received exactly the same with wired and wireless controllers. Perhaps I am not seeing the “config” commands which would only be sent for a few ms at start up. Also, one possibility why the data looks the same is becasue I am using the original playstation console, not ps2, and these controllers are designed for use on a ps2. I will see if I can test this out on a ps2.

I’m not using a PIC, but a Parallax “Propeller” microcontroller. However, I think they would communicate with playstation controllers in the same manner.

I will try tweaking the code more and seeing if I can see anything else going on between the console and the controllers.

Hi,

Humm, that’s different alright. I can get mode, button and joystick data (always the LAST received value) even if the joystick is off. Not useful, of course, but it demonstrates that the rcvr stores received values from the joystick. We’re of course reading the rcvr in a tight loop. My rcvr right hand LED stays on after I start to give it read commands. one could probably get by without sending the initialization sequences, but then one would have to remember to put the joystick in analog mode. I’d like to eliminate that requirement. So I need to figure out why the initialization sequences seem to be hit-n-miss. I can see when my mode shifts to 73h if I don’t do it manually. It may take a dozen passes to get it. So the timing’s not correct yet.

I think you’re correct; it might need some button press; although there seems to be some exchange between the units with the power-on of the joystick.

Bit-bang should be the same for different processors. And the delay should be fine as well. Don’t know about the old Playstation console, you could be right.

Try things like reversing the clock polarity! If you read the mode, then the data polarity should be OK.

Yeah, it’s tricky starting with NO reference point. I had NOTHING for quite a while until I added the 40uS startup delay. Then I started to see a glimmer of mode back. But it was after that step that moving the delay to AFTER the load of CMD that seemed to do it. Well, most of “it”.

Alan KM6VV

I hooked up my pelican wireless to my playstation (original) and logic analyzer (just another propeller, amazingly!) and this is what I got:
http://i17.photobucket.com/albums/b100/customhovercraft/combined.jpg

The signal was jumping all over the place, so I took 4 random print screens hoping to get a glimpse of what was going on. Things to note:

-the “get data” command is 0x43, NOT 0x42 for this controller
-F3 is the controller ID (it was in digital mode)
-some other weird things seem to be going on, not sure if it’s just the frame refreshing or what, but the attn/sel line is pulled high, seemingly in the middle of a transmission

I will try to work on this more, possibly analyzing more frames, but it is pretty time consuming. I will see if I can write a program in assembly just to “listen” to the signals and output the precise data/cmd bytes as well as how frequently they appear. I will also try this out on a ps2 to see if it’s different.

My guess right now is that the playstation alternates “get data” commands until a controller responds by pulling ACK low. Then, the console “knows” what type of controller it is and how to communicate with it.

That’s interesting. I could see 50 uS CMD word to CMD word, I can’t remember off hand how that compares with what I ended up with. “Looks close” on an eyeball check.

I’d like to know the clock hi/low times, the space between command bytes, and the rep rate of the command string (together they should define the “dead time” between strings of command bytes. Preferably for the PS2. If you zoom in, can you see the clock edge relationship to the cmd and data? I keep hearing “data/cmd changes on the falling clock edge”, but that didn’t seem to work for me.

I think you’re on to something on the alternating 43h and 42h. I believe I have seen some F3h IDs also. but very random. I qualify a received string with the mode 73h and 5Ah “data ready” before I copy it into my DualShock] array.

Adding ACK to our interface could be useful, as you’ve verified.

Good job! It’s late, I’m off to bed.

Alan KM6VV

Hi,

Well, I seem to have lost the reply I made last night. Too late, I guess!

I would suggest getting the pulse width of the clock (hi/lo times) and it’s frequency. Also the rep rate of the read command (some 9 bytes), and the “dead time” between the string of bytes, and the end of the “frame”. The time between bytes looks very close on eyeball inspection, but it would be good to nail it down. Then we can see how close you and I are to a “working” system.

You might also try to “zoom-in” and see what the data/cmd to clock-edge timing looks like. I’ve read several places (maybe they copy each other?) that data/cmd should change on the falling clock edge, but that didn’t work for me.

I think you’re on to something with the observation of the 43h and 42h commands alternating. I might try that.

I wonder if we should really be watching for ACK? I’d really like to get the DELAYS (other then 1us?) out of this code. They waste processor execution cycles! And in deterministic programs and RTOS, they’re a no-no, as they BLOCK. One time initialization sequences on startup are probably OK.

Good work!

Alan KM6VV

Here are some readings I got off a PS2 with a regular wired controller. I got a glimpse of the startup commands by plugging/unplugging the controller and taking a screen shot right as the signal started appearing. Hard to see here, but it looks like its nearly 1 us per half clock cycle with equal on/off time (so ~16us between bytes). Initial delay before first byte seems to be 20us. Also, it seems like data is transmitted slower during the config period when controller is first plugged in.

http://i17.photobucket.com/albums/b100/customhovercraft/command.jpg

I wrote a program to “trigger” on the controller being plugged in and to print out the command bytes sent immediately after the ‘trigger’. Each line has the packet #, followed by a space, and then the command sequence (taken to 9 bytes) in hex, in reverse (right most byte is the first one transmitted). I only went up to 10 lines because that’s all the print terminal I am using has, but it seems like I will have to go longer before the commands stabilize and go in to regular operation (000…004201). Here it is: (regular wired PS2 controller + PS2)

0 000000000000004501
1 000000000000004601
2 000000000001004601
3 000000000000004701
4 000000000000004C01
5 000000000001004C01
6 000000000301004401
7 00FFFFFF0100004D01
8 000000000000004101
9 00000003FFFF004F01
10 000000000200004001
184897 us

0 000000000000004501
1 000000000000004601
2 000000000001004601
3 000000000000004701
4 000000000000004C01
5 000000000001004C01
6 000000000301004401
7 00FFFFFF0100004D01
8 000000000000004101
9 00000003FFFF004F01
10 000000000200004001
184789 us

n
1 000101010101010101
2 000045010001004301
3 000000000000004601
4 000000000001004601
5 000000000000004701
6 000000000000004C01
7 000000000001004C01
8 000000000301004401
9 00FFFFFF0100004D01
10 000000000000004101
1887308 us

Below each of the 3 readings is an estimate of how much time it took to get the 10 readings. The first two seem to form a consistent pattern, but the third reading is slightly different. This may be because of the timing of things. I have one processor constantly reading the signals and another just for printing. Thus, half way through while the printing processor is accessing the data, the ‘reading processor’ may be changing the data, causing the reading to look strange. I need to fix this…

I also really need to hook up the ACK line and find a way to print more data.

So it looks like the PS2 runs at half speed while it’s doing configuration. I was wondering if it needed more time between commands, but I couldn’t detect any changes.

Maybe you can use a “trigger word” to get later data (act as a “trigger delay”)?

I’ve ported from the PICDEM FS USB demo board over to a “Quick Flash” (PICBOOK.COM) 18F452 (& 18F4620 et al) board. Shouldn’t change anything, although I will be periodically sending data requests based on a timer interrupt rather then as a result of program speed. I’d REALLY like to get the SPI back to hardware; rather then have to bit-bang it! That way, I can get rid of the blocking delays needed currently. And the data collection will be in the “background” and handled more by hardware.

Yes, I suspect the ACK line might be useful as well.

Thanks for the data.

Alan KM6VV

I revised the program and got it to print up to 30 data packets, trigger on the “5A” status of the controller. However, there is only room for the first 6 command bytes, and no room for the data bytes. I can however, print 10 data packets with the full command and data bytes. Here is the format:

packet 1 packet 2 packet 3
packet 4 packet 5 packet 6

packet 28 packet 29 packet 30
<time in us it took to get all 30 packets>

I took several looks at the pattern for the wired controller right after it is plugged into a ps2, and here is a sample that represents the majority of the frames I saw:

010000004201 010101010101 010001004301 Wired DS2
000000004601 000001004601 000000004701 on GT4, PS2
000000004C01 000001004C01 000301004401
FF0100004D01 000000004101 03FFFF004F01
000200004001 000201004001 000202004001
000203004001 000204004001 000205004001
000206004001 000207004001 000208004001
000209004001 00020A004001 00020B004001
000000004101 000000004301 010000004201
000000004201 000000004201 000000004201
2035626 us
9 000301004401
10 FF0100004D01
1752212 us

And here, just for comparison, a wireless controller (I just did it once)

010000004201 010101010101 010001004301 WIRELESS
000000004601 000001004601 000000004701 PREDATOR
000000004C01 000001004C01 000301004401 on GT4, ps2
FF0100004D01 000000004101 03FFFF004F01
000200004001 000201004001 000202004001
000203004001 000204004001 000205004001
000206004001 000207004001 000208004001
000209004001 00020A004001 00020B004001
000000004101 000000004301 010000004201
000000004201 000000004201 000000004201
1534679 us

Stuff to note:
-the 00…004201 is the “regular transmission” command, which goes into effect after the26th or so startup packet is sent, meaning it takes about 26 bytes to “initialize” a controller
-wireless setup seems same as wired
-30 packets takes 1.5+ seconds, regular transmission is 60 packets/second exact (not coincidentally, ps2 video is 60 fps)

Conclusion: It seems like the PS2 console “tries” a variety of “get dat” commands and “looks” for a response from the controller (in the incoming data bytes where button data usually is). In this way, the console can find out what type of controller it is, and perhaps, the controller (wireless ones at least) can be configured to run.

I think the next step would be to print 30 packets of cmd AND dat bytes to see each controllers (wired vs wireless) response to each of these different commands.