PS2 Controller with Arduino Porting AVR to Arduino

SO to start off I AM a newb. I've been working on a control system for my schools ROV program and I realised that the PS2 controller has a reasonably understandable interface and plenty of information already on the internet. Plus i had a couple kicking around the house. So i found this code on this site dunk's robot - PS2 Controller on an AVR for the atmega 8 and since it and the arudinos run at the same clock speeds the code should be functional once it had been ported to the arduino ide. Unfortunently I managed to burn out my FTDI chip and while the new on is on the way I was wondering if this code makes sense and would work. So any help would be appreciated. Heres the origonal code. The ported code will follow that :smiley:

#define PSclock            2               // PD2
#define PSdata             3               // PD3
#define PSacknolage  4               // PD4
#define PScommand   5               // PD5
#define PSattention     6               // PD6 int main(void)
{
   // set the baud rate of the UART      // (needed for transmitting over radio module).
   //uartSetUp(2400);

   // set port pins to output for status leds:
   sbi(DDRC, PC0);                 // led.
   sbi(DDRC, PC1);                 // led
   sbi(DDRC, PC2);                 // led
   sbi(DDRC, PC3);                 // led
   sbi(DDRD, PD7);                 // led
   sbi(DDRB, PB0);                 // led
   sbi(DDRB, PB1);                 // led
   sbi(DDRB, PB2);                 // led

   // PSx controller I/O pin setup:
   sbi(DDRD, PD2);                 // clock. output. (blue)

   cbi(DDRD, PD3);                 // data. input. (brown)
   sbi(PORTD, PD3);               //    enable pullup resistor

   cbi(DDRD, PD4);                 // acknolage. input. (green)
   sbi(PORTD, PD4);               //    enable pullup resistor

   sbi(DDRD, PD5);                 // command. output. (orange)

   sbi(DDRD, PD6);                 // attention. output. (yellow)


   // enable interupts
   sei();

   // watchdog timer reset and enable
   //wdt_reset();
   //wdt_enable(0x02);

   timerInit();


   // 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.
   unsigned char chk_ana = 0, cnt = 0;
   while(chk_ana != 0x73){
       // put controller in config mode
       sbi(PORTD, PScommand);
       sbi(PORTD, PSclock);
       cbi(PORTD, PSattention);

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

       sbi(PORTD, PScommand);
       delay_ms(1);
       sbi(PORTD, PSattention);

       delay_ms(10);

       // put controller in analouge mode
       sbi(PORTD, PScommand);
       sbi(PORTD, PSclock);
       cbi(PORTD, PSattention);

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

       sbi(PORTD, PScommand);
       delay_ms(1);
       sbi(PORTD, PSattention);

       delay_ms(10);

       // exit config mode
       sbi(PORTD, PScommand);
       sbi(PORTD, PSclock);
       cbi(PORTD, PSattention);

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

       sbi(PORTD, PScommand);
       delay_ms(1);
       sbi(PORTD, PSattention);

       delay_ms(10);

       // poll controller and check in analouge mode.
       sbi(PORTD, PScommand);
       sbi(PORTD, PSclock);
       cbi(PORTD, PSattention);

       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);

       sbi(PORTD, PScommand);
       delay_ms(1);
       sbi(PORTD, PSattention);
       delay_ms(10);

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

   short int temp, data0, data1, data2, data3, data4, data5, i ,debounceSelect;
  // main program loop:
   while (1){

        sbi(PORTD, PScommand);                          // start communication with PSx controller
        sbi(PORTD, PSclock);
        cbi(PORTD, PSattention);

        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.

        delay_us(1);
        sbi(PORTD, PScommand);                      // close communication with PSx controller
        delay_us(1);
        sbi(PORTD, PSattention);                        // 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:
                        display(data0);
                        break;
                case 1:
                        display(data1);
                        break;
                case 2:
                        display(data2);
                        break;
                case 3:
                        display(data3);
                        break;
                case 4:
                        display(data4);
                        break;
                case 5:
                        display(data5);
        }        // this section calls my R/C transmit code (not included here).
        //tx_channel(0, data2);
        //tx_channel(1, data5);

   } // while(1)  
} //main 
// 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.
int gameByte(short int command)
{
        short int i ; 
        delay_us(1);
        short int data = 0x00;                             // clear data variable to save setting low bits later.
        for(i=0;i<8;i++)
        {
                if(command & _BV(i)) sbi(PORTD, PScommand);       // bit bang "command" out on PScommand wire.
                else cbi(PORTD, PScommand);
                cbi(PORTD, PSclock);                             // CLOCK LOW
                delay_us(1);                                              // wait for output to stabilise
                if((PIND & _BV(PSdata))) sbi(data, i);  // read PSdata pin and store
                //else cbi(data, i);
                sbi(PORTD, PSclock);                             // CLOCK HIGH
        }
        sbi(PORTD, PScommand);

        delay_us(20);                                                   // wait for ACK to pass.

        return(data);
}


// put 1 byte on the 8 LEDs. obviously you need to change the output pins to // match your board.
void display(short int LEDs)
{
        if(LEDs & _BV(0)) cbi(PORTC, PD0);
        else sbi(PORTC, PD0);

        if(LEDs & _BV(1)) cbi(PORTC, PD1);
        else sbi(PORTC, PD1);

        if(LEDs & _BV(2)) cbi(PORTC, PD2);
        else sbi(PORTC, PD2);

        if(LEDs & _BV(3)) cbi(PORTC, PD3);
        else sbi(PORTC, PD3);

        if(LEDs & _BV(4)) cbi(PORTD, PD7);
        else sbi(PORTD, PD7);

        if(LEDs & _BV(5)) cbi(PORTB, PD0);
        else sbi(PORTB, PD0);

        if(LEDs & _BV(6)) cbi(PORTB, PD1);
        else sbi(PORTB, PD1);

        if(LEDs & _BV(7)) cbi(PORTB, PD2);
        else sbi(PORTB, PD2);

        return;
}

