Arduino Digital Pin Speeds?

I recently came across this website: Nintendo Gamecube Controller Pinout
And it got me thinking about using an arduino to interface with a game cube controller. The hitch is the game cube uses a ridiculously fast one wire interface at the speed of 4us per bit.
The bit codes:
1 = low 1us, high 3us
0 = low 3us, high 1us

I think the “start data” code could be sent by the arduino using direct port access but how fast can it read and save digital pin inputs?

I was thinking it might be possible using an array and just spew the raw data into the array for 300 or so microseconds (the controller replies to the start code with 64 bits of information, taking 256microseconds, so I thought 300 to be safe), then sending the array to the computer for analysis.
1 sample + save to ram cycle would have to be <1microsecond (<16 clock cycles i think)
Anyone know if this is possible? I don’t want to start this and then find out later that it’s too quick to sample with arduino :wink:

(edit: trying to save you from horrible grammar)

Not sure if this code is a return or non return to zero code. But basically you would start timing at an edge and latch 2uS after the edge to get the data. Personally I would use a monostable and D-Type latch for this but then there are people who would rather do it all in software. As a compromise you might be able to do it using the internal counter / timers. I would also clock this data into a FIFO so I can clock it out at my leisure but it depends on what else you want your processor to do at the same time. But then that's me, I am a bit hardware centric. :)

I just found this http://www.raphnet.net/electronique/gc_n64_usb/index_en.php#schematic so I guess it is possible to do in code.

Your idea of latching 2uS after an edge is great, thanks, much simple than my idea

would something like:

int data[63];
int dbit=0;

void setup(){
attachInterrupt(0,save,FALLING);
}

void save()
{delayMicroseconds(2);
data[dbit]=digitalRead(2);
dbit=dbit+1;
}

work OK? Obviously to send the start sequence you would turn off the interrupt. And then once the array is filled up shift it to the computer and set dbit to 0

Yes give it a try. Although do bits always start on a falling edge?

Yep, the data line is 3.3v pull-up, and the bits always start low, then go high either 1us or 3us into the bit I'll give it a go tomorrow, I need an adjustable regulator for the data line and I don't have one lying around which is annoying. I'll post my results sometime tomorrow

Here’s the code I came up with but for some reason the only data I get back is just a whole heapo nothin’. which is weird because the data line is pull up so something must be sinking the power

int dbit =0;
int data[63];
int initialise=1;

void setup()
{ pinMode(2,INPUT);
pinMode(14,OUTPUT);
digitalWrite(2,LOW);
digitalWrite(14,LOW);

attachInterrupt(0,readdata,FALLING);
noInterrupts();
  Serial.begin(9600);
}

void loop()
{ 
 // if (initialise ==1){
  initcntrlr();
  interrupts();
  delayMicroseconds(300);
  noInterrupts();
  printdata();
  delay(60000);
 // initialise =0;
//}
//  if (initialise !=1){
 //if (Serial.available()){initialise = Serial.read();}}
}


  /* Initialization code is apparently:
  0100 0000 0000 0011 0000 0010
  */

void initcntrlr(){
PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(1);         //This is a 1
PORTC = B000000;
delayMicroseconds(3);
  
  PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(1);         //This is a 1
PORTC = B000000;
delayMicroseconds(3);

PORTC = B100000;
delayMicroseconds(1);         //This is a 1
PORTC = B000000;
delayMicroseconds(3);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);

PORTC = B100000;
delayMicroseconds(1);         //This is a 1
PORTC = B000000;
delayMicroseconds(3);

PORTC = B100000;
delayMicroseconds(3);         //This is a 0
PORTC = B000000;
delayMicroseconds(1);
}
  

void readdata(){
 delayMicroseconds(2);
data[dbit]=digitalRead(2);
dbit=dbit+1;
}
    
void printdata()
{for (int i=0;i<64;i++){
  Serial.println(data[i]);}
dbit = 0;
}

And here’s what comes in from the serial port

0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
260

anybody have any ideas?

