diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 94 |
1 files changed, 87 insertions, 7 deletions
@@ -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); |