Proof of concept: PSX -> Whatever converter

#1

Mostly I wanted to post this so I’d have a permanent working copy somewhere. :slight_smile: I’ve been playing around with an Arduino, a cool little microcontroller board.I know a lot of people want a solution for making converters that just aren’t found out there, like a non-dumbass PSX->NeoGeo converter, especially for SuperGun projects, and hopefully for a decent PSX->Xbox360 converter. So, to kill two birds with one stone, that’s what I’ve been trying to do with the Arduino.

This is the code that successfully reads the state of the controller. It returns the two bytes from the pad that report the state of the d-pad, start, select, and the eight buttons. Successfully tested with:

-Namco stick
-Sony digital pad
-Sony DualShock pad
-Sony DualShock 2 pad

I’ll be working as I can on a small generic board. Getting ones made for SuperGun/NeoGeo support will be a priority, but I’m trying to make it as generic as possible so using it for rolling your own converters, as well as using it for Saturn->Whatever converters are possible as well. I’ll also be trying to use the ideas for button remapping that I use with the UPCB. Chances are Start+Select will be used to start the remapping process.

If you have an Arduino and want to test this out, wire up a controller to the Arduino digital pins listed in the second group of #defines. I used a cut extension cable connected to a protoshield.


#include <stdlib.h>
#define SQUARE 7
#define CROSS  6
#define  CIRCLE  5
#define  TRIANGLE  4
#define R1  3
#define L1  2
#define  R2  1
#define L2  0



//the arduino pin # for the spi lines
//needed
#define DATAOUT 11 //MOSI pin CMD
#define DATAIN 12 //MISO pin DATA
#define SPICLOCK 13  //SCK pin 
#define SLAVESELECT 10 //SS pin
#define ACK 7

unsigned char spi_transfer(volatile unsigned char data)
{
  SPDR = data;
  while (!(SPSR & (1<<SPIF))) {};
  return (unsigned char) SPDR;  
}

void setup()
{
  Serial.begin(9600); 
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(SLAVESELECT, OUTPUT);
  pinMode(ACK, INPUT);
  digitalWrite(SLAVESELECT, HIGH);//we're not talking to the
  //PSX controller yet.
  //setup SPI control register SCPR=0111 1110
  //bit 7 - Interupt Enable- Not messing with interupts, 
  //so leave at 0
  //bit 6 - Enable - Need SPI, so set to 1
  //bit 5 - DORD - PSX sends LSB first, so 1.
  //bit 4 - MSTR - Arduino is the SPI master, so 1.
  //bit 3 - CPOL - PSX is idel high, so 1
  //bit 2 - CPHA - Sample at lead or trail edge. 
  //not 100% sure about CPHA. Trying at 1
  //bit 1 & 0 - 10
  //we want a 250KHz clock. Assuming a 16MHz clock, default
  //on the Arduino, we need 1/64 of Fosc. To get this, we
  //need the SPR1=1, SPR0=0, SPI2X=0
  //SPCR = 0b0111111;
  // EDIT: Trying with the 1/64 of Fosc didn't work on first party digital pads
  // but trying with 1/128 does.
  SPCR = 0b01111111;
  //SPSR - only thing we need is for bit 0 (SPI2X) to be 0
  SPSR&=0b11111110;//bit 0 is only writable bit, so no need to worry 
  //bits
}

void printbyte(unsigned char data)
{
  char string[20];
  itoa(data, string, 16);
  Serial.println(string);
}

void printuint(unsigned int data)
{
  char string[20];
  itoa(data, string, 16);
  Serial.println(string);
}

void waitForACK()
{
 while(digitalRead(ACK)==HIGH);  
}

unsigned int PSXstatus()
{
  unsigned int result=0;
  unsigned char status, data, byte3, byte4, byte5;  
  digitalWrite(SLAVESELECT, LOW);
  status = spi_transfer(0x01);
  waitForACK();
  data = spi_transfer(0x42);
  waitForACK();
  byte3 = spi_transfer(0xFF);
  waitForACK();
  byte4 = spi_transfer(0xFF);
  waitForACK();
  byte5 = spi_transfer(0xFF);
  digitalWrite(SLAVESELECT, HIGH);
  result=byte4;
  result=result<<8;
  result=result + byte5;
  return result;
}
void loop()
{
  unsigned int status;
  Serial.println("Loop begins.");
  status=PSXstatus();
  printuint(status);
  if ((status & (1<<R2)) == 0)
  {
    Serial.println("R2 pressed.");
  }
  delay(1000);
}


I can’t wait to make my own PSX->Xbox360 converter.

EDIT: DAMNIT! Use a pull up resistor between DATA (Arduino pin 12) and +5v. For higher speed, a lower value resistor is needed. 100 ohm at the least, 1.5k at the most. Actual PSX is 1k or 1.5k, I forget.

0 Likes

#2

Toodles, how hard would it be to make a X360 to PS3 converter? Since the X360 pad works on the PC should it not be easy to code something for it to work on PS3?

0 Likes

#3

I don’t like Micorsoft Ltd make an only accessories and other the party 3rd want to make accessories must have license fee by Micorsoft. :rolleyes:

0 Likes

#4

sounds great. awesome work as always. :tup:

if you ever produce these (like you did with the UPCBs), i’m sure a lot of people would purchase one from you.

0 Likes

#5

Very very very very hard. USB may be everywhere nowadays, but it is NOT a simple protocol at all.

0 Likes

#6

Yes, and their stupid, strict ass policy on not allowing 3rd party licensed converters is :annoy:

best o luck Toodles, keep everyone posted

0 Likes

#7

are there enough I/O pins?

Even if not, you could couple this with a shift register…

0 Likes

#8

Just barely. 28 pin PDIP, 5 needed for power, one for reset (that I could use as an I/O pin if needed, but make reprogramming difficult), leaves me 22 pins. Im working on having it use only the internal oscillator so I dont need an external crystal or resonator. 5 needed for PSX control (CMD, DAT, ACK, ATT, CLK) leaves me 17 pins for general I/O. (PORTD 0-7, PORTC 0-5, PORTB 0, 6, &7) that I can use for LED’s or driving lines. Even with two LEDs, that’s enough for a stick, start, select, guide/home, and 8 buttons.

0 Likes