First off try and see if interrupts are being triggered by turning on an LED (pin 13) in the interrupt service routine.

Then look to change:- PORTC = B100000; to PORTC |= 0x80;

and PORTC = B000000; to PORTC &= 0x7F;

This will just change the bit you want and not the whole port.

Thanks for all your help Grumpy_Mike, I really appreciate it

It seems that none the interrupt isn't triggered once, even when I turn the interrupts on before sending the initialization code. The data line is 3.3v pull up at about 5ma, and I'm sending the initialization through a transistor. I would have thought 3.3v would be plenty to make a pin HIGH.

So either the interrupts arn't triggering or I my output isn't working

OK I think it's my output since I can manually trigger the interrupt

OK, I’m using analog pin 0 and switching between Output state 0 and Input state 0, using it like an open drain

DDRC =B111111;
delayMicroseconds(3);         //This is a 0
DDRC =B000000;
delayMicroseconds(1);

seems to work
I also found out that delay doesn’t work inside interrupt triggered functions so I’m using for (int i=0;i<32;i++){} to kill aproximately 2us worth of clock cycles (I might be very wrong there)
I’m getting all 0’s for data still though buuuut the first bit is always 1 so I guess the interrupt function itself works, it’s just my implementation thats wrong

Well it looks like I'm finding out every way of not getting this to work. I have substituted asm("nop\n\t"); into the code for timing purposes because apparently delayMicroseconds is untrustworthy under 2uS.

Setting the interrupt to read the data at 3.5uS into the bit should return all ones. It doesn't. It does return

1
0
1
0
0
1
0
0
0
0
1
1
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

So more investigation must be done. At least I'm learning a ton about the intricacies of the Arduino langauge ;)

Keep going you'll get there in the end. :)

Progress Report
Right now I know that my initiation code does work, and that my setup works too (surprisingly). I had a lot of timing issues with the interrupt so right now I just want to know what code will reliably capture every bit.
This is what I’m using right now (I’ll be tweaking it in a few minutes anyway ;))

  for (int i=0;i<300;i++){
  __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t""nop\n\t");
  data[dbit]=PIND;
dbit=dbit+1;}
}

I’m using 10 no operations which mean that should leave 6 cycles for the rest to capture every microsecond. I don’t think this is the case though since looking at the data returned I can count 40 bits out of 64 that are meant to be sent.

Question: Does anyone know how many cycles a for takes up?
My guess was one for the comparison, one for the increment and one for the implementation, but I must have been wrong. Actually just typing this I reallise there must also be one for setting up the variable.

Anywho, thats where I’m at

(edit: also does anyone know what the sram overhead is apart from user code? I’m using a 300 byte array to store data, I don’t want to go any higher in case of the arduino going crazy)

More progress, not much though:

void monitor(){
  for (int i=0;i<300;i++){
 __asm__("nop\n\t""nop\n\t");
  data[dbit]=PIND;
dbit=dbit+1;}

Samples approx every 1uS so I can manually pick out the bits

1
0
0      -
0
1
0
0      - start bits
0
1
0
1
1      -
1
0
1
1      - the start button is pressed 
1
0
0      -Y isn't
0
1
0
0      -X isn't
0
1
0
0      -B isn't
0
1
0
1      -A is pressed
1      
1
1
0
0      -
0
1
0
0      - start bits
0
1
0
1
1      -
1
0
0      start isn't pressed
0
1
0
1      Y is pressed
1      
1
0
0      X isn't
0
1
0
1
1      B is pressed
1
0
0      A isn't
0
1

One thing I’ll look at soon is how fast the interrupt kicks in when the data line falls low. I’m thinking of just getting two arduinos, one running a attachInterrupt(0,readdata,FALLING) followed by an instant pin read, and the other one to go DDRC = B000000; DDRC = B111111, gradually putting more __asm(“nop\n\t”); between the port toggles until the other arduino can read it. I wish I had a scope :’(

Hello greendude, perhaps you'd be able to help me? http://forum.allaboutcircuits.com/showthread.php?p=150601#post150601