Playstation Controller

Ok, wow, I have been trying to talk to a playstation controller using arduino. I am a novice so i think it is a tad hard for me.

first of the clock speed of 16Mhz is way to fast, so I added a 1ms delay between high and low of clock to get a 500hz clock.

the fallowing code should work, But It doesn't!

int clock = 2;
int ATT = 3;
int RX = 4;
int TX = 5;
int ACK = 6;
char TMP;
void setup () {
 Serial.begin(19200);
 pinMode(clock,OUTPUT);
 pinMode(ATT,OUTPUT);
 pinMode(RX,INPUT);
 pinMode(TX,OUTPUT);
 pinMode(ACK,INPUT);
}

unsigned char psx_data(unsigned char out_byte); /*  This is an example of a forward declaration or "prototype" */
void lcdDisplay(unsigned char); /* Also note your parameters don't have to match names... you only need the types and commas, FYI the moar yuo know */

void loop() {
        unsigned char data_1;
        unsigned char data_2;
      digitalWrite(ATT, LOW); // lower ATT
      
      psx_data(0x01); // send a start command to the psx controller
      unsigned char type = psx_data(0x42); // send a data request to psx controller + get controller type

      psx_data(0x00); // get 'here comes data' code

      data_1 = psx_data(0x00); // get controller data byte 1
      data_2 = psx_data(0x00); // get controller data byte 2

      digitalWrite(ATT, HIGH); // raise ATT
                                                             
        lcdDisplay(type);
}

unsigned char psx_data(unsigned char out_byte)
{
      unsigned char in_byte; // data received from PSX controller
      unsigned char mask_byte;
      unsigned char bit_counter;
                             
      mask_byte = 1;
      in_byte = 0;
      
      // for each bit in the transmitted byte
      for (bit_counter = 0; bit_counter < 8; bit_counter++)
      {            
            // CLK low
            digitalWrite(clock,LOW);
            
            // set up CMD line (data out to controller)
            if (out_byte & mask_byte) digitalWrite(TX,HIGH);
            else digitalWrite(TX,LOW);
                         
            // shift the mask bit for the next comparison
            mask_byte <<= 1;
            
                delay(1);
            // CLK high
            digitalWrite(TX,HIGH);
             
            // load the current controller data bit on the bus into our return byte
            if (digitalRead(RX) == 1) in_byte |= 0x80;
            // and right-shift to line up the next bit (last bit has final value, no need to shift)
            if (bit_counter < 7) in_byte >>= 1;
                delay(1);
      }              
      return in_byte;
}

//talks to my matrix orbital LCD display
void lcdDisplay (unsigned char x) {
       Serial.print(254,BYTE);
       Serial.print("X");
       Serial.print("Sample: ");
       Serial.print(x, DEC);
}

Some sites i have been using fro help
source code i based it off of
http://www.lynxmotion.com/images/files/atmel01.c

more stuff

playstation data protocol and pinouts

Thanks :smiley:

I know i am new and it helps if someone had the hardware, but i really need sombody to look at this. I want to make a converter so that i can use this controller to control a robot. I only have a week or so to do it. So any help i can get will be greatly appreciated. Does anybody have any suggestions or have any ideas why my code isn't working?

I haven't tried interfacing with a Playstation Controller yet, but it's on my todo list since I just picked up a AH3-R Hexapod from Lynxmotion and I'll be having the Arduino handle communication and sensor data.

I looked at your code and some of the links you provided. It looks like the controller communicates with something kind of resembling SPI. I found this simple BS2 program on the Lynxmotion site which looks like it would be really easy to port over to Arduino with shiftOut and shiftIn. Might be worth a try if you're not getting anywhere with the code you posted before.

What's your application and/or what other hardware are you using?

Well. I am going to convert it to an analog joystick for use in the First robotics Competition. Also on that note i need to sooth out pwm signals >.<
i am using ps1 controller and have been going to a friends house using there oscilloscope
.

code sent from me from someone who has gotten it to work with the arduino, have yet to test it out.
...i will post it on my web site if it works, and reply to this :slight_smile:
"If you can;t get an answer, try harder and do it yourself D:"

YES! IT WORKS!

#include <math.h>
#include <stdio.h>
#include <avr/io.h>

#define LED_PIN 13
#define DELAY(wait) digitalWrite(LED_PIN,LOW); delay(wait); digitalWrite(LED_PIN,HIGH);

