Super Nintendo, together with the Sega Megadrive (or Genesis) are the representative consoles of the 16-bit era. I had the Megadrive, but played some lot in Super Nintendo too.
I have played in emulators since always, a lot of them, including the SNES. I don’t think I play bad using the keyboard, but I prefer using controllers, even better if the controllers are the ones of the console emulated. Some time ago, I built a adapter for connecting SNES controllers to PC from Raphaël Assénat’s site using a ATmega 8 with the VUSB library. I found the USB implementation to hard to understand, so I just followed the instructions. In the end, it worked.
I wanted to play Super Mario, but I did not have this adapter anymore. However, I had a Arduino Micro and some veroboard. The thing about the Arduino Micro, is that like the Arduino Leonardo, it has native USB, being able to act like a keyboard, a mouse, a joystick, or whatever. The Arduino Leonardo is probably suitable for this too, as it also has a native USB port.
Note: The other Arduino models generally use another ATmega to handle the USB protocol, while the main chip is used for code. Usually the user may not even realize that the board has two processors. The models Micro and Leonardo have a USB port in the ATmega used (32u4), and only one chip is used for USB communication and general coding.
Hardware
I had to connect the controllers to the Arduino. For this I used some veroboard and male headers basically.Please, remember that only the Arduino micro and Leonardo can be used for this. You can see the details below:
The SNES controller connector pinout is :
I connected as follows, but you can change in the code if you want.
Controller Arduino
5v 5v
data D7
clock D4
latch D5
GND GND
Note: Every line is shared between the controllers except the data line, this means that latch, clock, 5v and GNd are connected in the controllers connected, the data lines must be separated, I used the pin D6 for the data line of the second controller. A reading in the code can clear this better.
Library
I still don’t know much about the USB protocol and its way of communication. In addition, I wanted to complete the project in one afternoon. It was time for a library.
Ops, I assume that you have the last version of Arduino software, because the library does not work with version 1.6.5 or below. If you don’t have the version 1.6.6, please update so we can continue. :)
Oh, coming back to the code. The library I found works great, it was coded by Matthew Heironimus, and can be found here. Just download it and extract in the libraries folder of the Arduino IDE files.
With this library, you can make the Arduino appear in the computer as up to 3 controllers. Then you can code the board to receive the button states from the controllers and send them to the PC as a USB HID controller. I choose to use the two controllers code, because I only had two SNES controllers anyway.
SNES controller protocol
The SNES controller protocol is pretty simple. In the connector of the controller there are two lines for power (5v and ground), and three other lines, one for cock, one for data, and the other is the latch line. To read the buttons, the procedure is:
- High pulse on the latch pin for 12us. This instructs the controller to lock the state of the buttons for reading.
- The first bit(button B state) will be already in the data line, read it.
- Toggle the clock light form low to high, read the bit, toggle the clock line to low again.
- Repeat the step four for the next 14 bits(16 bits are read, but some are always high).
As said before, pretty easy to read. More information can be found in this useful document.
Arduino Code.
Finally. If you already installed the library and connected everything, just burn the code bellow in the Arduino and you have finished. Yay!
#include "Joystick2.h" int clk = 4, data1 = 7, data2 = 6, latch = 5; //two data lines, one for each controller. uint16_t buttons1 = 0, buttons2 = 0;//the variables for each controller state const bool testAutoSendMode = false;//we choose when to send the values over USB void setup() { Joystick[0].begin(false);//Initialise the controllers Joystick[1].begin(false); // Pin config pinMode(latch, OUTPUT); pinMode(clk, OUTPUT); pinMode(data1, INPUT); pinMode(data2, INPUT); } int readControllers() { digitalWrite(latch, HIGH);//latch pulse, lock the state of the buttons in the register delayMicroseconds(12); digitalWrite(latch, LOW); delayMicroseconds(6); buttons1 = 0;//zero the variables to receive new values. buttons2 = 0; buttons1 |= (digitalRead(data1) << 0); //first bit read before clock. buttons2 |= (digitalRead(data2) << 0); for (int i = 1; i < 16; i++) {//clock &read digitalWrite(clk, HIGH); delayMicroseconds(6); buttons1 |= (digitalRead(data1) << i);//the values are stored for each bit buttons2 |= (digitalRead(data2) << i); digitalWrite(clk, LOW); delayMicroseconds(6); } buttons1 = ~buttons1; //workaround, a button pressed is read as a '0'(pull ups), jus inversing them to my taste. buttons2 = ~buttons2; } void loop() { readControllers(); //Controller 1 if (buttons1 & (1 << 0)) { Joystick[0].pressButton(0); //B } else { Joystick[0].releaseButton(0); } if (buttons1 & (1 << 1)) { Joystick[0].pressButton(1); //Y } else { Joystick[0].releaseButton(1); } if (buttons1 & (1 << 2)) { Joystick[0].pressButton(2); //Select } else { Joystick[0].releaseButton(2); } if (buttons1 & (1 << 3)) { Joystick[0].pressButton(3); //Start } else { Joystick[0].releaseButton(3); } if (buttons1 & (1 << 4)) { Joystick[0].setYAxis(-127); //Up and Down, -127=total up, 127= total down } else if (buttons1 & (1 << 5)) { Joystick[0].setYAxis(127); } else { Joystick[0].setYAxis(0); //the value zero, means the stick is stopped } if (buttons1 & (1 << 6)) { Joystick[0].setXAxis(-127); //Right left } else if (buttons1 & (1 << 7)) { Joystick[0].setXAxis(127); } else { Joystick[0].setXAxis(0); } if (buttons1 & (1 << 8)) { Joystick[0].pressButton(4); //A } else { Joystick[0].releaseButton(4); } if (buttons1 & (1 << 9)) { Joystick[0].pressButton(5); //X } else { Joystick[0].releaseButton(5); } if (buttons1 & (1 << 10)) { Joystick[0].pressButton(6); //L } else { Joystick[0].releaseButton(6); } if (buttons1 & (1 << 11)) { Joystick[0].pressButton(7); //R } else { Joystick[0].releaseButton(7); } //Controller 2 if (buttons2 & (1 << 0)) { Joystick[1].pressButton(0); //B } else { Joystick[1].releaseButton(0); } if (buttons2 & (1 << 1)) { Joystick[1].pressButton(1); //Y } else { Joystick[1].releaseButton(1); } if (buttons2 & (1 << 2)) { Joystick[1].pressButton(2); //Select } else { Joystick[1].releaseButton(2); } if (buttons2 & (1 << 3)) { Joystick[1].pressButton(3); //Start } else { Joystick[1].releaseButton(3); } if (buttons2 & (1 << 4)) { Joystick[1].setYAxis(-127); //Up Down } else if (buttons2 & (1 << 5)) { Joystick[1].setYAxis(127); } else { Joystick[1].setYAxis(0); } if (buttons2 & (1 << 6)) { Joystick[1].setXAxis(-127); //Right left } else if (buttons2 & (1 << 7)) { Joystick[1].setXAxis(127); } else { Joystick[1].setXAxis(0); } if (buttons2 & (1 << 8)) { Joystick[1].pressButton(4); //A } else { Joystick[1].releaseButton(4); } if (buttons2 & (1 << 9)) { Joystick[1].pressButton(5); //X } else { Joystick[1].releaseButton(5); } if (buttons2 & (1 << 10)) { Joystick[1].pressButton(6); //L } else { Joystick[1].releaseButton(6); } if (buttons2 & (1 << 11)) { Joystick[1].pressButton(7); //R } else { Joystick[1].releaseButton(7); } if (testAutoSendMode == false) { Joystick[0].sendState(); //send the state to the computer. Joystick[1].sendState(); } }
The end
Of course that is not. Thanks for reading and see you next time. o/
Fala , Robson ! bacana esse post gringo que você trouxe e adaptou ! gostei pacas ! eu vivo montando gamepads em Atmegas328p. Uso o próprio Arduino como Programador, mas sem precisar de outro chip ou usá-lo como “as ISP Programmer”. Faço o upload do arquivo hex direto para o Arduino e extraio o Atmega depois para o circuito. Eu modifiquei alguns parâmetros de bibliotecas deste firmware e o próprio “Makefile”. Fiquei interessado neste projeto que você postou. Baixei as bibliotecas. No entanto, surgem inúmeros erros de compilação antes de fazer o upload. Meu Arduino é o UNO R3 e uso a IDE 1.05 R2. Meu O.S é o Windows 7 Ultimate 64 bits. Tem ideia do que pode estar acontecendo ? eu simplesmente baixei o arquivo e nada modifiquei. Apenas extraí para a pasta biblioteca do Arduino e fiz a adição. No mais, o “Dragão sem Chama”, sempre tem me surpreendido com uns posts muito bacanas, tais como este seu. Muito bom ! valeu !
Oi Ferinha.Obrigado pelos elgios.No entanto, o post é de autoria minha.
Versão em português:
http://dragaosemchama.com.br/2015/11/controller-de-super-nintendo-no-pc/
Como dito no post, infelizmente o Arduino UNO não pode ser usado para este tutorial. Pesquise por UNO JOY para poder usá-lo.
Amigo, muito legal o projeto. Me diz uma coisa, acha que daria pra adaptar ele para fazer uma tarefa mais simples? Eu queria fazer um adaptador para ligar controles de snes no neogeo, e lá os controles não tem codificação nenhuma, cada botão / direção é um fio independente…Então seria uma conversão mais simples, apenas ler o protocolo do snes e jogar cada botão em uma saída (fio) correspondente. Agradeço a atenção. Obrigado!
Oi Marcelo. Se o protocolo do controle de NEOGEO for simples como você diz, então sim.
Além disso, você pode usar qualquer outro arduino, já que nao vai precisar da usb. Só fique ligado no número de pinos, pois devem ser muitos pelo que disse.
Lembre se que as portas analógicas do Arduino podem ser usadas como pinos digitais.
Por nada. Abraço