Ported code will be in the next post

Heres the ported code and it does compile I was wondering if it would work. With the differences between avr and arduino I might have screwed something up.

#define PSclock     2               // PD2
#define PSdata      3               // PD3
#define PSack       4               // PD4
#define PScommand   5               // PD5
#define PSattention     6               // PD6 int main(void)

void setup () {




  // PSx controller I/O pin setup:
  pinMode (PSclock, OUTPUT);                 // clock. output. (blue)

  pinMode (PSdata, INPUT);                  // data. input. (brown)
  digitalWrite (PSdata, HIGH);               //    enable pullup resistor

  pinMode (PSack, INPUT);                  // acknowledge. input. (green)
  digitalWrite (PSack, HIGH);              //    enable pullup resistor

  pinMode (PScommand, OUTPUT);                 // command. output. (orange)

  pinMode (PSattention, OUTPUT); 
  ;                 // attention. output. (yellow)
  Serial.begin (9600); 

  // enable interupts

  sei();

  // watchdog timer reset and enable
  //wdt_reset();
  //wdt_enable(0x02);

  //timerInit();


  // 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.
  unsigned char chk_ana = 0, cnt = 0;
  while(chk_ana != 0x73){
    // put controller in config mode
    digitalWrite(PScommand, HIGH);
    digitalWrite(PSclock, HIGH);
    digitalWrite(PSattention,LOW);

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

    pinMode(PScommand, HIGH);
    delay(1);
    digitalWrite(PSattention, HIGH);

    delay(10);

    // put controller in analog mode
    digitalWrite(PScommand, HIGH);
    digitalWrite(PSclock, HIGH);
    digitalWrite(PSattention, LOW);

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

    digitalWrite(PScommand, HIGH);
    delay(1);
    digitalWrite(PSattention,HIGH);

    delay(10);

    // exit config mode
    digitalWrite(PScommand, HIGH);
    digitalWrite(PSclock, HIGH);
    digitalWrite(PSattention,LOW);

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

    digitalWrite(PScommand, HIGH);
    delay(1);
    digitalWrite(PSattention, HIGH);

    delay(10);

    // poll controller and check in analouge mode.
    digitalWrite(PScommand, HIGH);
    digitalWrite(PSclock, HIGH);
    digitalWrite(PSattention,LOW);

    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);

    digitalWrite(PScommand, HIGH);
    delay(1);
    digitalWrite(PSattention, HIGH);

    delay(10);


    // keep increasing counter to be dispalyed untill PSx controller confirms it's in analouge mode.
    Serial.println (cnt++);                     
    if (cnt > 254){ 
      cnt=0;
    }
  }
}
short int temp, data0, data1, data2, data3, data4, data5, i ,debounceSelect;
// main program loop:
void loop (){

  digitalWrite(PScommand, HIGH);
  digitalWrite(PSclock, HIGH);
  digitalWrite(PSattention,LOW);

  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.

  delayMicroseconds(1);
  digitalWrite(PScommand, HIGH);                      // close communication with PSx controller
  delayMicroseconds(1);
  digitalWrite(PSattention,HIGH);                        // 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:
    Serial.print ("case 0: ");
    Serial.println(data0);
    break;
  case 1:
    Serial.print ("case 1: ");
    Serial.println(data1);
    break;
  case 2:
    Serial.print ("case 2: ");
    Serial.println(data2);
    break;
  case 3:
    Serial.print ("case 3: ");
    Serial.println(data3);
    break;
  case 4:
    Serial.print ("case 4: ");
    Serial.println(data4);
    break;
  case 5:
    Serial.print ("case 5: ");
    Serial.println(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.
int gameByte(short int command)
{
  short int i ; 
  delayMicroseconds(1);
  short int data = 0x00;                             // clear data variable to save setting low bits later.
  for(i=0;i<8;i++)
  {
    if(command & _BV(i)) digitalWrite(PScommand, HIGH);       // bit bang "command" out on PScommand wire.
    else digitalWrite(PScommand, LOW);
    digitalWrite(PSclock, LOW);                             // 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);
    digitalWrite(PSclock, HIGH);                             // CLOCK HIGH
  }
  digitalWrite(PScommand,HIGH);

  delayMicroseconds(20);
  ;                                                   // wait for ACK to pass.

  return(data);
}

Just wondering: how did you manage to burn out your FTDI chip ? :-?

I made a dumb mistake >:( tried hooking up a PS2 controller. As technically they are supposed to be run off a 3v3 i tried using that power source from the arduino. Stupidly i did not check what current that pin was capable of supplying (50ma) and I guess its all done by the FTDI chip so I guess thats what burnt it. Next thing I know i smelled smoke and my board was on fire, now i have the same symptoms as described in this walkthrough http://www.neufeld.newton.ks.us/electronics/?p=328 Oh well ones on the way now time for some tricky soldering

Hi,
I´m new here, and I tried to read the data of a Playstations2 Controller with the Arduino but didint work. I tried your code and it dosen´t work. I dont know what I am doing wrong. Did you used some IC, our you just plugged the controller directly in to the arduino? Do you have some schematic to use whith this code? I will be glad for your answer.