/* These are AVR PORTB pins, +8 to convert to Arduino pins */
#define PS2clk 5
#define PS2cmd 3
#define PS2att 2
#define PS2dat 4
#define PS2PORT PORTB
#define PS2IN PINB
#define CTRL_CLK 20
#define CTRL_BYTE_DELAY 20

//These are our button constants
#define PSB_SELECT 0x01
#define PSB_L3 0x02
#define PSB_R3 0x04
#define PSB_START 0x08
#define PSB_PAD_UP 0x10
#define PSB_PAD_RIGHT 0x20
#define PSB_PAD_DOWN 0x40
#define PSB_PAD_LEFT 0x80

#define PSB_L2 0x100
#define PSB_R2 0x200
#define PSB_L1 0x400
#define PSB_R1 0x800
#define PSB_GREEN 0x1000
#define PSB_RED 0x2000
#define PSB_BLUE 0x4000
#define PSB_PINK 0x8000

#define SET(x,y) (x|=(1<<y))
#define CLR(x,y) (x&=(~(1<<y)))
#define CHK(x,y) (x & (1<<y))
#define TOG(x,y) (x^=(1<<y)) 

boolean PSButton();
unsigned char PS2data[9];
void read_gamepad();
void config_gampad();
unsigned char get_gamepad_mode();
unsigned char i;

void setup() {
    randomSeed(analogRead(0));
    Serial.begin(57600);
    pinMode(LED_PIN,OUTPUT);
    digitalWrite(LED_PIN,HIGH);

    pinMode(PS2clk+8,OUTPUT);
    pinMode(PS2att+8,OUTPUT);
    pinMode(PS2cmd+8,OUTPUT);
    pinMode(PS2dat+8,INPUT);
    digitalWrite(PS2dat+8,HIGH);

    config_gampad();
}
void loop () {
    read_gamepad();  
    if(PSButton(PSB_SELECT))
     Serial.print("Select\n");
    if(PSButton(PSB_L3))
     Serial.print("L3\n");
    if(PSButton(PSB_R3))
     Serial.print("R3\n");
    if(PSButton(PSB_START))
     Serial.print("Start\n");
    if(PSButton(PSB_PAD_UP))
     Serial.print("Up\n");
    if(PSButton(PSB_PAD_RIGHT))
     Serial.print("Right\n");
    if(PSButton(PSB_PAD_LEFT))
     Serial.print("LEFT\n");
    if(PSButton(PSB_PAD_DOWN))
     Serial.print("DOWN\n");
    if(PSButton(PSB_L1))
     Serial.print("L1\n");
    if(PSButton(PSB_R1))
     Serial.print("R1\n");
    if(PSButton(PSB_L2))
     Serial.print("L2\n");
    if(PSButton(PSB_R2))
     Serial.print("R2\n");
    if(PSButton(PSB_GREEN))
     Serial.print("Triangle\n");
    if(PSButton(PSB_RED))
     Serial.print("Circle\n");
    if(PSButton(PSB_PINK))
     Serial.print("Square\n");
    if(PSButton(PSB_BLUE))
     Serial.print("X\n");
}
boolean PSButton(unsigned int button) {
int byte = 3;
if (button >= 0x100) {
  byte = 4;
  button = button >> 8;
}
  if (~PS2data[byte] & button) 
  return true;
  else
  return false;
}
unsigned char _gamepad_shiftinout (char byte) {
   unsigned char tmp = 0;
   for(i=0;i<8;i++) {
      if(CHK(byte,i)) SET(PS2PORT,PS2cmd);
        else  CLR(PS2PORT,PS2cmd);
      CLR(PS2PORT,PS2clk); 
      delayMicroseconds(CTRL_CLK); 
        if(CHK(PS2IN,PS2dat)) SET(tmp,i); 
      SET(PS2PORT,PS2clk); 
   }
   SET(PS2PORT,PS2cmd); 
   delayMicroseconds(CTRL_BYTE_DELAY);
   return tmp;
}
void _gamepad_shiftout (char byte) {
   for(i=0;i<8;i++) {
      if(CHK(byte,i)) SET(PS2PORT,PS2cmd);
        else  CLR(PS2PORT,PS2cmd);
      CLR(PS2PORT,PS2clk); 
      delayMicroseconds(CTRL_CLK); 
      SET(PS2PORT,PS2clk); 
      //delayMicroseconds(CTRL_CLK); 
   }
   SET(PS2PORT,PS2cmd); 
   delayMicroseconds(CTRL_BYTE_DELAY);
}
unsigned char _gamepad_shiftin() {
   unsigned char tmp = 0;
   for(i=0;i<8;i++) {
      CLR(PS2PORT,PS2cmd);
      CLR(PS2PORT,PS2clk); 
      delayMicroseconds(CTRL_CLK);
        if(CHK(PS2IN,PS2dat)) SET(tmp,i); 
      SET(PS2PORT,PS2clk); 
      delayMicroseconds(CTRL_CLK);
   }
   SET(PS2PORT,PS2cmd); 
   delayMicroseconds(CTRL_BYTE_DELAY);
   return tmp;
}
void read_gamepad() {
    SET(PS2PORT,PS2cmd); 
    SET(PS2PORT,PS2clk); 
    CLR(PS2PORT,PS2att); // low enable joystick
    delayMicroseconds(CTRL_BYTE_DELAY);
    char dword[9] = {0x01,0x42,0,0,0,0,0,0,0};
    for (int i = 0; i<9; i++) {
        PS2data[i] = _gamepad_shiftinout(dword[i]);
    }
    SET(PS2PORT,PS2att); // HI disable joystick
}
unsigned char get_gamepad_mode() {
    SET(PS2PORT,PS2cmd); 
    SET(PS2PORT,PS2clk); 
    CLR(PS2PORT,PS2att); // low enable joystick
    _gamepad_shiftout(0x01);
    unsigned char x = _gamepad_shiftin();
    SET(PS2PORT,PS2att); // HI disable joystick
    return x;
}
void config_gampad() {
   SET(PS2PORT,PS2cmd); 
   SET(PS2PORT,PS2clk); 
   CLR(PS2PORT,PS2att); // low enable joystick
    _gamepad_shiftout(0x01);
    _gamepad_shiftout(0x43);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x01);
    _gamepad_shiftout(0x00);
    // Lock to Analog Mode on Stick
    _gamepad_shiftout(0x01);
    _gamepad_shiftout(0x44);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x01);
    _gamepad_shiftout(0x03);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x00);
    // Vibration
    /*
    _gamepad_shiftout(0x01);
    _gamepad_shiftout(0x4D);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x01);
    */
    _gamepad_shiftout(0x01);
    _gamepad_shiftout(0x4F);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0xFF);
    _gamepad_shiftout(0xFF);
    _gamepad_shiftout(0x03);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x01);
    _gamepad_shiftout(0x43);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x00);
    _gamepad_shiftout(0x5A);
    _gamepad_shiftout(0x5A);
    _gamepad_shiftout(0x5A);
    _gamepad_shiftout(0x5A);
    _gamepad_shiftout(0x5A);
   SET(PS2PORT,PS2att);
}

