NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Interfacing a PS2 Controller with the Nerdkits

January 29, 2010
by Ethanal
Ethanal's Avatar

A couple years ago, I bought this for my NXT, but now, I am trying to interface it with the Nerdkits. I found some sample code for the controller written in a c-like language called NXC and I am now trying to translate it into regular C for the Atmega168. The board talks to the NXT over I2C (whatever that is).

Can anyone help me translate this?

The original this how far I've gotten on the header-like file:

/*-------------------------------------- Controller button layout:


L1 R1 L2 R2

d triang a c square circle b cross

l_j_b r_j_b l_j_x r_j_x l_j_y r_j_y

-------------------------------------- / / bits as follows: b1: a b c d x r_j_b l_j_b x b2: square cross circle triang R1 L1 R2 L2 */

/************/

//done struct psp { unsigned char b1; //raw byte read from PSP-Nx unsigned char b2; //raw byte read from PSP-Nx

// computed button states
unsigned char   l1;
unsigned char   l2;
unsigned char   r1;
unsigned char   r2;
unsigned char   a;
unsigned char   b;
unsigned char   c;
unsigned char   d;
unsigned char   triang;
unsigned char   square;
unsigned char   circle;
unsigned char   cross;
unsigned char   l_j_b;  // joystick button state
unsigned char   r_j_b;  // joystick button state

int   l_j_x;   // analog value of joystick scaled from 0 to 100
int   l_j_y;   // analog value of joystick scaled from 0 to 100
int   r_j_x;   // analog value of joystick scaled from 0 to 100
int   r_j_y;   // analog value of joystick scaled from 0 to 100

};

/************/

void PSP_SendCommand(unsigned char port, unsigned char i2cAddr, unsigned char cmd) { unsigned char cmdBuf[]; ArrayBuild(cmdBuf, i2cAddr, 0x41, cmd); I2CWrite(port, 0, cmdBuf); int status = I2CCheckStatus(port); while (status > NO_ERR) status = I2CCheckStatus(port); }

/************/

void PSP_PowerOFF(byte port, byte i2cAddr) { PSP_SendCommand(port, i2cAddr, 'D'); }

/************/

void PSP_PowerON(byte port, byte i2cAddr) { PSP_SendCommand(port, i2cAddr, 'E'); }

/************/

void PSP_ReadButtonState(byte port, byte i2cAddr, psp & currState) {

unsigned char message[];
unsigned char buf[10];
int count, l;
unsigned char b0;
unsigned char b1;
unsigned char nByteReady = 0;

SetSensorLowspeed(port);

PSP_PowerON(port, i2cAddr);
//PSP_PowerOFF(port, i2cAddr);

currState.b1 = 0;
currState.b2 = 0;
currState.l1 = 0;
currState.l2 = 0;
currState.r1 = 0;
currState.r2 = 0;
currState.a = 0;
currState.b = 0;
currState.c = 0;
currState.d = 0;
currState.triang = 0;
currState.square = 0;
currState.circle = 0;
currState.cross = 0;
currState.l_j_b = 0;
currState.r_j_b = 0;
currState.l_j_x = 0;
currState.l_j_y = 0;
currState.r_j_x = 0;
currState.r_j_y = 0;

// 0x42 - Button 1
// 0x43 - Button 2
// 0x44 - X left
// 0x45 - Y left
// 0x46 - X right
// 0x47 - Y right

ArrayBuild(message, i2cAddr, 0x42);
while (I2CStatus(port, nByteReady) ==  STAT_COMM_PENDING);
count = 6;
if(I2CBytes(port, message, count, buf)) {
    b0 = buf[0];
    b1 = buf[1];

    currState.b1        = b0;
    currState.b2        = b1;

    currState.l_j_b     = (b0 >> 1) & 0x01;
    currState.r_j_b     = (b0 >> 2) & 0x01;

    currState.d         = (b0 >> 4) & 0x01;
    currState.c         = (b0 >> 5) & 0x01;
    currState.b         = (b0 >> 6) & 0x01;
    currState.a         = (b0 >> 7) & 0x01;

    currState.l2        = (b1     ) & 0x01;
    currState.r2        = (b1 >> 1) & 0x01;
    currState.l1        = (b1 >> 2) & 0x01;
    currState.r1        = (b1 >> 3) & 0x01;
    currState.triang    = (b1 >> 4) & 0x01;
    currState.circle    = (b1 >> 5) & 0x01;
    currState.cross     = (b1 >> 6) & 0x01;
    currState.square    = (b1 >> 7) & 0x01;

    currState.l_j_x = ((buf[2] - 128) * 100)/128;
    currState.l_j_y = ((buf[3] - 128) * 100)/128;
    currState.r_j_x = ((buf[4] - 128) * 100)/128;
    currState.r_j_y = ((buf[5] - 128) * 100)/128;

}

}

