Playstation Controller Integration

22 Nov 2009

Hello,

I have mannaged to get a wireless guitar to work with the arduino using arduino code. It has worked great and i've started to port over the code for the mbed. I have done most of it but there are a few errors that I do not know how to get rid of.

Here is the code as I have it so far:

 

#include "mbed.h"

DigitalOut PSclock(p21);
DigitalIn PSdata(p22);
DigitalIn PSack(p23);
DigitalOut PScommand(p24);
DigitalOut PSattention(p25);

Serial pc(USBTX, USBRX); // tx, rx
int temp, data0, data1, data2, data3, data4, data5, i ,debounceSelect;

// enable interupts

//sei();

// this loop continues to put PSx controller into analouge mode untill the
// controller responds with 0x73 in the 2nd byte.
// (PS2 controller responds with 0x73 when in analouge mode.)
// the status LEDs will continue to count upwards untill a controller is found.
// if everything is working correctly this should happen on the first pass of
// this loop but occasionally errors occur and a 2nd or 3rd itteration happen.
int chk_ana = 0, cnt = 0;

void startup() {

    while (chk_ana != 0x73) {
        // put controller in config mode
        PScommand = 1;
        PSclock = 1;
        PSattention =0;

        gameByte(0x01);
        gameByte(0x43);
        gameByte(0x00);
        gameByte(0x01);
        gameByte(0x00);

        PScommand = 1;
    wait(0.000001);
        PSattention=1;

    wait(0.00001);

        // put controller in analog mode
        PScommand = 1;
        PSclock =1;
        PSattention =1;;

        gameByte(0x01);
        gameByte(0x44);
        gameByte(0x00);
        gameByte(0x01);
        gameByte(0x03);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);

        PScommand = 1;
    wait(0.000001);
        PSattention =1;

    wait(0.00001);

        // exit config mode
        PScommand = 1;
        PSclock = 1;
        PSattention = 1;

        gameByte(0x01);
        gameByte(0x43);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x5A);
        gameByte(0x5A);
        gameByte(0x5A);
        gameByte(0x5A);
        gameByte(0x5A);

        PScommand = 1;
    wait(0.000001);
        PSattention = 1;

    wait(0.00001);

        // poll controller and check in analouge mode.
        PScommand = 1;
        PSclock=1;
        PSattention=0;

        gameByte(0x01);
        chk_ana = gameByte(0x42);            // the 2nd byte to be returned from the controller should = 0x73 for "red" analouge controller.
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);

        PScommand = 1;
        wait(1);
        PSattention =1;

    wait(0.00001);


        // keep increasing counter to be dispalyed untill PSx controller confirms it's in analouge mode.
        pc.putc(cnt++);
        if (cnt > 254) {
            cnt=0;
        }
    }
}


// main program loop:
void loop () {

    PScommand=1;
    PSclock=1;
    PSattention = 0;

    gameByte(0x01);                                       // bite 0. header.
    temp = gameByte(0x42);                          // bite 1. header. (should possibly put test on this byte to detect unplugging of controller.)
    gameByte(0x00);                                       // bite 2. header.

    data0 = gameByte(0x00);                         // bite 3. first data bite.
    data1 = gameByte(0x00);                         // bite 4.
    data2 = gameByte(0x00);                         // bite 5.
    data3 = gameByte(0x00);                         // bite 6.
    data4 = gameByte(0x00);                         // bite 7.
    data5 = gameByte(0x00);                         // bite 8.

    wait(0.000001);
    PScommand = 1;                      // close communication with PSx controller
    wait(0.000001);
    PSattentio=1;                        // all done.



    if (!(data0 & _BV(0)) && !debounceSelect) {     // capture one unique press of the "select" button
        debounceSelect = 1;
    } else if ((data0 & _BV(0)) && debounceSelect) {
        if (i++ >= 5) i=0;
        debounceSelect = 0;
    }


    // this switch decides which data register to show on status LEDs depending on how many times
    // the "select" button on the PS2 controller has been pressed.
    switch (i) {
        case 0:
            pc.printf("case 0: ");
            pc.printf(data0);
            break;
        case 1:
            pc.printf("case 1: ");
            pc.printf(dta1);
            break;
        case 2:
            pc.printf("case 2: ");
            pc.printf(data2);
            break;
        case 3:
            pc.printf("case 3: ");
            pc.printf(data3);
            break;
        case 4:
            pc.printf("case 4: ");
            pc.printf(data4);
            break;
        case 5:
            pc.printf("case 5: ");
            pc.printf(data5);
    }


} //void loop




