Go Down

Topic: Playstation Controller (Read 45665 times) previous topic - next topic

Shutter

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!

Code: [Select]

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
http://www.geocities.com/digitan000/Hardware/22/e22_page.html?200822

playstation data protocol and pinouts
http://pinouts.ru/Game/playstation_9_pinout.shtml

Thanks :D

Shutter

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?

cairn

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?

Shutter

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 ^_^
"If you can;t get an answer, try harder and do it yourself D:"

Shutter

#4
Feb 29, 2008, 01:37 am Last Edit: Feb 29, 2008, 01:54 am by Shutter Reason: 1
YES! IT WORKS!
Code: [Select]

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

Shutter

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 ^-^

electri-fire

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.

plachapelle

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

md10bldr

One more here eagerly awaiting your library!  :)

alanchatham

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!

bens

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

alanchatham

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.

synlor

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

Pol_c_j

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

don803

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

Go Up