Hello Everyone,
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.
Thus to Summarize connect all the lines as directed above with all pins pulled up to VCC with a 10K resistor.
----------------- Programming ----------------

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 -------------------
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
1 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).
2 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.
3 Grey
7.6V :Vibration Motors Power: 6-9V.
4 Black
Ground
5 Red
VCC :Variable power from 5 V down to 3V.
6 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
7 Blue
Clock
500kHz THIS IS CONNECTED TO SCK (PIN PB7) of Atmega16
8 White
Not Connected: Reserved for future use.
9 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.
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 .........
hi i am working with atmega 8535 for interfacing with ps2 wired controller
ReplyDeletecan you help me please?
can i have for email-id.......
This comment has been removed by the author.
ReplyDeletehi
Deletewhat is the use of timer pwm
ReplyDeleteI 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