Today I discovered why I have been having a few compatibility problems with my Playstation interface code.
The PSX uses a SPI bus. The device is supposed to put data on the bus when there is a high to low transition, then read the command on the low to high change. Sure enough the official controller sets the data line within 0.3us of the clock transition.
The problem is that some revisions of the PSX hardware don’t wait for the low to high transition to read the data line. They read at some random point during the clock cycle.
It seems to be some kind of bug because Sony fixed it in later revisions. That is of course assuming that the information on the net about the controller protocol is correct. It may be that the controller is supposed to assert the data line within a few hundred nanoseconds but that seems somewhat unlikely. It would force you to use a hardware SPI bus and thus limit the choice of microcontroller. Maybe Sony don’t care about the needs of third party developers…
I saw a PSX dev-kit for sale last year and wish I had it now. Oh well, it’s sorted now. Make sure the data is there before the transition, just like the PSX does with the command line, and it works.
Anyway,
9 Comments
Great Finding! Keep on such a good work!
Jochen
Bleh. I’m having trouble with the stupid SPI thing using an Atmel chip. I can do the data transfer by manually adjusting lines and and sampling, but I have yet to figure out what combination of register settings will make the SPI interface work.
Any tips?
Getting the AVR’s hardware SPI interface working should not be difficult. It will be a lot easier to debug if you have a logic analyser.
Unfortunately I don’t have an analyzer, but I did manage to find out what my problem was. I didn’t realize I was sending MSB instead of LSB. My init code looks like this:
DDRB |= (1 << PB4) | (1 << PB5) | (1 << PB7); // Set SPI out, clock and slave select for output
SPCR = (1 << SPE) | (1 << MSTR); // Enable SPI, set to master
SPCR |= (1 << CPOL) | (1 << CPHA); // Set on fall, sample on rising
SPCR |= (1 << DORD); // LSB first
SPCR |= (1 << SPR1); // SPI clock: 62500 Hz. Best stable speed in practice.
I'm literally just throwing byes at the SPI bus without pauses, so I didn't get stable data until I went to very low speeds. I think I can take the performance hit in my application.
You should be able to get orders of magnitude faster than that. Could be an issue with the hardware side of things.
I had a strange issue with I2C where it only seemed to work at extremely low speeds, and even then not reliably. It turned out to be a failed pull-up resistor on one of the lines. I have never had a resistor fail in a non-obvious way before (i.e. smoke).
For SPI… Capacitance issue maybe? Are you using breadboard? How about the other device, could it be misconfigured or something? SPI should do 10MHz without problems, faster with a bit of effort.
It’s for a computer science final project. I’ve just soldered jumper wires from a junked PlayStation controller port to an Atmel STK500 dev board. I don’t need to do better, but I’m curious about how to fix it.
Since this board is a lender from campus, all sorts of things could be wrong with it. I’ve got an Arduino with the ATMEGA328 on it I might fiddle with once this project is behind me.
The reason I dialed back the clock rate was because I noticed that at higher clock speeds (<250KHz PS1 rate), I get jitter on my output LEDs, whereas if I use a lower clock they hold at solid brightness for each button output. Odd I know, but it works.
I'm using the stock 1MHz clock since I need a 1MHz oscillator for the Commodore SID chip I'll be using. Unless there's a clock divider for the output, but that's getting off topic.
I'll invest much more effort when I continue doing this stuff in my spare time, but considering how green I am with MCUs, I'm very happy with my results even if a bit slow.
Keep in mind that the PS1 used 125KHz. The PS2 doubled it to 250KHz, but will fall back to 125KHz if the peripheral does not identify itself as being a PS2 one.
A final update on this since the project is long past me, it was in fact a faulty pull-up. It outright died during my presentation, but once I threw a spare 10K resistor to +5 everything was exceedingly happy.
That was a hairy presentation :D
I had a resistor fail when working on a clock with I2C interface. Took me a while to find it as it is not a very common fault. I now have an oscilloscope which makes that sort of thing a lot easier.