Hey Guys! This is my first post so forgive me if I do anything out of the norm!
So here's my goal, I built a 4x4x4 LED cube and controlled it with a pic18f4520, that was pretty cool at first, but it isn't terribly interesting. So to spice things up a bit I decided I'd implement a 3D Snake game on it. And I still think that'd be pretty cool, but nobody wants to play any game with just a few buttons attached to a PCB. No no no, that'd be boring. So I figured why not use a controller that is widely loved (and that I had lying around) the Game Cube controller! But it just wont work! AH!
It uses a 3.43v bidirectional dataline to communicate with the gamecube. so, using a voltage regulator and a pull up resistor I pulled up the line (which is port A0) to 3.43 volts. Then I toggle it from input to output in order to simulate an open-drian output. I've tested this, and it seems to work just fine.
So the GameCube itself sends a 24 bit (+ 1 termination bit) signal to the controller as a status update, then the controller responds with a 64 bit (+ 1 termination bit) update.
Each bit takes place over 4 microseconds, and is divided into 3 parts:
1 microsecond low ( 0 volts )
2 microseconds data ( 0 or 3.43 volts )
1 microsecond high (3.43 volts)
So the low and high bits look like this:
Low: _ _ _ ¯ (4 microseconds)
High: _ ¯ ¯ ¯ (4 microseconds)
If you're interested the protocol is documented here.
I'm running a 10 MHz Crystal (with 15 pf caps) with PLL enabled, so I have 10 cycles for 1 microsecond, so the timing shouldn't be too difficult. But I just cant get the gamecube controller to respond! Here's the code I've written so far. All it does is send the 24 bit signal, and monitor to see if anything pulls A0 low, and if anything does (which it should if the controller responds!) it lights an LED. But it wont light
I posted my code below! If anyone has any insight or any more questions or anything I'd love to hear back! Thanks for taking the time!
Yashar
So here's my goal, I built a 4x4x4 LED cube and controlled it with a pic18f4520, that was pretty cool at first, but it isn't terribly interesting. So to spice things up a bit I decided I'd implement a 3D Snake game on it. And I still think that'd be pretty cool, but nobody wants to play any game with just a few buttons attached to a PCB. No no no, that'd be boring. So I figured why not use a controller that is widely loved (and that I had lying around) the Game Cube controller! But it just wont work! AH!
It uses a 3.43v bidirectional dataline to communicate with the gamecube. so, using a voltage regulator and a pull up resistor I pulled up the line (which is port A0) to 3.43 volts. Then I toggle it from input to output in order to simulate an open-drian output. I've tested this, and it seems to work just fine.
So the GameCube itself sends a 24 bit (+ 1 termination bit) signal to the controller as a status update, then the controller responds with a 64 bit (+ 1 termination bit) update.
Each bit takes place over 4 microseconds, and is divided into 3 parts:
1 microsecond low ( 0 volts )
2 microseconds data ( 0 or 3.43 volts )
1 microsecond high (3.43 volts)
So the low and high bits look like this:
Low: _ _ _ ¯ (4 microseconds)
High: _ ¯ ¯ ¯ (4 microseconds)
If you're interested the protocol is documented here.
I'm running a 10 MHz Crystal (with 15 pf caps) with PLL enabled, so I have 10 cycles for 1 microsecond, so the timing shouldn't be too difficult. But I just cant get the gamecube controller to respond! Here's the code I've written so far. All it does is send the 24 bit signal, and monitor to see if anything pulls A0 low, and if anything does (which it should if the controller responds!) it lights an LED. But it wont light
I posted my code below! If anyone has any insight or any more questions or anything I'd love to hear back! Thanks for taking the time!
Yashar
Rich (BB code):
#include <p18f4520.h>
void assembly(void);
void main(void)
{
unsigned int i,j,check;
check=0;
// Set all outputs to Digital
ADCON1 = 0xFF;
CMCON=0x07;
// Initialize pins
LATD = 0x00;
TRISD = 0x00;
LATA = 0x00;
TRISA = 0x01;
while(1)
{
assembly();
LATDbits.LATD0 = ~LATDbits.LATD0; //toggle this LED for fun
// Just a delay that ALSO checks if anything drives RA0 low
// but mostly it's just a delay to see the LED toggle
for ( i = 0; i < 30000; i++)
{
for(j=0; j<5; j++)
{
if(PORTAbits.RA0 == 0)
{
check=1;
}
}
}
if (check==1) LATDbits.LATD1=1;
}
}
void assembly(void)
{
_asm
//1 uS = 10 cycles
//3 uS = 30 cycles
//9 NOPs + instruction to set next bit should be 10 cycles
//We want to send 0100 0000 0000 0011 0000 0011 <- The last bit is high because I want some rumble action!
//But don't forget to TERMINATE by sending a 1 at the end of the 24 bit stream.
//First 0100
CALL sendZero, 0
CALL sendOne, 0
CALL sendZero, 0
CALL sendZero, 0
// Then 0000
CALL sendZero, 0
CALL sendZero, 0
CALL sendZero, 0
CALL sendZero, 0
// And 0000
CALL sendZero, 0
CALL sendZero, 0
CALL sendZero, 0
CALL sendZero, 0
// Followed by 0011
CALL sendZero, 0
CALL sendZero, 0
CALL sendOne, 0
CALL sendOne, 0
// Proceded with 0000
CALL sendZero, 0
CALL sendZero, 0
CALL sendZero, 0
CALL sendZero, 0
// Finally 0011
CALL sendZero, 0
CALL sendZero, 0
CALL sendOne, 0
CALL sendOne, 0
// Terminated with 1, After termination A0 will be an input, and should be high.
CALL sendOne, 0
// Check to see if anything drives A0 low.
// This is just to see if we get any thing back
MOVLW 0xFF
MOVWF 0x0B, 0
loopB:
MOVLW 0xFF
MOVWF 0x0A, 0
loopA:
BTFSS PORTA, 0, 0 // Skip next instrucion if A0 is high
BSF LATD, 1, 0
DECFSZ 0x0A, 1, 0
BRA loopA
DECFSZ 0x0B, 1, 0
BRA loopB
GOTO fin // This ends the ASM before Functions
//============================================================================
//========================Function Declarations===============================
//============================================================================
sendZero:
BCF TRISA, 0, 0 // 1 - Set A0 as output (low) for 3 uSeconds
CALL delay29, 0 // 29 = 2(call) + 25(NOP) + 2(return)
BSF TRISA, 0, 0 // 1 - Set A0 as input (high) for 1 uSecond
CALL delay5, 0 // 5 = 2(call) + 1(NOP) + 2(return)
// A0 has been high for 5 cycles already. Next we will return from
// this function (2 clock cycles) and call another one (2 clock cycles)
// then set change A0 again (1 clock cycle). So 5 clock cycles remain.
sendOne:
BCF TRISA, 0, 0 // 1 - Set A0 as output (low) for 1 uSeconds
CALL delay9, 0 // 9 = 2(call) + 5(NOP) + 2(return)
BSF TRISA, 0, 0 // 1 - Set A0 as input (high) for 3 uSecond
CALL delay25, 0 // 25 = 2(call) + 21(NOP) + 2(return)
// A0 has been high for 25 cycles already. Next we will return from
// this function (2 clock cycles) and call another one (2 clock cycles)
// then set change A0 again (1 clock cycle). So 5 clock cycles remain.
delay29: // Including the CALL this is a 29 cycle delay
NOP // 1
NOP // 1
NOP // 1
NOP // 1
delay25:
NOP // 1 // 5
NOP // 1
NOP // 1
NOP // 1
NOP // 1
NOP // 1 // 10
NOP // 1
NOP // 1
NOP // 1
NOP // 1
NOP // 1 // 15
NOP // 1
NOP // 1
NOP // 1
NOP // 1
NOP // 1 // 20
delay9:
NOP // 1
NOP // 1
NOP // 1
NOP // 1
delay5:
NOP // 1 // 25
RETURN 0 // 2
fin:
_endasm
}