/************/

string PSP_format_bin ( int i ) { string s;

int j;

int b = 0x80; s = ""; for ( j = 0; j < 8; j++) { if ( i&b ) { s += NumToStr(1); } else { s += NumToStr(0); } b = b>>1; } return (s); }

This is the demo program (includes the header file above)

include "PSP-Nx-lib.nxc"

const byte SensorPort = IN_1;

define ADDR 0x02

/*-------------------------------------- Controller button layout:


  L1                R1
  L2                R2

  d                 triang

a c square circle b cross

 l_j_b              r_j_b
 l_j_x              r_j_x
 l_j_y              r_j_y

-------------------------------------- / / bits as follows: b1: a b c d x r_j_b l_j_b x b2: square cross circle triang R1 L1 R2 L2 */

task main() { string msg, msg0, msg1, msg2, msg3; psp currState; string x; int i;

while (true ) {

PSP_ReadButtonState(SensorPort, ADDR, currState);

msg = "b1:          nxc";
x = PSP_format_bin(currState.b1);
msg = StrReplace(msg, 3, x);
TextOut(0, LCD_LINE1, msg, false);

msg = "b2:             ";
x = PSP_format_bin(currState.b2);
msg = StrReplace(msg, 3, x);
TextOut(0, LCD_LINE2, msg, false);

msg = "   . .       . .  ";
x = NumToStr(currState.l1);
msg = StrReplace(msg, 3, x);
x = NumToStr(currState.l2);
msg = StrReplace(msg, 5, x);
x = NumToStr(currState.r1);
msg = StrReplace(msg, 13, x);
x = NumToStr(currState.r2);
msg = StrReplace(msg, 15, x);
TextOut(0, LCD_LINE3, msg, false);

msg = "    .         .   ";
x = NumToStr(currState.d);
msg = StrReplace(msg, 4, x);
x = NumToStr(currState.triang);
msg = StrReplace(msg, 14, x);
TextOut(0, LCD_LINE4, msg, false);

msg = "   . .       . .  ";
x = NumToStr(currState.a);
msg = StrReplace(msg, 3, x);
x = NumToStr(currState.c);
msg = StrReplace(msg, 5, x);
x = NumToStr(currState.square);
msg = StrReplace(msg, 13, x);
x = NumToStr(currState.circle);
msg = StrReplace(msg, 15, x);
TextOut(0, LCD_LINE5, msg, false);

msg = "    .         .   ";
x = NumToStr(currState.b);
msg = StrReplace(msg, 4, x);
x = NumToStr(currState.cross);
msg = StrReplace(msg, 14, x);
TextOut(0, LCD_LINE6, msg, false);

msg = "l:               ";
x = NumToStr(currState.l_j_x);
msg = StrReplace(msg, 2, x);
x = NumToStr(currState.l_j_y);
msg = StrReplace(msg, 7, x);
TextOut(0, LCD_LINE7, msg, false);

msg = "r:               ";
x = NumToStr(currState.r_j_x);
msg = StrReplace(msg, 2, x);
x = NumToStr(currState.r_j_y);
msg = StrReplace(msg, 7, x);
TextOut(0, LCD_LINE8, msg, false);

}

}

Thanks!

January 29, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Ethenal,

It sounds like you have found yourself a really neat project on your hands. My suggestion is to try to step back a little and understand the I2C protocol a little better (also known as the TWI - Two Wire Interface). From the little bit of reading I did into that controller it seems the NXT abstracts away an awful lot of the actual communication which makes it easy to use, but pretty much impossible to understand.

The Atmega168 has an on board module to handle I2C. In the datasheet it is called the 2 wire serial interface. Take a look at that section of the datasheet, along with a few threads on the forums about the two wire interface. Try to just read the raw data coming out of the controller, without worrying about decoding it. Once you have a bitstream coming out of your controller, you can start trying to see what that NXT code does and decode what the controller is sending.

Hope that gets you going in the right direction!

Humberto

January 29, 2010
by Ethanal
Ethanal's Avatar

Thanks!

By "reading the raw data" do you mean using an oscilloscope, or connecting the controller to the Atmega168 and reading I2C data from there (via serial or lcd)?

February 02, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi Ethanal,

I guess I meant, any way you can get find to read the raw bit stream. If you have an oscilloscope handy, then great! That should let you immediately see the signal coming out, then all you have to do is decode it. If not, then you have to use the MCU to try to catch the I2C and send it down the serial port to see.

Humberto

February 02, 2010
by Ethanal
Ethanal's Avatar

I don't have an oscilloscope, but I have a Bus Pirate coming in the mail soon. I guess I can use that or the MCU.

Thanks!

Post a Reply

Please log in to post a reply.

Did you know that interrupts can be used to trigger pieces of code when events happen? Learn more...