1
0
mirror of https://github.com/baldengineer/SNES-NRF24 synced 2024-12-21 06:48:50 -05:00

First Commit

This commit is contained in:
James Lewis 2017-08-19 09:10:00 -07:00
commit 06e71d4417
3 changed files with 345 additions and 0 deletions

8
readme.md Normal file
View File

@ -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

176
snes-in.ino Normal file
View File

@ -0,0 +1,176 @@
//nes-in.ino
#include <SPI.h>
#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<sizeof(controllerButtons); x++)
Serial.print(bitRead(controllerButtons,x));
Serial.println();
Serial.print("Bin: "); Serial.println(controllerButtons, BIN);
Serial.print("Dec: "); Serial.println(controllerButtons, DEC);
Serial.print("Hex: "); Serial.println(controllerButtons, HEX);
Serial.println();
Serial.flush();
previousPrintMillis = currentMillis;
}
//printButtons(controllerButtons,NES);
if (0 && (currentMillis - previousPrintMillis > 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;
}
}

161
snes-out.ino Normal file
View File

@ -0,0 +1,161 @@
// nes-out.ino
// https://hackaday.io/project/12940-wireless-snes-with-nrf24
// @baldengineer
#include <SPI.h>
#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();
}