summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c94
1 files changed, 87 insertions, 7 deletions
diff --git a/main.c b/main.c
index 64b811d..4a5135c 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,43 @@
+// AVR gamecube controller interface
+// Copyright (C) 2014 Florian Jung
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+
+/* Setup:
+
+ lfuse: 0xe0
+ hfuse: 0xd9
+
+ attach a 12MHz quartz to the atmega8, using the appropriate XTAL pins.
+
+ supply 3.3V to the 3.3V line of the gamecube controller.
+ supply 5V to the 5V line of the gamecube controller.
+ connect the GND and SHIELD lines of the controller to the common GND.
+ connect the DATA line of the gamecube controller to the C5 pin.
+
+ !!! ensure that the PORTC has bit 0 cleared at any time. !!!
+ !!! otherwise, +5V is supplied to the pin; the gamecube !!!
+ !!! controller, however, may shortcut the line down to !!!
+ !!! GND at any time, leading to HARDWARE DAMAGE. !!!
+*/
+
#include <avr/io.h>
#include <avr/delay.h>
-static char buffer[300];
+static char buffer[300]; // contains the exploded bits, i.e. each bit sent/received occupies one byte here.
#define OUT0 "sbi %2, 5 \n" /* pull line to GND */
#define OUT1 "cbi %2, 5 \n" /* tristate the line */
@@ -11,9 +47,40 @@ static char buffer[300];
#define WAIT10MINUS10 ""
#define WAIT34MINUS10 "ldi r16,5 \n rcall delay_loop \n nop \n nop \n"
-
+/* send the first "len" bytes stored in "bytes" to the controller,
+ * then receive the reply and store it into the global "buffer". */
int send_recv_gc(char* bytes, int len)
{
+ /* Phase 1: Send the data.
+ * Phase 1.1: Explode the bits into buffer. buffer[0..7] will contain the bits of bytes[0],
+ * buffer[8..15] contains the bits of bytes[1], and so on. MSB first.
+ * Phase 1.2: Actually send the data.
+ *
+ * intermediate Phase: wait for data line to become high again.
+ *
+ * Phase 2: Receive the reply.
+ * Phase 2.1: Busy-loop until the line is pulled down for the first time.
+ * Phase 2.2: Actually receive now:
+ * A counter is set to 0x80.
+ * Busy-loop until the line becomes high. Increment the counter in each iteration.
+ * (The line is now high.)
+ * Busy-loop until the line becomes low again. Decrement the counter each iteration.
+ * (Done receiving the bit)
+ * Write out the counter to buffer[], and proceed with the next bit.
+ *
+ * If the counter over- or underflows, stop receiving, because the line
+ * seems to be idle again (i.e. data transfer is finished). That's a timeout
+ * of ca. 53 us. (when running at 12 MHz)
+ *
+ * buffer[] now contains the counter values of the bits.
+ * if (buffer[42] > 0x80), i.e. (buffer[42] & 0x80), then the line was longer LOW than HIGH -> bit42 = 0
+ * otherwise, the line was longer HIGH than LOW -> bit42 = 1.
+ */
+
+ // The NOPs are there because of symmetry reasons.
+ // the "// 2" comments after the assembly directives are the number of cycles this
+ // instruction will take to execute.
+
char* buf_ptr = buffer;
/****** SEND PART ******/
@@ -150,32 +217,45 @@ int main (void)
while(1)
{
temp++;
- if (!(PIND & 0x08))
+ if (!(PIND & 0x08)) // check if uC is hung up
{
//PORTB=~(1 << ((temp>>9)%6));
PORTB=~temp;
}
- else if (!(PIND & 0x20))
+ else if (!(PIND & 0x20)) // debug num_received
{
PORTB=~n_received>>3;
}
- else if (!(PIND & 0x40))
+ else if (!(PIND & 0x40)) // clear debug output
{
PORTB=~0x00;
}
else
{
+ // decode "buffer" and write button states to PORTB
+
//PORTB=~buffer[4];
- char tmp=0;
+ unsigned char tmp2=0;
for (int i=0;i<8;i++)
+ tmp2|= ( (buffer[55-i]&0x80)?0:(1<<i) );
+
+ char tmp=0;
+ for (int i=1;i<8;i++)
tmp|= ( (buffer[i]&0x80)?0:(1<<i) );
+
+ if ( (temp & 0xFF) > tmp2 )
+ tmp|=1;
+
PORTB=~tmp;
}
- _delay_ms(1);
+ _delay_ms(0.3);
char foo[] = { 0x40, 0x03, 0x02 };
+ if (!(PIND & 0x10))
+ foo[2]=0x03;
+
n_received=send_recv_gc(foo, 3);