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);
}
/*----------------------------------------------------------------------*/
bulkhead wrote:
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.