// PSx controller communication function.
// send a byte on the command line and receive one on the data line.
// needs Attention pin to have gone low before called to activate controller.
void gameByte (char command) {
    int i ;
    wait(0.000001);
    short int data = 0x00;                             // clear data variable to save setting low bits later.
    for (i=0;i<8;i++) {
        if (command & _BV(i)) {
            PScommand=1;    // bit bang "command" out on PScommand wire.
        } else {
            PScommand = 0;
        }
        PSclock=0;                            // CLOCK LOW
        delayMicroseconds(20);                                              // wait for output to stabilise
        if ((PIND & _BV(PSdata)))_SFR_BYTE(data) |= _BV(i); // read PSdata pin and store
        //else cbi(data, i);
        PSclock=1;                             // CLOCK HIGH
    }
    PScommand = 1;

    wait(0.00002);
    ;                                                   // wait for ACK to pass.

    return(data);
}

PlayStationController

 

The problems I am having is with the last function called gameByte, there are a few variable that I have no idea what they would correspond to in mbed language and I was wondering if anyone has any idea of what to do to get it to compile.

Thanks so much, more information about the project is here: Second Life Rock Band

22 Nov 2009 . Edited: 22 Nov 2009

Hi Vlad.  This project sounds really cool! I will be watching to see how it progresses.  I have a little bit of experience with C/C++ but am still a novice.  Hopefully I can help a little bit =)

 

First thing I see is a possible typo in your code.  In your switch statement under case 1 shouldn't dta1 be data1:

 

        case 1:
            pc.printf("case 1: ");
            pc.printf(dta1);
            break;

 

Also, your gameByte() function is defined to return void but at the end of the function you are trying to return the variable data.  Since data within the gameByte() function is a short int you might want to try chaning void to short int or just int.

 

 

One more thing that might be a problem, you have the integer i declared both at the top of your code, possibly as a global variable, and also within the gameByte() function.

 

And finally, I spy with my little eye a lonesome semicolon (;) just above the return(data) command inside gameByte().

 

I hope this helps. Thanks,

Aaron

22 Nov 2009 . Edited: 22 Nov 2009

Hi Vlad,

Aaron has done a great job of identifying some of the problems. I just imported your code, made these changes, and added some more to make it allcompile ok. Here is the result:

PlayStationController

Note, just because it compiles, that doesn't mean it does the right thing!

Here are the main changes I made:

I moved gameByte() earlier in the main.cpp file so it is defined by the time it is used, and changed the return type from void to char.

There was a function (or macro) named _BV(n), which doesn't exist. A little google suggests this is a bit setting macro (probably "Bit Value" or something), but the logic is basically:

1 << n;

It doesn't seem to save much typing, but I guess people might like to wrap it up. So I just quickly added this to get that working:

int _BV(int bit) {
    return 1 << bit;
}

