commit 06e71d4417e05234b750646ba2468581b1659e41 Author: James Lewis Date: Sat Aug 19 09:10:00 2017 -0700 First Commit diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..8712313 --- /dev/null +++ b/readme.md @@ -0,0 +1,8 @@ +nrf24 based wireless adapter for SNES controllers. Should also work with NES. + +Ironically, you'll need an extension cable. Cut it in half so you can connect the controller side and console side. + +Worked with both my real SNES and my Retron5. I'm not a good enough player to tell if there is lag. + +More information here: +https://hackaday.io/project/12940-wireless-snes-with-nrf24 \ No newline at end of file diff --git a/snes-in.ino b/snes-in.ino new file mode 100644 index 0000000..22a4d57 --- /dev/null +++ b/snes-in.ino @@ -0,0 +1,176 @@ +//nes-in.ino + +#include +#include "RF24.h" + +#define NES 0x0 +#define SNES 0x1 + +/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 +uno spi pins +SPI: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). +radio(ce_pin,cs_pin) */ +RF24 radio(9,10); +byte addresses[][6] = {"1Node","SNES1"}; +/**********************************************************/ + +const int radioNumber = 0; +const bool debugPrint = false; + +const byte latch = 4; // Orange(HDR) +const byte clock = 7; // Yellow(HDR) +const byte data = 8; // Red(HDR) + +unsigned long previousFrameMillis=0; +//int frameInterval = 16; // approx 1/60 (60Hz), slightly faster than NES +int frameInterval = 16; // approx 1/60 (60Hz), slightly faster than NES + +unsigned long previousPrintMillis=0; +int printInterval = 1000; +/* + +Every 60Hz, + +12us Latch +wait 6us +8 pulses, 12us per cycle, 50% Duty Cycle +data clocked in on falling edge + +*/ + + +void setup() { + // put your setup code here, to run once: + Serial.begin(115200); + Serial.println(F("S/NES RF24 Transmitter [From Controller]")); + pinMode(latch, OUTPUT); + pinMode(clock, OUTPUT); + pinMode(data, INPUT_PULLUP); // is pull up needed? yup! :) + + // Radio setup + radio.begin(); + // Set the PA Level low to prevent power supply related issues since this is a + // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. + radio.setPALevel(RF24_PA_LOW); + + if(radioNumber){ + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1,addresses[0]); + }else{ + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1,addresses[1]); + } +// radio.openWritingPipe(addresses[0]); +} + +unsigned int previousController; + +void loop() { + // check the clock + unsigned long currentMillis = millis(); + + // time to get the next frame yet? + if ((currentMillis - previousFrameMillis) > frameInterval) { + unsigned int controllerButtons = 0xFFFF; + + // assert latch for 12 us + digitalWrite(latch, HIGH); + delayMicroseconds(8); // spec says 12us, adjusting for digitalWrite + digitalWrite(latch, LOW); + // wait for 6us (ugh) + delayMicroseconds(4); + + if (debugPrint && (currentMillis - previousPrintMillis > printInterval)) + Serial.println(currentMillis); + + // clock out the data + + for (int pulseCounter=0; pulseCounter < 16; pulseCounter++) { + // spec i read said 8 clocks for the data, but looks like latch + // asserted low reads the first byte ('A') + + int dataValue = digitalRead(data); + if (debugPrint && (currentMillis - previousPrintMillis > printInterval)) { + Serial.print(dataValue); + } + + controllerButtons = controllerButtons << 1; + + if (dataValue) + controllerButtons = controllerButtons | 0x0001; + else + controllerButtons = controllerButtons & 0xFFFE; + + + // clock pulse, approximately 24us long 9us HIGH, 15us LOW + // much slower than NES + // don't need the 8th clock because latch brought in the first bitu + if (pulseCounter != 15) { + digitalWrite(clock, HIGH); + delayMicroseconds(4); + digitalWrite(clock, LOW); + delayMicroseconds(4); + } + + } + if (debugPrint && (currentMillis - previousPrintMillis > printInterval) ) { + Serial.println(); + Serial.print("bitRead: "); + //for (int x=8; x>=0; x--) + for (int x=0; x printInterval)) { + printButtons(controllerButtons,NES); + Serial.flush(); + previousPrintMillis = currentMillis; + } + + //Serial.print(F("Now sending: ")); + //Serial.println(controllerButtons, BIN); + + /*if (!radio.write( &controllerButtons, sizeof(controllerButtons) )){ + Serial.println(F("failed")); + }*/ + + if (controllerButtons != previousController) { + Serial.print(F("Last: ")); + Serial.println(previousController, BIN); + Serial.print(F("Now : ")); + Serial.println(controllerButtons, BIN); + radio.write( &controllerButtons, sizeof(controllerButtons)); + previousController = controllerButtons; + } + previousFrameMillis = millis(); + } +} + +String directions[] = {"right","left","down","up","start","select","b","a","err"}; + +void printButtons(unsigned int buttons, byte controllerType) { + switch (controllerType) { + case NES: + for (int x=7; x>=0; x--) + if (!bitRead(buttons,x)) + Serial.println(directions[x]); + break; + + case SNES: + break; + + default: + return; + break; + } + +} diff --git a/snes-out.ino b/snes-out.ino new file mode 100644 index 0000000..3224c9a --- /dev/null +++ b/snes-out.ino @@ -0,0 +1,161 @@ +// nes-out.ino +// https://hackaday.io/project/12940-wireless-snes-with-nrf24 +// @baldengineer + +#include +#include "RF24.h" + +/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 +uno spi pins +SPI: 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). +radio(ce_pin,cs_pin) */ +const int radioNumber = 1; +RF24 radio(9,10); +byte addresses[][6] = {"1Node","SNES1"}; +/**********************************************************/ + +/* +const byte latch = 3y; // Orange(HDR) +const byte clock = 7; // Yellow(HDR) +const byte data = 8; // Red(HDR) +*/ + +const byte latch = 3; // PD3 +const byte clock = 7; // PD7 +const byte data = 8; // PB0 + + + +void setup() { + // Serial.begin(115200); +// Serial.println(F("S/NES RF24 Receiver [To Console]")); + + pinMode(latch, INPUT); // black PD3, pin 3 + pinMode(clock, INPUT); // orange PD7, pin 7 + pinMode(data, OUTPUT); // red PB0, pin 8 + digitalWrite(data, LOW); + + attachInterrupt(digitalPinToInterrupt(latch), handleController, RISING); + + + radio.begin(); + + // Set the PA Level low to prevent power supply related issues since this is a + // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default. + radio.setPALevel(RF24_PA_LOW); + + // Open a reading pipe on this radio +// radio.openReadingPipe(1,addresses[0]); + + if(radioNumber){ + radio.openWritingPipe(addresses[1]); + radio.openReadingPipe(1,addresses[0]); + }else{ + radio.openWritingPipe(addresses[0]); + radio.openReadingPipe(1,addresses[1]); + } + + // Start the radio listening for data + radio.startListening(); +} + +bool skip = false; +unsigned long currentMillis = 0; +unsigned long previousMillis = 0; +int interval = 250; + +volatile int controller = 0xFFFF; + +int lastLatchState = LOW; +int lastClockState = HIGH; +int latchState = 0; +int clockState = 0; + + +void handleSerial() { + return; + + char incomingByte = Serial.read(); + + switch (incomingByte) { + case '!': + skip = true; + break; + + case '@': + skip = false; + break; + } +} + +int previousController=0; + +int handleRadio() { + int incomingController = 0xFFFF; + int newController = 0xFFFF; + + + //while (radio.available()) { + radio.read( &incomingController, sizeof(incomingController) ); // Get the payload +// } +// Serial.print(F("Rec: ")); +// Serial.println(incomingController, BIN); + + for(int x=0; x < 16; x++) { + // 0000 0000 0000 0000y + if (bitRead(incomingController, x)) + newController = newController | 0x01; + else + newController = newController & 0xFFFE; + if (x != 15) + newController = newController << 1; + } + if (previousController != incomingController) { + /* + Serial.println(F("Chg")); + Serial.print(F("Last: ")); + Serial.println(previousController, BIN); + Serial.print(F("Now : ")); + Serial.println(incomingController, BIN); + Serial.print(F("Swiz: ")); + Serial.println(newController, BIN); */ + //radio.write( &incomingController, sizeof(incomingController)); + previousController = incomingController; + } + // Serial.print(F("Now: ")); +// Serial.println(newController, BIN); + + // delay (500); + return newController; +} + +void handleController() { + int thisControllerValue = controller; + for (int x = 0; x<16; x++) { + if (thisControllerValue & 0x01) + PORTB = PORTB | 0x01; // 0000 0001 + else + PORTB = PORTB & 0xFE; // 1111 1110 + + while (PIND & 0x80); + while (!(PIND & 0x80)); + + thisControllerValue = thisControllerValue >> 1; + } + //PORTB = PORTB | 0x01; // PB0, HIGH: 0000 0001 + PORTB = PORTB & 0xFE; // PB0, LOW. + return; +} + +void loop() { + /*if (Serial.available()) + handleSerial(); */ + + while (skip) + handleSerial(); + + if( radio.available()) + controller = handleRadio(); + + currentMillis = millis(); +}