Friday, 29 August 2014

Interfacing Playstation controller with Atmega Microcontroller

Hello Everyone,
                              In this post I will explain about How to interface a playstation 2 (It can also be one with a little change in clock frequency) joystick with Atmega 16 microcontroller (though you can use any series of Atmel or even any other family microcontroller but you cannot use my code then  :(      ).

 When I first started working on this project I had a lot of trouble finding "Proper" resources and all I found was Arduino libraries. But why should we use libraries made by others when we can make our own and this is what has compelled me to write this post.

So Lets get started.........

We'll be using the SPI (Serial peripheral interface ) Protocol of Atmega for communicating with the Ps2 controller.The SPI (Serial Peripheral Interface) is a peripheral used to communicate between the AVR and other devices, like others AVRs, external EEPROMs, DACs, ADCs, etc. With this interface, you have one Master device which initiates and controls the communication, and one or more slaves who receive and transmit to the Master.
I have a detailed post on SPI on my blog http://roboticsforevery1.blogspot.in/2014/08/serial-peripheral-interface-spi.html

Ok.. Now that U know everything about SPI we'll discuss about the ps2 controller.......

------------------------ Wiring -------------------
The PS2 console gamepad has 9 wires- 5 communication lines, VCC,GND, vibration motor power, and a reserved line for future use.

Pin Color Name Description
Brown
DATA :This is the signal from controller to host. It is an 8-bit serial transmission synchronous to the falling edge of the clock. THIS IS CONNECTED TO MISO (PIN PB6) of Atmega16. This is an open collector output and requires a pull-up resistor (1 to 10k, maybe more). (A pull-up resistor is needed because the controller can only connect this line to ground; it can't actually put voltage on the line).
Orange
Command :This is the signal from the host to the controller. Again, it is an 8-bit serial transmission on the falling edge of the clock.THIS IS CONNECTED TO MOSI (PIN PB5) of Atmega16. 
Grey
7.6V :Vibration Motors Power: 6-9V.
Black
Ground
Red
VCC :Variable power from 5 V down to 3V.
Yellow
Attention :This signal is used to get the attention of the controller. This signal will go low for theduration of a transmission.THIS IS CONNECTED TO SS' (PIN PB4) of Atmega16
Blue
Clock 
500kHz THIS IS CONNECTED TO SCK (PIN PB7) of Atmega16
White
Not Connected: Reserved for future use.
Green
 This signal is low for at least one clock period after each 8 bits are sent and ATT is still low. 
  


Thus to Summarize connect all the lines as directed above with all pins pulled up to VCC with a 10K resistor.


        ----------------- Programming  ----------------
Transmission Protocol


The PlayStation controller communicates with the host MCU via SPI protocol. All transmissions are 8-bit serial LSB first synchronous to the falling edge of the clock. In fact, it behaves like a big shift register. So, it transmits andreceives data at the same time. That means, even to read the controller data you need to send some dummy bytes.
          Note:It Uses MODE 3 of SPI.


Command Listing:
There are more than 15 different commands( I'll be discussing only a few to avoid confusion and also to not make this post boring :) ). 
0x42: Main polling command

This command gets all the digital and analog button states. When the host MCU wants to read controller data itpulls the ATT line low and issues a start command (0x01). The controller will then reply with its Type ID(0x41=Digital, 0x73=Analog). At the same time as the controller is sending this ID byte the host is transmitting getdata (0x42). Following this the CMD line goes idle and the controller transmits ready (0x5A) followed by 2 (digitalmode) or 6 bytes (analog mode) data.

0x43: Enter / Exit Config Mode
 This can poll the controller like 0x42, but if the first command byte is 0x01, it has the effect of entering config mode(0xF3), in which the packet response can be configured.
0x44: Switch modes between digital and analog
Only works after the controller is in config mode (0xF3).
Set analog mode: Command Byte 4 = 0x01
Set digital mode: Command Byte 4 = 0x00
If Command Byte 5 is 0x03, the controller mode is locked.

Byte Sequence to Configure Controller for Analog Mode + Button Pressure + Vibration Control
The following sequence will setup a controller to send back all available analog values, and also map the left and right motors to command bytes 4 and 5.
-- 0x42 Poll once just for fun
byte #
1
2
3
4
5
Command (hex)
01
42
00
FF
FF
Data (hex)
FF
41
5A
FF
FF
section
header
digital
-- 0x43 Go into configuration mode
byte #
1
2
3
4
5
Command (hex)
01
43
00
0x01
00
Data (hex)
FF
41
5A
FF
FF
section
header
digital
-- 0x44 Turn on analog mode
byte #
1
2
3
4
5
6
7
8
9
Command (hex)
01
44
00
0x01
0x03
00
00
00
00
Data (hex)
FF
F3
5A
00
00
00
00
00
00
section
header
config parameters
-- 0x4D Setup motor command mapping
byte #
1
2
3
4
5
6
7
8
9
Command (hex)
01
4D
00
00
01
FF
FF
FF
FF
Data (hex)
FF
F3
5A
00
01
FF
FF
FF
FF
section
header
config parameters
-- 0x4F Config controller to return all pressure values
byte #
1
2
3
4
5
6
7
8
9
Command (hex)
01
4F
00
FF
FF
03
00
00
00
Data (hex)
FF
F3
5A
00
00
00
00
00
5A
section
header
config parameters
-- 0x43 Exit config mode
byte #
1
2
3
4
5
6
7
8
9
Command (hex)
01
43
00
0x00
5A
5A
5A
5A
5A
Data (hex)
FF
F3
5A
00
00
00
00
00
00
section
header
config parameters
-- 0x42 Example Poll (loop this)
byte #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Command (hex)
01
42
00
WW
YY
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
Data (hex)
FF
79
5A
FF
FF
7F
7F
7F
7F
00
00
00
00
00
00
00
00
00
00
00
00
section
header
digital
analog joy
button pressures (0xFF = fully pressed)
analog map

RX
RY
LX
LY
R
L
U
D
Tri
O
X
Sqr
L1
R1
L2
R2

 






Note:The default data byte value from a controller is 0xFF So if select is pressed then the data in Byte0 will be 0xFE (0b1111 1110) similarly if left arrow (<- )is pressed then byte0 value will be 0x7F and so on for all other digital keys.

       -----------------Code-------------- 


#ifndef F_CPU
#define F_CPU 16000000L
#endif


#include <util/delay.h>
#include <avr/io.h>
#include <math.h>

unsigned char spi(unsigned char data)
{
       //Start transmission
       SPDR = data;
       //Wait for transmission complete
       while (!(SPSR & (1<<SPIF)));
       return SPDR;
}

int main(void)
{
       int data0,data1,data2,data3,data4,data5,a,b,c,d=0;
      
       int x,y,z;
      
       // Port A initialization
       PORTA=0x00;
       DDRA=0xFE; //A0-ip 1234567-op 0b11111110

       // Port B initialization
       PORTB=0x00;
       DDRB=0xB0;

       // Port C initialization
       PORTC=0x00;
       DDRC=0xFF;

       // Port D initialization
       PORTD=0x00;
       DDRD=0x30;
      
       //init timer 1
       TCCR1A=0xA1;
       TCCR1B=0x0A;
       ICR1H=0x00;
       ICR1L=0x00;
       OCR1AH=0x00;
       OCR1AL=0x00;
       OCR1BH=0x00;
    //configuring spi in mode3
       SPCR=0x7E;
       SPSR=0x01;

       TWCR=0x00;


      PORTA|=(1<<PORTA3);
      while(d!= 0x73) // locking the controller on analog mode
      {
            
             PORTB|=(1<<PORTB5)|(1<<PORTB7); //set
             PORTB&=~(1<<PORTB4); //clr
            
            
             spi(0x01); //entering config mode
             spi(0x43);
             spi(0x00);
             spi(0x01);
             spi(0x00);
            
             PORTB|=(1<<PORTB5);
             _delay_ms(1);
             PORTB|=(1<<PORTB4);

             _delay_ms(10);

            
             PORTB|=(1<<PORTB5)|(1<<PORTB7); //setting
             
             PORTB&=~(1<<PORTB4); // clearing

             spi(0x01); //seting analog mode
             spi(0x44);
             spi(0x00);
             spi(0x01);
             spi(0x03);
             spi(0x00);
             spi(0x00);
             spi(0x00);
             spi(0x00);

             PORTB|=(1<<PORTB5);
             _delay_ms(1);
             PORTB|=(1<<PORTB4);

             _delay_ms(10);

            
             PORTB|=(1<<PORTB5)|(1<<PORTB7);
             PORTB&=~(1<<PORTB4);

             spi(0x01);/*was using this to poll.The code will work fine even without this*/
             spi(0x43);
             spi(0x00);
             spi(0x00);
             spi(0x5A);
             spi(0x5A);
             spi(0x5A);
             spi(0x5A);
             spi(0x5A);

             PORTB|=(1<<PORTB5);
             _delay_ms(1);
             PORTB|=(1<<PORTB4);
             _delay_ms(10);


            
            
             PORTB|=(1<<PORTB5)|(1<<PORTB7);
             PORTB&=~(1<<PORTB4);
             spi(0x01);
             d=spi(0x42); //making sure we're in the analog mode the value of d will be 0x73
             spi(0x00);   // if d is not equal to 0x73 this loop will repeat 
             spi(0x00);
             spi(0x00);
             spi(0x00);
             spi(0x00);
             spi(0x00);
             spi(0x00);
      PORTB|=(1<<PORTB5);
             _delay_ms(1);
             PORTB|=(1<<PORTB4);
             _delay_ms(10);
            
      }
        
       while(d==0x73) 
       {
         while (1)
     { 
     
       PORTB|=(1<<PORTB5) | (1<<PORTB7);
       PORTB&=~(1<<PORTB4);
        a=spi(0x01);                               
        b=spi(0x42);                               
        c=spi(0x00);
                                             

        data0 = spi(0x00); //buttons set 1 8                     
        data1 = spi(0x00); //button set 2  8        
        data2 = spi(0x00); //  rx                          
        data3 = spi(0x00); //  ry                    
        data4 = spi(0x00); //  lx                     
        data5 = spi(0x00); //  ly                     

        _delay_us(1);
        PORTB|=(1<<PORTB5);                    
        _delay_us(1);
        PORTB|=(1<<PORTB4);
}}



Hope this was helpful .................... Let me know if there are any mistakes in this .........

5 comments:

  1. hi i am working with atmega 8535 for interfacing with ps2 wired controller
    can you help me please?
    can i have for email-id.......

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. what is the use of timer pwm

    ReplyDelete
  4. I am using this code for atmega 2560 but this code is not working i have changed all the freq and registers according to atmega 2560

    ReplyDelete

Total Pageviews

3,847