Ok, so I have been working on this and improving it. So, it looks like there is a small problem. it is suppose to be that you can hook up the PSX controllers in a bus. when i have the rx line hooked up to another rx line it gets grounded D:
It is suppose to be that I select which controller to talk to using the select line and i can use the same pins for everything else.
Any ideas why this is not working?

I will make an official Lib for arduino soon ^-^

Ehrmm... I think rx is a "recieve" pin, so should be connected to a tx "transmit" pin. In this case the DATA pin of the Playstation controller , that's pin 1 , the brown wire.

Correct me if I'm wrong , I'm new here.

Any results yet? I'm looking forward to the library.

I'm also looking foward your libraries... Any change to your last posted code?

I'm going to plug in a controller to the board to test it...

my goal is to use a wireless dualshock controller for tank RC combat.

Philippe

One more here eagerly awaiting your library! :slight_smile:

Hi there -

So I'm basically working on the opposite of your project, that is, making a controller to interface with a PlayStation 2. I feel like the code you've got posted seems like it'd be able to do the job with a couple of modifications, but I don't really understand what it's doing exactly...

Really, it's these lines that I don't really understand -

#define PS2PORT PORTB
#define PS2IN PINB
#define CTRL_CLK 20
#define CTRL_BYTE_DELAY 20

...

#define SET(x,y) (x|=(1<<y))
#define CLR(x,y) (x&=(~(1<<y)))
#define CHK(x,y) (x & (1<<y))
#define TOG(x,y) (x^=(1<<y))

I think if I knew what was going on in those lines, I could pretty easily figure out how to modify the rest of the program to emulate a controller instead of a playstation...So if anyone could help me out, it'd be a great help!