These sort of things are often defined as Macros, which are basically a text substitution by a C pre-processor before compiling. I'd encourage defining them as function, as it helps the compiler give you better error reports, type checking etc. Macros are like someone coming in, changing your code, then talking back to you in what it was translated to. People will tell you "it is not as efficient", which in some cases will be true, but in a lot of cases it won't make any difference and you can even encourage the compiler to "inline" functions meaning you get exactly the same result (I'll do a post about this sometime perhaps). But i'm getting of track here...

The printf() statements needed a little modification, from:

        case 0:
            pc.printf("case 0: ");
            pc.printf(data0);
            break;

to:

        case 0:
            pc.printf("case 0: %d\n", data0);
            break;

Also, the program didn't have a main() function, and every C program needs one of these. My guess is this code is based on the arduino convention of a hidden main that calls setup then loop, so you need to add:

int main() {
    startup();
    while(1) {
        loop();
    }
}

There were probably a few tweaks more, but this was the main crux to get it to compile!

Now, you'll have to start looking at the logical bugs... :)

Simon

22 Nov 2009

Hi vlad,

I just looked at what your code was logically doing, and I got a hunch that it is basically emulating a SPI interface. I had a little google and found this page:

which suggests the same (and seems like a brilliant resource). If so, this would suggest all this code could be really simplified down by just using the SPI interface. Might be worth a look.

Simon

22 Nov 2009

Thanks Aaron and Simon!

I have imported the code and it compiled no problem. I connected the wireless unit to the mbed and these are my outputs:

 

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~���������������������������������������������������������������������������������������������
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~�������������������������������������������������������������������������������������������������������������������������������
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~�����������������������������������������������������������������

Not sure what this means but its pretty much just printing an ascii value + 1 im guessing. When I run the code with an arduino the result is 255,255,255,255 until I press a button.The guitar is still connecting to the board but I think simon is right, there is some logic issues in the code.

I am using Simon's export here:

PlayStationController

22 Nov 2009

After some testing I noticed that the problem was it was never getting past the setup function, for some reason I think it is to do with timing. The wait function is one second correct? wait(1)= 1 second, the arduino code uses delay(10) which is really 1/100th of a second.

My question is, is wait_ms() milliseconds or microseconds?

22 Nov 2009

_ms is milliseconds, _us is microseconds.

22 Nov 2009

Great thanks! The timing is now 100% the same as the ardino code but still not getting past the setup function. The receiver is suppose to send 0X73 back when it is in analog mode but it does not. It is very strange because there is nothing that has changed between codes.

Could it possibly be the pins I am using or should any digital pins work for this application?

I noticed that there was a peice of gameByte that was commented out that stored the value of the bit, could this be any part of the issue.

An updated version of the code is here with updated timing:

PlayStationController

22 Nov 2009 . Edited: 22 Nov 2009

Hi Vlad,

I don't have a controller to test on, but I just wrote some code based on the details at http://www.curiousinventor.com/guides/ps2. The code is quite a lot simpler than the code you have as I used the mbed SPI interface. I have no idea if it will work and there will likely be some bugs/adjustments needed, but it might be a neater starting point?

PlayStationController

Simon

22 Nov 2009

Hey Simon,

Thank you very much for everything, I compiled the code but got a strage "pin map not found" error, and my mbed is freaking out flashing the led's 1 and 4 then 2 and 3. Not sure what is going on but my mbed is not happy lol

22 Nov 2009

Ah, my bad! Because i'm using SPI pins now, it needs to, umm, use some SPI pins!!

Try this:

PlayStationController

You'll need to rewire the controller wires as per this new code:

SPI spi(p5, p6, p7);   // mosi, miso, sclk (or "command", "data", "clock")
DigitalOut cs(p25);    // chip select (or "attention")

Simon

22 Nov 2009 . Edited: 22 Nov 2009

Oh man I feel stupid now for asking, such a simple thinking. I have compiled the code but it seems like still not wanting to connect past the startup. I have noticed that the mode of the DigitalIn for the acknowledge pin needs to be set up pullup. In the past code's I have just set it to a digital pin and nothing else. Could this be part of the problem?

This is what the website you have mentioned has said:

 

Green - Acknowledge: This normally high line drops low about 12us after each byte for half a clock cycle, but not after the last bit in a set. This is a open collector output and requires a pull-up resistor (1 to 10k, maybe more). playstation.txt says that the playstation will consider the controller missing if the ack signal (> 2us) doesn't come within 100us.

I have seen that you can chage the mode of the DigitalIn, just not sure of the syntax

23 Nov 2009 . Edited: 23 Nov 2009

Hi Vlad,

Your code didn't have any acknowledge logic (although a pin was defined), so I ignored that.

Note, the other thing is the SPI frequency and format. From the same page and oscilloscope pictures, i'd suggest try 100KHz, and the clock and phase inverted:

spi.frequency(100000);   // 100KHz
spi.mode(8, 3);          // 8-bit, PHA/POL=1 

Or at least investigate this area.

If you are still seeing nothing, maybe just start by trying to poll the basic poll command (i.e. the old digital/backward compatible mode i'd guess), and look at things like the acknowledge/pullups.

Simon

27 Nov 2009

Here is an update on this topic. Still cannot get mbed to read the controller but it is passing serial data to the mbed. Kinda cheating but there sure is a lot of embedding. Here is a video of the guitar in action attached to a wave shield. I need to get a SD card holder+breakout board then the mbed can process the Wav files.

 

07 Jul 2010

Your actually having more problems than that, I'm putting this here for others before they make the same mistake I did... THIS DOES NOT WORK IN ANY WAY SHAPE OR FASHION. I'm basically trying to help others who are trying to interface a Playstation controller to MBED and letting them know... DONT BOTHER READING THIS THEY NEVER GOT ANY OF IT TO WORKING.

user avatar Vlad Cazan wrote:

Hello,

I have mannaged to get a wireless guitar to work with the arduino using arduino code. It has worked great and i've started to port over the code for the mbed. I have done most of it but there are a few errors that I do not know how to get rid of.

Here is the code as I have it so far:

 

#include "mbed.h"

DigitalOut PSclock(p21);
DigitalIn PSdata(p22);
DigitalIn PSack(p23);
DigitalOut PScommand(p24);
DigitalOut PSattention(p25);

Serial pc(USBTX, USBRX); // tx, rx
int temp, data0, data1, data2, data3, data4, data5, i ,debounceSelect;

// enable interupts

//sei();

// this loop continues to put PSx controller into analouge mode untill the
// controller responds with 0x73 in the 2nd byte.
// (PS2 controller responds with 0x73 when in analouge mode.)
// the status LEDs will continue to count upwards untill a controller is found.
// if everything is working correctly this should happen on the first pass of
// this loop but occasionally errors occur and a 2nd or 3rd itteration happen.
int chk_ana = 0, cnt = 0;

void startup() {

    while (chk_ana != 0x73) {
        // put controller in config mode
        PScommand = 1;
        PSclock = 1;
        PSattention =0;

        gameByte(0x01);
        gameByte(0x43);
        gameByte(0x00);
        gameByte(0x01);
        gameByte(0x00);

        PScommand = 1;
    wait(0.000001);
        PSattention=1;

    wait(0.00001);

        // put controller in analog mode
        PScommand = 1;
        PSclock =1;
        PSattention =1;;

        gameByte(0x01);
        gameByte(0x44);
        gameByte(0x00);
        gameByte(0x01);
        gameByte(0x03);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);

        PScommand = 1;
    wait(0.000001);
        PSattention =1;

    wait(0.00001);

        // exit config mode
        PScommand = 1;
        PSclock = 1;
        PSattention = 1;

        gameByte(0x01);
        gameByte(0x43);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x5A);
        gameByte(0x5A);
        gameByte(0x5A);
        gameByte(0x5A);
        gameByte(0x5A);

        PScommand = 1;
    wait(0.000001);
        PSattention = 1;

    wait(0.00001);

        // poll controller and check in analouge mode.
        PScommand = 1;
        PSclock=1;
        PSattention=0;

        gameByte(0x01);
        chk_ana = gameByte(0x42);            // the 2nd byte to be returned from the controller should = 0x73 for "red" analouge controller.
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);
        gameByte(0x00);

        PScommand = 1;
        wait(1);
        PSattention =1;

    wait(0.00001);


        // keep increasing counter to be dispalyed untill PSx controller confirms it's in analouge mode.
        pc.putc(cnt++);
        if (cnt > 254) {
            cnt=0;
        }
    }
}


