Hardware used:
Arduino Mega 2560, PS2 controller, Open Bench Logic Analyzer, laptop
Project Goal:
I am working on a project where I am polling data from a PS2 controller and trying to send the data collected back to a PC so it can be viewed on the serial monitor.
Problem:
The controller uses an SPI bus for its communication protocol. I started out just getting the SPI part working. Using a logic analyzer to spy on the data being passed back and forth, I have determined that I can successfully send a command to the controller and have it send back valid data over the SPI bus. Great!
The next step was to take the data that had been collected, organize it and send it over the Serial port (That is the USB / Serial port). This is where I ran into trouble. So the order of operations is Send a series of commands over SPI, analyze the data, send the data over the USB serial connection, repeat.
What I notice is this. With just the SPI code and data processing code present I am able to communicate just fine with the PS2 controller. Here is the working code below:
// This program attempts to poll data from a PS2 controller using SPI protocol, break that data up into useful chunks and send the chunks over the USB/Serial connection so the values
//can be viewed on the serial monitor
//17Apr12
#include <SPI.h>
void setup(){
//Clock high when idle, data read on clock transition from hi to lo
SPI.setDataMode(SPI_MODE3);
//Clock to 500khz
SPI.setClockDivider(SPI_CLOCK_DIV32);
SPI.setBitOrder(LSBFIRST);
SPI.begin();
//Setup SS pins
pinMode(SS, OUTPUT);
digitalWrite(SS,HIGH);
//Setup Serial to relay data back to Serial Monitor
Serial.begin(9600);
}
void loop(){
//Variable to hold data from controller
int confirm = 0; int dataHi = 0; int dataLo = 0; int data =0; int goodData = 0; int garbage = 0;
//Send 0x01, 0x42, 0x00 (18 times) This is a PS2 command to poll the controller
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x01); //Should return 0x00
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
data = SPI.transfer(0x42); //Return varies depending on mode the controller is in
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
confirm = SPI.transfer(0x00); //Should return 0x5D
//Serial.println(confirm);
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x00); //Used to control motor in controller
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x00); //Used to control motor in controller
digitalWrite(SS,HIGH);
for(int x = 0; x < 16; x++){ //Controller may spit back up to 16 more bytes, this is here as a dumb way to make sure all the bytes are clocked through
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x00);
digitalWrite(SS,HIGH);
}
dataHi = (data & 0xF0) >> 4; //Get high Nibble
dataLo = data & 0xF; //Get low nibble
//Serial.print("data = "); Serial.print(data); Serial.println(" ");
//Serial.print("dataHi = "); Serial.print(dataHi); Serial.println(" ");
//Serial.print("dataLo = "); Serial.print(dataLo); Serial.println(" ");
//Was this a valid read? Was the 3rd byte back 0x5D?
if(confirm == 0x5D) {
goodData = 1;
//Serial.print("Did it read 0x5D? "); Serial.println(goodData); Serial.println(" ");
}//end if
}//end loop
The next step is to uncomment the Serial.print commands so I can send that data back to the PC. Here it is:
// This program attempts to poll data from a PS2 controller using SPI protocol, break that data up into useful chunks and send the chunks over the USB/Serial connection so the values
//can be viewed on the serial monitor
//17Apr12
#include <SPI.h>
void setup(){
//Clock high when idle, data read on clock transition from hi to lo
SPI.setDataMode(SPI_MODE3);
//Clock to 500khz
SPI.setClockDivider(SPI_CLOCK_DIV32);
SPI.setBitOrder(LSBFIRST);
SPI.begin();
//Setup SS pins
pinMode(SS, OUTPUT);
digitalWrite(SS,HIGH);
//Setup Serial to relay data back to Serial Monitor
Serial.begin(9600);
}
void loop(){
//Variable to hold data from controller
int confirm = 0; int dataHi = 0; int dataLo = 0; int data =0; int goodData = 0; int garbage = 0;
//Send 0x01, 0x42, 0x00 (18 times) This is a PS2 command to poll the controller
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x01); //Should return 0x00
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
data = SPI.transfer(0x42); //Return varies depending on mode the controller is in
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
confirm = SPI.transfer(0x00); //Should return 0x5D
//Serial.println(confirm);
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x00); //Used to control motor in controller
digitalWrite(SS,HIGH);
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x00); //Used to control motor in controller
digitalWrite(SS,HIGH);
for(int x = 0; x < 16; x++){ //Controller may spit back up to 16 more bytes, this is here as a dumb way to make sure all the bytes are clocked through
digitalWrite(SS,LOW);
garbage = SPI.transfer(0x00);
digitalWrite(SS,HIGH);
}
dataHi = (data & 0xF0) >> 4; //Get high Nibble
dataLo = data & 0xF; //Get low nibble
Serial.print("data = "); Serial.print(data); Serial.println(" ");
Serial.print("dataHi = "); Serial.print(dataHi); Serial.println(" ");
Serial.print("dataLo = "); Serial.print(dataLo); Serial.println(" ");
//Was this a valid read? Was the 3rd byte back 0x5D?
if(confirm == 0x5D) {
goodData = 1;
Serial.print("Did it read 0x5D? "); Serial.println(goodData); Serial.println(" ");
}//end if
}//end loop
When I run this second piece of code, I notice that my SPI bus stops working correctly. I seem to get no responses from the PS2 controller. I checked this with the logic analyzer and in the code (the if statement toward the end). However, the serial data is being sent over the USB port and I can read it on my serial monitor, but no SPI data is being received from the controller.
Any ideas on why this might be happening?
Thanks!