Can you elaborate a little on what you don't understand? I can try to give you a general description of what the defines are (note that I have no familiarity with the original program):

PORTB is defined in <avr/io.h>, which is automatically included in your sketches. It is the mega168 register that controls the output state of the pins on port B (Arduino digital pins 8 - 13). Setting bit n of PORTB causes the corresponding pin to drive high if the pin is set as an output, or it causes the internal pull-up to be enabled if the pin is set as an input. Clearing bit n of PORTB causes the corresponding pin to drive low if the pin is set as an output, or it causes the pin to be tri-stated (high impedance) if the pin is set as an input.

PINB is also defined in <avr/io.h>. It is the mega168 register that tells you the digital input values of the port B pins. You use this register to read digital inputs of Arduino digital pins 8 - 13.

CTRL_CLK and CTRL_BYTE_DELAY sound like they have to do with timing; I'd need to look at them in the context of the code to know what they are used for.

The remaining defines perform bit manipulations on bytes. SET(byte, bit) will set the specified bit of the specified byte to 1 while leaving the rest of the bits in the byte unchanged. CLR(byte, bit) clears the specified bit of the specified byte. CHK(byte, bit) returns 0 if the specified bit of the specified byte is 0, otherwise it returns a non-zero value. TOG(byte, bit) toggles the specified bit of the specified byte (1 -> 0 and 0 -> 1).

Useful bitwise operators to understand:

~: bitwise NOT. Example: ~1011 = 0100
|: bitwise OR. Example: 1010 | 0011 = 1011
&: bitwise AND. Example: 1010 & 0011 = 0010
<<: bitshift left. Example: 10001011 << 2 = 00101100

: bitshift right. Example: 10001011 >> 2 = 00100010
^: bitwise XOR. Example: 1010 ^ 0011 = 1001

Note that & and | are different from the boolean operators && and ||.

  • Ben

Wow, thanks Ben! That's going to help me alot I think! Mostly, I'm pretty new to messing with low-level stuff - I'm coming in from a Python/Java background (also an Economics major background), so the more EE stuff of these projects is all new stuff to me. Thanks though, and I'll try and get some controller emulation stuff done up.

I don't mean to step on your toes Shutter since you are working on a library for this already, but I had some old code used for reading a playstation controller and I threw together a library. It only works with the original digital controller, at least that is the only thing I have tested with it. More information and a download can be found on the playground.

http://www.arduino.cc/playground/Main/PSXLibrary

Hi. I'm using the psx library and my question is where I have to connect the ecknowledge pin? In the arduino webpage examples it don't explain anything about this.
I have a pololu LV-168 board and the arduino 11 because the libraries of psx don't work for 12 and obviously a Pllaystation 2 controller.
please help me and if these helps include photos or pictures better because i'm not a very experimented english speaker.
Thanks and sorry if my english is bad

I tried the PSX library posted by synlor, and could not get it to compile with arduino 017. I saw another similar result elsewhere on the forum.

I then used the code posted on Feb 29 by Shutter. It compiled free of errors without changes. I wired it up to a controller, and had the whole thing running after moving the wires up 8 to pins 10-13, and setting my baud rate to 57,600. Thanks for your post Shutter

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.

PSX Controllers is a link to the controller pinout. According to Shutters code, the pins connect as follows. 5v goes to the 5v arduino supply. gnd goes to arduino ground. Att connects to pin 10. cmd connects to pin 11. Dat connects to pin 12. clk connects to pin 13. No Ic's are needed. Double check the baud rate. I just soldered 22 guage wire to the pins and put tape on them telling me where to wire them to arduino. It has been rock solid for me. I have hooked it to 2 windows pc's and a mac.

Good Luck,
Don

And the ACK pin? I dont need to use it?
I´m using Arduino 0017 software in a Windows PC, and I´m wiring the PS2 connector directly in to the Arduino.
Did you used the code posted of Shutter? If you dont please, can you sand me your code?
Thank you for your help.

Ack is not used.
Shutters code works just fine as posted.
I ran it using 017.
I modified it to send the data differently, but his code will get you up and running. It was just easier for me to alter the arduino code than the software I was interfacing with.

HI, I have 2 controllers,the alambric one works fine but with the wireless seems to be trying to associate the controller, I dont really have a play station, I dont know how to interprete the LEDs.

I have this device


I tried to power it with 5v and 3.3, same behavior.

any ideas?, im using the last code posted by Shutter