-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/** | ||
* Author: John Crain Welsby (john.welsby@gmail.com) in collaboration with Arduino community, especially Nick Gammon. | ||
* Date: October 2016 | ||
* Version: 1.0 | ||
* | ||
* Implementation of N64_Interface. Specifically designed to run on 16MHz 5V Arduino Uno, or compatible. | ||
*/ | ||
|
||
|
||
|
||
|
||
// V2.00 | ||
// VajskiDs consoles (October 2022) | ||
// Reworked into an In Game reset! | ||
|
||
|
||
// ************** IGR Combination L+R+A+B+Z ************** | ||
|
||
|
||
#include "N64_Interface.h" | ||
#include "Arduino.h" | ||
|
||
//Do nothing for 1 cycle, 1/16 of a microsecond on Arduino Uno | ||
#define NOP asm volatile ("nop\n\t") //as per original, delayMicroseconds doesn't seem to be as accurate - insta crash. Tried using 1 and 3 microseconds respectively. Moved to macros. | ||
#define OneMicroSecondDelay NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; | ||
#define ThreeMicroSecondDelay NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP;NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; NOP; | ||
#define low bitWrite(DDRD, 2, 1); //Make data pin an output (low) | ||
#define high bitWrite(DDRD, 2, 0); //Make data pin an input (high impedence, lets if float, console pulls it up) | ||
#define resetpin 4 | ||
#define rst pinMode(resetpin, OUTPUT), bitWrite(PORTD, 4, 0), delay(100), pinMode(resetpin, INPUT); | ||
|
||
|
||
N64_Interface::N64_Interface(int serialpin) : mask_(1 << serialpin) { | ||
|
||
} | ||
|
||
|
||
void N64_Interface::send(char const* input, uint16_t length) { | ||
|
||
for (int i = 0; i < length; i++) { | ||
char currentByte = input[i]; | ||
|
||
for (int j = 0; j < 8; j++) { | ||
bool currentBit = currentByte & 0x80; //get leftmost bit | ||
currentByte <<= 1; //shift left | ||
|
||
if (currentBit) { | ||
//send logical 1 | ||
low | ||
OneMicroSecondDelay | ||
high | ||
ThreeMicroSecondDelay | ||
} else { | ||
//send logical 0 | ||
low | ||
ThreeMicroSecondDelay | ||
high | ||
OneMicroSecondDelay | ||
} | ||
} | ||
} | ||
|
||
//send stop bit | ||
bitWrite(DDRD, 2, 1); //Make data pin an output (low) | ||
OneMicroSecondDelay | ||
bitWrite(DDRD, 2, 0); //Make data pin an input (high impedence, simulates high | ||
} | ||
|
||
|
||
void N64_Interface::receive(char* output, uint16_t length) { | ||
|
||
char mask = mask_; //Create a local copy for speed reasons | ||
|
||
|
||
for (int i = 0; i < length; i++) { | ||
char currentByte = 0; | ||
|
||
for (int j = 0; j < 8; j++) { | ||
while (PIND & mask) {}; //wait for low | ||
|
||
//wait 1 microsecond | ||
OneMicroSecondDelay | ||
|
||
currentByte <<= 1; //shift left | ||
currentByte |= (PIND & mask) != 0; //add latest bit | ||
|
||
while (!(PIND & mask)) {}; //wait for high | ||
} | ||
|
||
output[i] = currentByte; | ||
} | ||
|
||
//wait for stop bit | ||
while (PIND & mask) | ||
; | ||
while (!(PIND & mask)) | ||
; | ||
|
||
} | ||
|
||
|
||
void IGR(const N64_Status& status) { | ||
if (status.buttons1 & BUTTON_A && status.buttons1 & BUTTON_B && status.buttons1 & BUTTON_Z && status.buttons2 & BUTTON_L && status.buttons2 && BUTTON_R) rst; // Wanted to use START instead of Z but this can't catch that combo for some reason. | ||
} | ||
|
||
|
||
void N64_Interface::sendStatusQuery() { | ||
send(&COMMAND_STATUS, 1); //Pass the status command byte to the send() function. | ||
} | ||
|
||
void N64_Interface::receiveStatus(N64_Status& status) { | ||
receive((char*)&status, status_size); //Pass the status struct to the receive() function. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// ************* ORIGINAL KUDOS ************* https://github.com/LogicalUnit/N64_Interface | ||
/** | ||
* Author: John Crain Welsby (john.welsby@gmail.com) in collaboration with Arduino community, especially Nick Gammon. | ||
* Date: October 2016 | ||
* Version: 1.0 | ||
* | ||
* Use this header file to communicate with a Nintendo 64 controller. It is specifically designed to run on a 16MHz 5V Arduino Uno, or compatible. | ||
* Looking into the N64 controller connector, arrow on top, wires from left to right are: GND, Data, 3V3. | ||
* You must specify which pin is connected to the Data wire in the constructor of N64_Interface. Valid pins are: 2, 3, 4, 5, 6, or 7. | ||
* If you just want to get the status of the N64 controller's joystick and buttons, use the convenience functions to send and receive status queries. | ||
* Multi-byte queries, such as when communicating with a memory card, have not been tested -- but might work. | ||
* Be sure to disable interrupts when communicating with the controller. | ||
* Search online for more information about the N64 controller communication protocol. | ||
*/ | ||
|
||
|
||
// V2.00 | ||
// VajskiDs consoles (October 2022) | ||
// Reworked into an In Game reset! | ||
|
||
|
||
// ************** IGR Combination L+R+A+B+Z ************** | ||
|
||
|
||
#ifndef N64_INTERFACE_H | ||
#define N64_INTERFACE_H | ||
|
||
|
||
|
||
//Status buttons1: | ||
const char BUTTON_D_RIGHT = 0x01; | ||
const char BUTTON_D_LEFT = 0x02; | ||
const char BUTTON_D_DOWN = 0x04; | ||
const char BUTTON_D_UP = 0x08; | ||
const char BUTTON_START = 0x10; | ||
const char BUTTON_Z = 0x20; | ||
const char BUTTON_B = 0x40; | ||
const char BUTTON_A = 0x80; | ||
|
||
//Status buttons2: | ||
const char BUTTON_C_RIGHT = 0x01; | ||
const char BUTTON_C_LEFT = 0x02; | ||
const char BUTTON_C_DOWN = 0x04; | ||
const char BUTTON_C_UP = 0x08; | ||
const char BUTTON_R = 0x10; | ||
const char BUTTON_L = 0x20; | ||
|
||
//Controller commands (queries to send). | ||
const char COMMAND_IDENFITY = 0x00; | ||
const char COMMAND_STATUS = 0x01; | ||
|
||
//Structure for storing controller status (joystick and buttons). | ||
typedef struct { | ||
char buttons1; | ||
char buttons2; | ||
char stick_x; | ||
char stick_y; | ||
} N64_Status; | ||
|
||
//Number of bytes in a N64_Status struct | ||
const int status_size = sizeof(N64_Status); | ||
|
||
//Print the contents of a N64_Status struct to serial | ||
void IGR(const N64_Status& status); | ||
|
||
//Interface to the Nintendo 64 controller | ||
class N64_Interface { | ||
|
||
public: | ||
//Specify which pin is connected to the N64 controller's Data wire. Choose pin 2, 3, 4, 5, 6, or 7. | ||
N64_Interface(int serialpin = 2); | ||
|
||
//Convenience function. Send the status query byte to the controller. | ||
void sendStatusQuery(); | ||
|
||
//Convenience function. Receive the status response from the controller. | ||
void receiveStatus(N64_Status& status); | ||
|
||
//Send bytes starting at input to controller, length is number of bytes to send. | ||
void send(char const* input, unsigned int length); | ||
|
||
//Receive bytes starting at output from controller, length is number of bytes to receive. | ||
void receive(char* output, unsigned int length); | ||
|
||
private: | ||
//Hex representation of the data pin. | ||
char mask_; | ||
|
||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// ************* ORIGINAL KUDOS ************* | ||
/** | ||
* Author: John Crain Welsby (john.welsby@gmail.com) | ||
* Date: October 2016 | ||
* Version: 1.0 | ||
* | ||
* Simple demonstration of communication with a Nintendo 64 controller. | ||
* Controller must be connected as described in N64_Interface.h (GND, Data, 3V3). | ||
* Serial output at 115200 baud. | ||
*/ | ||
|
||
|
||
|
||
// V2.00 | ||
// VajskiDs consoles (October 2022) | ||
// Reworked into an In Game reset! | ||
|
||
|
||
// ************** IGR Combination L+R+A+B+Z ************** | ||
|
||
|
||
#include "N64_Interface.h" | ||
#define resetpin 4 | ||
#define serialpin 2 | ||
|
||
|
||
//Global variables | ||
N64_Interface interface(serialpin); //N64 controller Data wire is connected to pin 2. | ||
N64_Status status, oldStatus; //Status of joystick and buttons. | ||
|
||
void setup() { | ||
pinMode (resetpin, INPUT); | ||
|
||
//Start by clearing the status variables | ||
memset(&status, 0, status_size); | ||
memset(&oldStatus, 0, status_size); | ||
} | ||
|
||
|
||
void loop() { | ||
|
||
noInterrupts(); //Disable interrupts, they interfere with timings. | ||
interface.sendStatusQuery(); //This is how we send the status query (1 byte). | ||
interface.receiveStatus(status); //This is how we receive the status response (4 bytes). | ||
interrupts(); //Timing critical section complete, re-enable interrupts. | ||
IGR(status); | ||
delay(500); | ||
|
||
} |