mirror of
https://github.com/baldengineer/SNES-NRF24
synced 2024-12-21 23:08:51 -05:00
First Commit
This commit is contained in:
commit
06e71d4417
8
readme.md
Normal file
8
readme.md
Normal 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
176
snes-in.ino
Normal 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
161
snes-out.ino
Normal 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();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user