Advertisement
Guest User

Waffle

a guest
Jan 10th, 2010
917
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.27 KB | None | 0 0
  1. /*
  2.  * Nintendo 64 Controller to Arduino sketch
  3.  * By Waffle (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?action=viewprofile;username=Waffle)
  4.  * See this Arduino forum thread for info: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1261980415
  5.  *
  6.  * Connect N64 controller +3.3V line to Arduino 3.3V line
  7.  * Connect N64 controller ground line to Arduino ground
  8.  * Connect N64 controller data line to an Arduino I/O pin with a 1K pull-up resistor to 3.3V line
  9.  *
  10.  * Set Arduino pin used for data line in the follow three #defines:
  11.  * Example for Arduino pin 9: N64_DATA_DDR = DDRB, N64_DATA_PIN = PINB, N64_DATA_PIN_NO = PINB1
  12.  */
  13.  
  14. #define N64_DATA_DDR    DDRB
  15. #define N64_DATA_PIN    PINB
  16. #define N64_DATA_PIN_NO PINB1
  17.  
  18. #include <util/delay.h>
  19.  
  20. /* 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)
  21.  * modifications/improvements:
  22.  * - adjusted timing for 16 MHz
  23.  * - support writing variable length data
  24.  * - receive variable length data directly packed into destination buffer
  25.  */
  26. uint8_t n64cmd(uint8_t rxdata[], uint8_t rxlen, uint8_t txdata[], uint8_t txlen) {
  27.     uint8_t num = 0;
  28.     uint8_t oldSREG = SREG;
  29.  
  30.     cli();
  31.     asm volatile(
  32. "nextByte%=:                        \n"
  33. "           cpi %[txlen], 0         \n" // 1
  34. "           breq done%=             \n" // 1
  35. "           dec %[txlen]            \n" // 1
  36. "           ld r16, z+              \n" // 2
  37. "           ldi r17, 0x80           \n" // 1
  38. "nextBit%=:                         \n"
  39. "           mov r18, r16            \n" // 1
  40. "           and r18, r17            \n" // 1
  41. "           breq send0%=            \n" // 2
  42. "           nop                     \n"
  43.  
  44. // 1us low, 1us high
  45. "send1%=:                           \n"
  46. "           sbi %[ddr], %[pinNo]    \n" // 2
  47. "               nop\nnop\nnop\nnop  \n" // 4
  48. "               nop\nnop\nnop\nnop  \n" // 4
  49. "               nop\nnop\nnop\nnop  \n" // 4
  50. "               nop\nnop            \n" // 2
  51. "           cbi %[ddr], %[pinNo]    \n" // 2
  52. "               ldi r19, 11         \n" // 1
  53. "lp1%=:         dec r19             \n" // 1
  54. "               brne lp1%=          \n" // 2
  55. "           lsr r17                 \n" // 1
  56. "           breq nextByte%=         \n" // 1
  57. "               nop\nnop\nnop\nnop  \n" // 4
  58. "               nop                 \n" // 1
  59. "           rjmp nextBit%=          \n" // 2
  60.  
  61. // 3us low, 1us high
  62. "send0%=:   sbi %[ddr], %[pinNo]    \n" // 2
  63. "               ldi r19, 15         \n" // 1
  64. "lp0%=:         dec r19             \n" // 1
  65. "               brne lp0%=          \n" // 2
  66. "               nop                 \n" // 1
  67. "           cbi %[ddr], %[pinNo]    \n" // 2
  68. "               nop                 \n" // 1
  69. "           lsr r17                 \n" // 1
  70. "           breq nextByte%=         \n" // 1
  71. "               nop\nnop\nnop\nnop  \n" // 4
  72. "               nop                 \n" // 1
  73. "           rjmp nextBit%=          \n" // 2
  74.  
  75. // finished sending, sync up to the stop bit time
  76. "done%=:                            \n"
  77. "           nop\nnop\nnop\nnop      \n" // 4
  78. "           nop\nnop\nnop           \n" // 3
  79.  
  80. // stop bit
  81. "           sbi %[ddr], %[pinNo]    \n" // 2
  82. "               nop\nnop\nnop\nnop  \n" // 4
  83. "               nop\nnop\nnop\nnop  \n" // 4
  84. "               nop\nnop\nnop\nnop  \n" // 4
  85. "               nop\nnop            \n" // 2
  86. "           cbi %[ddr], %[pinNo]    \n"
  87.  
  88. // stop now if there's nothing to receive
  89. "           cpi %[rxlen], 0         \n" // 1
  90. "           breq end%=              \n" // 1
  91.  
  92. // receiving
  93. "           clr r18                 \n" // 1  current byte
  94. "           ldi r17, 0x80           \n" // 1  current bit
  95. "st%=:                              \n"
  96. "           ldi r16, 0xff           \n" // 1  setup timeout
  97. "waitFall%=:                        \n"
  98. "           dec r16                 \n" // 1
  99. "           breq end%=              \n" // 1
  100. "           sbic %[pin], %[pinNo]   \n" // 2
  101. "           rjmp waitFall%=         \n"
  102.  
  103. // wait about 2us to check the state
  104. "           nop\nnop\nnop\nnop      \n" // 4
  105. "           nop\nnop\nnop\nnop      \n" // 4
  106. "           nop\nnop\nnop\nnop      \n" // 4
  107. "           nop\nnop\nnop\nnop      \n" // 4
  108. "           nop\nnop\nnop\nnop      \n" // 4
  109. "           nop\nnop\nnop\nnop      \n" // 4
  110. "           nop\nnop\nnop\nnop      \n" // 4
  111.  
  112. "           sbic %[pin], %[pinNo]   \n" // 2
  113. "           or r18, r17             \n"
  114. "           lsr r17                 \n" // 1
  115. "           brne nextRxBit%=        \n" // 2
  116.  
  117. "nextRxByte%=:                      \n"
  118. "           st x+, r18              \n" // 2  store the value
  119. "           inc %[num]              \n" // 1  increase number of received bytes
  120. "           cp %[rxlen], %[num]     \n" // 1  check for finish
  121. "           breq end%=              \n" // 1
  122. "           clr r18                 \n" // 1
  123. "           ldi r17, 0x80           \n" // 1
  124.  
  125. "nextRxBit%=:                       \n"
  126. "           ldi r16, 0xff           \n" // 1  setup timeout
  127. "waitHigh%=:                        \n"
  128. "           dec r16                 \n" // 1  decrement timeout
  129. "           breq end%=              \n" // 1  handle timeout condition
  130. "           sbis %[pin], %[pinNo]   \n" // 2
  131. "           rjmp waitHigh%=         \n"
  132. "           rjmp st%=               \n" // 2
  133.  
  134. "end%=:                             \n"
  135.             : [num] "=r"(num)
  136.             : [ddr] "I"(_SFR_IO_ADDR(N64_DATA_DDR)), [pin] "I"(_SFR_IO_ADDR(N64_DATA_PIN)), [pinNo] "I"(N64_DATA_PIN_NO),
  137.                 [rxdata] "x"(rxdata), [rxlen] "r"(rxlen),
  138.                 [txdata] "z"(txdata), [txlen] "r"(txlen), "0"(num)
  139.             : "r16", "r17", "r18", "r19"
  140.             );
  141.     SREG = oldSREG;
  142.  
  143.     _delay_us(100); // some commands leave the controller unresponsive for a while
  144.  
  145.     return num;
  146. }
  147.  
  148. struct n64Buttons { // 4 byte struct of the N64 controller data
  149.     uint8_t right : 1;
  150.     uint8_t left : 1;
  151.     uint8_t down : 1;
  152.     uint8_t up : 1;
  153.     uint8_t start : 1;
  154.     uint8_t z : 1;
  155.     uint8_t b : 1;
  156.     uint8_t a : 1;
  157.     uint8_t cRight : 1;
  158.     uint8_t cLeft : 1;
  159.     uint8_t cDown : 1;
  160.     uint8_t cUp : 1;
  161.     uint8_t r : 1;
  162.     uint8_t l : 1;
  163.     uint8_t unknown : 2;
  164.     int8_t x;
  165.     int8_t y;
  166. };
  167.  
  168. n64Buttons prev; // hold last button status for reporting
  169.  
  170. void setup() {
  171.     Serial.begin(9600);
  172. }
  173.  
  174. void loop() {
  175.     // fetch new button status
  176.     n64Buttons btn;
  177.     uint8_t num = n64cmd((uint8_t*)&btn, 4, (uint8_t[]){0x01}, 1);
  178.  
  179.     // check if we got 4 bytes back, if not there must be a connection or controller problem
  180.     if (num != 4) {
  181.         Serial.println("Controller Error!");
  182.         delay(1000);
  183.         return;
  184.     }
  185.  
  186.     // output if a button was just pressed
  187.     if (btn.a && !prev.a)
  188.         Serial.println('A');
  189.     if (btn.b && !prev.b)
  190.         Serial.println('B');
  191.     if (btn.z && !prev.z)
  192.         Serial.println('Z');
  193.     if (btn.start && !prev.start)
  194.         Serial.println("Start");
  195.     if (btn.up && !prev.up)
  196.         Serial.println("Up");
  197.     if (btn.down && !prev.down)
  198.         Serial.println("Down");
  199.     if (btn.left && !prev.left)
  200.         Serial.println("Left");
  201.     if (btn.right && !prev.right)
  202.         Serial.println("Right");
  203.     if (btn.l && !prev.l)
  204.         Serial.println('L');
  205.     if (btn.r && !prev.r)
  206.         Serial.println('R');
  207.     if (btn.cUp && !prev.cUp)
  208.         Serial.println("C-Up");
  209.     if (btn.cDown && !prev.cDown)
  210.         Serial.println("C-Down");
  211.     if (btn.cLeft && !prev.cLeft)
  212.         Serial.println("C-Left");
  213.     if (btn.cRight && !prev.cRight)
  214.         Serial.println("C-Right");
  215.  
  216.     // output analog stick values if it has changed
  217.     if (btn.x != prev.x || btn.y != prev.y) {
  218.         Serial.print("Stick: ");
  219.         Serial.print(btn.x, DEC);
  220.         Serial.print(", ");
  221.         Serial.println(btn.y, DEC);
  222.     }
  223.  
  224.     // set the previous to be the last
  225.     prev = btn;
  226. }
  227.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement