Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Nintendo 64 Controller to Arduino sketch
- * By Waffle (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?action=viewprofile;username=Waffle)
- * See this Arduino forum thread for info: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261980415
- *
- * Connect N64 controller +3.3V line to Arduino 3.3V line
- * Connect N64 controller ground line to Arduino ground
- * Connect N64 controller data line to an Arduino I/O pin with a 1K pull-up resistor to 3.3V line
- *
- * Set Arduino pin used for data line in the follow three #defines:
- * Example for Arduino pin 9: N64_DATA_DDR = DDRB, N64_DATA_PIN = PINB, N64_DATA_PIN_NO = PINB1
- */
- #define N64_DATA_DDR DDRB
- #define N64_DATA_PIN PINB
- #define N64_DATA_PIN_NO PINB1
- #include <util/delay.h>
- /* based off the 'N64/Gamecube controller to USB adapter' by Rapha�l Ass�nat (http://www.raphnet.net/electronique/gc_n64_usb/index_en.php)
- * modifications/improvements:
- * - adjusted timing for 16 MHz
- * - support writing variable length data
- * - receive variable length data directly packed into destination buffer
- */
- uint8_t n64cmd(uint8_t rxdata[], uint8_t rxlen, uint8_t txdata[], uint8_t txlen) {
- uint8_t num = 0;
- uint8_t oldSREG = SREG;
- cli();
- asm volatile(
- "nextByte%=: \n"
- " cpi %[txlen], 0 \n" // 1
- " breq done%= \n" // 1
- " dec %[txlen] \n" // 1
- " ld r16, z+ \n" // 2
- " ldi r17, 0x80 \n" // 1
- "nextBit%=: \n"
- " mov r18, r16 \n" // 1
- " and r18, r17 \n" // 1
- " breq send0%= \n" // 2
- " nop \n"
- // 1us low, 1us high
- "send1%=: \n"
- " sbi %[ddr], %[pinNo] \n" // 2
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop \n" // 2
- " cbi %[ddr], %[pinNo] \n" // 2
- " ldi r19, 11 \n" // 1
- "lp1%=: dec r19 \n" // 1
- " brne lp1%= \n" // 2
- " lsr r17 \n" // 1
- " breq nextByte%= \n" // 1
- " nop\nnop\nnop\nnop \n" // 4
- " nop \n" // 1
- " rjmp nextBit%= \n" // 2
- // 3us low, 1us high
- "send0%=: sbi %[ddr], %[pinNo] \n" // 2
- " ldi r19, 15 \n" // 1
- "lp0%=: dec r19 \n" // 1
- " brne lp0%= \n" // 2
- " nop \n" // 1
- " cbi %[ddr], %[pinNo] \n" // 2
- " nop \n" // 1
- " lsr r17 \n" // 1
- " breq nextByte%= \n" // 1
- " nop\nnop\nnop\nnop \n" // 4
- " nop \n" // 1
- " rjmp nextBit%= \n" // 2
- // finished sending, sync up to the stop bit time
- "done%=: \n"
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop \n" // 3
- // stop bit
- " sbi %[ddr], %[pinNo] \n" // 2
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop \n" // 2
- " cbi %[ddr], %[pinNo] \n"
- // stop now if there's nothing to receive
- " cpi %[rxlen], 0 \n" // 1
- " breq end%= \n" // 1
- // receiving
- " clr r18 \n" // 1 current byte
- " ldi r17, 0x80 \n" // 1 current bit
- "st%=: \n"
- " ldi r16, 0xff \n" // 1 setup timeout
- "waitFall%=: \n"
- " dec r16 \n" // 1
- " breq end%= \n" // 1
- " sbic %[pin], %[pinNo] \n" // 2
- " rjmp waitFall%= \n"
- // wait about 2us to check the state
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " nop\nnop\nnop\nnop \n" // 4
- " sbic %[pin], %[pinNo] \n" // 2
- " or r18, r17 \n"
- " lsr r17 \n" // 1
- " brne nextRxBit%= \n" // 2
- "nextRxByte%=: \n"
- " st x+, r18 \n" // 2 store the value
- " inc %[num] \n" // 1 increase number of received bytes
- " cp %[rxlen], %[num] \n" // 1 check for finish
- " breq end%= \n" // 1
- " clr r18 \n" // 1
- " ldi r17, 0x80 \n" // 1
- "nextRxBit%=: \n"
- " ldi r16, 0xff \n" // 1 setup timeout
- "waitHigh%=: \n"
- " dec r16 \n" // 1 decrement timeout
- " breq end%= \n" // 1 handle timeout condition
- " sbis %[pin], %[pinNo] \n" // 2
- " rjmp waitHigh%= \n"
- " rjmp st%= \n" // 2
- "end%=: \n"
- : [num] "=r"(num)
- : [ddr] "I"(_SFR_IO_ADDR(N64_DATA_DDR)), [pin] "I"(_SFR_IO_ADDR(N64_DATA_PIN)), [pinNo] "I"(N64_DATA_PIN_NO),
- [rxdata] "x"(rxdata), [rxlen] "r"(rxlen),
- [txdata] "z"(txdata), [txlen] "r"(txlen), "0"(num)
- : "r16", "r17", "r18", "r19"
- );
- SREG = oldSREG;
- _delay_us(100); // some commands leave the controller unresponsive for a while
- return num;
- }
- struct n64Buttons { // 4 byte struct of the N64 controller data
- uint8_t right : 1;
- uint8_t left : 1;
- uint8_t down : 1;
- uint8_t up : 1;
- uint8_t start : 1;
- uint8_t z : 1;
- uint8_t b : 1;
- uint8_t a : 1;
- uint8_t cRight : 1;
- uint8_t cLeft : 1;
- uint8_t cDown : 1;
- uint8_t cUp : 1;
- uint8_t r : 1;
- uint8_t l : 1;
- uint8_t unknown : 2;
- int8_t x;
- int8_t y;
- };
- n64Buttons prev; // hold last button status for reporting
- void setup() {
- Serial.begin(9600);
- }
- void loop() {
- // fetch new button status
- n64Buttons btn;
- uint8_t num = n64cmd((uint8_t*)&btn, 4, (uint8_t[]){0x01}, 1);
- // check if we got 4 bytes back, if not there must be a connection or controller problem
- if (num != 4) {
- Serial.println("Controller Error!");
- delay(1000);
- return;
- }
- // output if a button was just pressed
- if (btn.a && !prev.a)
- Serial.println('A');
- if (btn.b && !prev.b)
- Serial.println('B');
- if (btn.z && !prev.z)
- Serial.println('Z');
- if (btn.start && !prev.start)
- Serial.println("Start");
- if (btn.up && !prev.up)
- Serial.println("Up");
- if (btn.down && !prev.down)
- Serial.println("Down");
- if (btn.left && !prev.left)
- Serial.println("Left");
- if (btn.right && !prev.right)
- Serial.println("Right");
- if (btn.l && !prev.l)
- Serial.println('L');
- if (btn.r && !prev.r)
- Serial.println('R');
- if (btn.cUp && !prev.cUp)
- Serial.println("C-Up");
- if (btn.cDown && !prev.cDown)
- Serial.println("C-Down");
- if (btn.cLeft && !prev.cLeft)
- Serial.println("C-Left");
- if (btn.cRight && !prev.cRight)
- Serial.println("C-Right");
- // output analog stick values if it has changed
- if (btn.x != prev.x || btn.y != prev.y) {
- Serial.print("Stick: ");
- Serial.print(btn.x, DEC);
- Serial.print(", ");
- Serial.println(btn.y, DEC);
- }
- // set the previous to be the last
- prev = btn;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement