Toodles
01-02-2008, 02:29 AM
Mostly I wanted to post this so I'd have a permanent working copy somewhere. :) 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
#define DATAIN 12 //MISO pin
#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.
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
#define DATAIN 12 //MISO pin
#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.