// main program loop:
void loop () {

    PScommand=1;
    PSclock=1;
    PSattention = 0;

    gameByte(0x01);                                       // bite 0. header.
    temp = gameByte(0x42);                          // bite 1. header. (should possibly put test on this byte to detect unplugging of controller.)
    gameByte(0x00);                                       // bite 2. header.

    data0 = gameByte(0x00);                         // bite 3. first data bite.
    data1 = gameByte(0x00);                         // bite 4.
    data2 = gameByte(0x00);                         // bite 5.
    data3 = gameByte(0x00);                         // bite 6.
    data4 = gameByte(0x00);                         // bite 7.
    data5 = gameByte(0x00);                         // bite 8.

    wait(0.000001);
    PScommand = 1;                      // close communication with PSx controller
    wait(0.000001);
    PSattentio=1;                        // all done.



    if (!(data0 & _BV(0)) && !debounceSelect) {     // capture one unique press of the "select" button
        debounceSelect = 1;
    } else if ((data0 & _BV(0)) && debounceSelect) {
        if (i++ >= 5) i=0;
        debounceSelect = 0;
    }


    // this switch decides which data register to show on status LEDs depending on how many times
    // the "select" button on the PS2 controller has been pressed.
    switch (i) {
        case 0:
            pc.printf("case 0: ");
            pc.printf(data0);
            break;
        case 1:
            pc.printf("case 1: ");
            pc.printf(dta1);
            break;
        case 2:
            pc.printf("case 2: ");
            pc.printf(data2);
            break;
        case 3:
            pc.printf("case 3: ");
            pc.printf(data3);
            break;
        case 4:
            pc.printf("case 4: ");
            pc.printf(data4);
            break;
        case 5:
            pc.printf("case 5: ");
            pc.printf(data5);
    }


} //void loop




// PSx controller communication function.
// send a byte on the command line and receive one on the data line.
// needs Attention pin to have gone low before called to activate controller.
void gameByte (char command) {
    int i ;
    wait(0.000001);
    short int data = 0x00;                             // clear data variable to save setting low bits later.
    for (i=0;i<8;i++) {
        if (command & _BV(i)) {
            PScommand=1;    // bit bang "command" out on PScommand wire.
        } else {
            PScommand = 0;
        }
        PSclock=0;                            // CLOCK LOW
        delayMicroseconds(20);                                              // wait for output to stabilise
        if ((PIND & _BV(PSdata)))_SFR_BYTE(data) |= _BV(i); // read PSdata pin and store
        //else cbi(data, i);
        PSclock=1;                             // CLOCK HIGH
    }
    PScommand = 1;

    wait(0.00002);
    ;                                                   // wait for ACK to pass.

    return(data);
}

PlayStationController

 

The problems I am having is with the last function called gameByte, there are a few variable that I have no idea what they would correspond to in mbed language and I was wondering if anyone has any idea of what to do to get it to compile.

Thanks so much, more information about the project is here: Second Life Rock Band

07 Jul 2010

What are the variables in the function you are having problems with?  Is it the commented out else clause?

07 Jul 2010
The code above will work perfectly with a wireless guitar hero guitar on an arduino. After the code was ported for the mbed it stops working. I tried for a week to see what the issue was but I couldn't so i used the arduino. If you want to get this working which I'm sure is more then possible just find some arduino code for a standard wired controller and then port it over. It is just a basic spi command.
07 Jul 2010

user avatar Barry Shonbeck wrote:

What are the variables in the function you are having problems with?  Is it the commented out else clause?

Now that you mention it yes it won't compile with those commented lines uncommented. The other thing is I might need a pull up resistor on the datat line? This is going from info documented on the http://www.curiousinventor.com/guides/ps2 pages. I'm actually shocked that there isn't more on playstation controller interfacing an MBED than there is. I'm going to work on somehting but it's going to take me a while to get up to speed on it all. I'm using an SUMP onpen bench logic analyser on the data wire just before it goes to MBED and it is out putting data. So it is simply a failure of the code at this point. Thanks!

28 Sep 2017

The codes for Playstation integration are good enough to understand the things you want to say. keep posting. nice work.

http://gamingtoolkit.net/