SNESpaduino – Super Nintendo Gamepad for Arduino

The SNESpaduino library enables You to hook up Your old SNES (Super Nintendo Entertainment System) Gamepad as an input device to you Arduino.

SNES gamepad connected to an Arduino

The SNES gamepad can easily be connected to an Arduino – You’ll need nothing more but 5 wires.

Basically, the library does these 3 tasks:

  • Easy interfacing – You just need to connect 3 Pins (Latch, Clock, Data)
  • Read the buttons’ states – A function reads from the controller, which buttons are currently pressed
  • Help You parse the data – Using simple constants, processing the returned data is peanuts for You.

Not only that the library is incredible easy to use, You can also easily get to know the structure of an Arduino library, how these things are developed and what’s happening in the background. All the code is documented, the Commits on GitHub are also full of useful details. If you’re interested, dive in – it’s easy!

Download and Install

You can get the library in several ways:

To ensure you have the super-duper latest code, grab it from GitHub. Just use the git clone command from above on your OS of choice. However, if you don’t have the git program installed, feel free to download the repository as a ZIP. But note: When downloading the repo as a zip, you have to rename the extracted folder SNESpaduino-master (remove the -master)!

If you’re new to libraries, the official Arduino Library reference explains how you can install one. When You have successfully imported the library into the IDE, go over to connect your gamepad.

Connect the SNES Gamepad to an Arduino

The SNES Gamepad has 5 contacts: +5V, GND, Latch, Clock, Data. Here is the pin configuration of the connector (from left to right, starting with the group of 4 contacts). Also take a look at the picture, where pin-numbers as well as color coding is noted:

Nr 1 2 3 4 5 6 7
Use +5V Clock Latch Data N/C N/C GND
Color White Yellow Orange Red Brown
SNES Gamepad Connection

Pin configuration and color codes of the SNES gamepad.

Connect the gamepad’s GND / 5V to your Arduino’s Ground / +5V. Latch, Clock and Data go to any In/Out pin. Even analog ones. Over the Clock and Latch lines, the Arduino will send data, 5V/GND (HIGH/LOW), to tell the gamepad we’d like to receive the current state of all buttons. Over the Data line, our Arduino will receive that data.

In my examples, I used the pins 19, 20 and 21 of my Arduino Mega, but as said, you may use any In/Out Pin.

Test library and gamepad

Once the library is installed and the gamepad connected to the Arduino, it’s time to test things. The library includes 2 example sketches. Those are available under File > Examples > SNESpaduino. First, load the SNESpaduinoPrintToSerial sketch, compile it and load it onto the Arduino. The project’s code is documented, so you should be able to figure out what it does. If not, leave me a comment ;)

Using the library works like this: First, an instance of SNESpaduino is created, handing over the 3 pin numbers for Latch, Clock and Data lines to the constructor. Next, you can use the function getButtons() which will return the current state of all 12 Buttons as a 16 digit integer. Each bit in that integer represents a button: Is this bit 0 / LOW / False, the button is currently being pressed. So if a bit is 1 / HIGH / True, that means the according button is currently NOT being pressed.

This is due to the controller’s hardware design. Because this might be confusing, getButtons() will by default return the opposite (negative) bit pattern. This way, it’s easier to use If-Statements to check which buttons are being pressed (and seems more intuitive). If you need to have the “raw”, non-inverted output from the controller, call getButtons(boolean return_inverted) with the parameter false: getButtons(false);

Parsing data

The getButtons() function returns a uint16_t. As mentioned above, the bits in this integer represent which buttons are being pressed. To work with the data, here is a table to determine which bit represents which button:

Nr. 12 11 10 9 8 7 6 5 4 3 2 1
Button R L X A RIGHT LEFT DOWN UP START SELECT Y B
Value 2048 1024 512 256 128 64 32 16 8 4 2 1
HEX 0x800 0x400 0x200 0x100 0x80 0x40 0x20 0x10 0x08 0x04 0x02 0x01

So, if only A is being pressed, getButtons(); returns the value 1111000100000000

IMPORTANT: The last 4 bits (Most Significant Bits, MSB, left) must be ignored! getButtons() ony affects the first 12 bits (Least Significant Bits, LSB, right). So the remaining 4 bits will never be touched, they will always return as 1 (or non-inverting: 0).

Now, using logic operations and a bitmask, individual bits can easily be checked. For this purpose, SNESpaduino.h contains constants (preprocessor directives) BTN_*. These values are the same as the ones above in the table. If you wanted to check if The A button is being pressed, simply apply the logic AND function to the buttons’ states and the bitmask BTN_A. If this statement (button_states & BTN_A) is true, button A is in fact being pressed. See the 2 examples shipped with the library, it’s really simple.

I’d recommend modifying SNESpaduinoPrintToSerial – you can easily get used to the library’s usage while writing a simple function like… Check each individual button if it’s being pressed (and write that to Serial, just like in the example).

Contact

Please, feel free to contact me for any further questions, ideas, pull requests and so on. Write a comment or an eMail, or twitter @tacticalcode

All code (and this tutorial) is being published under CC-BY-SA license. So Share, Remix and Hack on!

– Damon Dransfeld

This entry was posted in Arduino
Bookmark the permalink Post a comment or leave a trackback: Trackback URL.

16 Comments

  1. Pere
    Posted 5. June 2013 at 00:35 | Permalink

    wow, i’m working and having fun with the same, i’ll look your code and trying two adapter two gamepad and the same arduino or teensy.

    thanks.

    • Pere
      Posted 5. June 2013 at 00:38 | Permalink

      I turned my arduino in hid mode using dfu and lufa, my pc and android detect the arduino as a keyboard.
      when i’v something i’ll tell you for try

      • Posted 5. June 2013 at 00:45 | Permalink

        Awesome. I’ll also work on compability for NES controllers. Around thursday, my post about the SNES gamepad’s internals should be ready to publish.
        So if you’re also into hardware, stay tuned ;)

  2. Pere
    Posted 5. June 2013 at 01:19 | Permalink

    Hi, in july i’ll be working on this for fun with my old games in emulated android apps.

    i followed this http://hunt.net.nz/users/darran/
    for convert arduino into a usb hid keyboard
    http://hunt.net.nz/users/darran/weblog/b3029/Arduino_UNO_Keyboard_HID_version_03.html

    with dfuprogramer i load arduino firmware or darra hid keyboard,
    this can change to arduino-normal for load new sketch or changue to keyboard.

    this my test code with two nes pads,

    /*
      
       
       Version: 0.2 (10/04/2013) 
       
    */
    #define KEY_LEFT_CTRL 0x01
    #define KEY_LEFT_SHIFT 0x02
    #define KEY_RIGHT_CTRL 0x10
    #define KEY_RIGHT_SHIFT 0x20
    #define KEY_NULL 0
    #define KEY_A 4
    #define KEY_B 5 
    #define KEY_C 6
    #define KEY_D 7
    #define KEY_E 8
    #define KEY_F 9
    #define KEY_G 10
    #define KEY_H 11
    #define KEY_I 12
    #define KEY_J 13
    #define KEY_K 14
    #define KEY_L 15
    #define KEY_M 16
    #define KEY_N 17
    #define KEY_O 18
    #define KEY_P 19
    #define KEY_Q 20
    #define KEY_R 21
    #define KEY_S 22
    #define KEY_T 23
    #define KEY_U 24
    #define KEY_V 25
    #define KEY_W 26
    #define KEY_X 27
    #define KEY_Y 28
    #define KEY_Z 29
    #define KEY_RARROW 79
    #define KEY_LARROW 80
    #define KEY_DARROW 81
    #define KEY_UARROW 82
    
    #include 
    
    //uint8_t NesDefaultKeyCode[8] = { BUTTON_A, BUTTON_B, SELECT, START, UP        , DOWN      , LEFT      , RIGHT };
            uint8_t Pad1KeyCode[8] = { KEY_A   , KEY_B   , KEY_C , KEY_D, KEY_UARROW, KEY_DARROW, KEY_LARROW, KEY_RARROW };
            uint8_t Pad2KeyCode[8] = { KEY_J   , KEY_K   , KEY_L , KEY_M, KEY_N     , KEY_O     , KEY_P     , KEY_Q };
         boolean Pad1KeyPressed[8] = { false   , false  , false  , false, false     , false     , false     , false };
         boolean Pad2KeyPressed[8] = { false   , false  , false  , false, false     , false     , false     , false };
    
    byte i = 0; //index arrays
    byte ControllerData = 0;
    byte buf[8] = { 0 };	/* Keyboard report buffer */
    
    // put your own strobe/clock/data pin numbers here
    NESpad pad1 = NESpad(2,3,4);
    NESpad pad2 = NESpad(2,3,5);
    
    void setup() {
      Serial.begin(9600);  
      delay(2000); //Keep Time Keyboard Load Drivers
      //Serial.println("START NESPAD-DUINO");
    }
    
    void loop() {
     
      delay(20);
      //READ PAD1
      ControllerData = pad1.buttons();
    
      //if (ControllerData != 0){
        // A
        i = 0;
        if (ControllerData & NES_A) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[2] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[2] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // B
        i = 1;
        if (ControllerData & NES_B) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[3] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[3] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
      
        // SELECT
        i = 2;
        if (ControllerData & NES_SELECT) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[7] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[7] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
      
        // START
        i = 3;
        if (ControllerData & NES_START) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[6] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[6] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // UP
        i = 4;
        if (ControllerData & NES_UP) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[4] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[4] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // DOWN
        i = 5;
        if (ControllerData & NES_DOWN) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[4] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[4] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // LEFT
        i = 6;
        if (ControllerData & NES_LEFT) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[5] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[5] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // LEFT
        i = 7;
        if (ControllerData & NES_RIGHT) {
          if(!Pad1KeyPressed[i]){
            Pad1KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[5] = Pad1KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad1KeyPressed[i] == true){
          Pad1KeyPressed[i] = false;
          buf[5] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        //write buffer pad1    
        //Serial.write(buf, 8);
    
      //}
    
      //READ PAD2
      ControllerData = pad2.buttons();
    
      //if (ControllerData != 0){
        // A
        i = 0;
        if (ControllerData & NES_A) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[2] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[2] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // B
        i = 1;
        if (ControllerData & NES_B) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[3] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[3] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
      
        // SELECT
        i = 2;
        if (ControllerData & NES_SELECT) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[7] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[7] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
      
        // START
        i = 3;
        if (ControllerData & NES_START) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[6] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[6] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // UP
        i = 4;
        if (ControllerData & NES_UP) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[4] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[4] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // DOWN
        i = 5;
        if (ControllerData & NES_DOWN) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[4] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[4] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // LEFT
        i = 6;
        if (ControllerData & NES_LEFT) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[5] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[5] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
        // LEFT
        i = 7;
        if (ControllerData & NES_RIGHT) {
          if(!Pad2KeyPressed[i]){
            Pad2KeyPressed[i] = true; //Make sure the button is only pressed once
            buf[5] = Pad2KeyCode[i];
            Serial.write(buf,8); // Write keyboard buffer
          }
        }else if (Pad2KeyPressed[i] == true){
          Pad2KeyPressed[i] = false;
          buf[5] = 0; //Release Keyboard key
          Serial.write(buf,8); // Write keyboard buffer
        }
        
    
     // }
      
      
    
    }
    

    bye.

    remove the code if you like.
    Pere.

    edit by Damon Dransfeld: I put that code in “sourcecode” short-tags for syntax highlighting ;)

  3. Posted 20. August 2013 at 05:09 | Permalink

    Hi! I’ve been following your web site for a long time now and finally got the bravery to go ahead and give you a shout out from Atascocita Tx! Just wanted to tell you keep up the fantastic job!

    Also visit my weblog weight loss plan :: Marilynn ::

  4. Posted 4. October 2013 at 14:25 | Permalink

    This is the perfect website for everyone who wants
    to understand this topic. You realize a whole lot its
    almost hard to argue with you (not that I
    personally will need to…HaHa). You definitely put a fresh spin on a topic which has been discussed for years.
    Excellent stuff, just great!

  5. Posted 3. April 2014 at 09:09 | Permalink

    Hello i am kavin, its my first time to commenting anyplace, when i read this
    article i thought i could also create comment
    due to this brilliant post.

  6. Christian
    Posted 6. January 2015 at 23:07 | Permalink

    Excellent article. Please be a little bit more specific about the pin order for the SNESpaduino object. Using the example provided the order is: SNESpaduino pad(PIN_LATCH, PIN_CLOCK, PIN_DATA). It was a gotcha for me eheh.

  7. asrocrip
    Posted 22. January 2015 at 11:51 | Permalink

    Thank you very much for the application, I have a problem when I load the code for the serial monitor I get this:
    Can you help?
    BTN_A
    BTN_DOWN
    BTN_X + BTN_Y
    BTN_START + BTN_SELECT + BTN_L + BTN_Y
    BTN_A
    BTN_DOWN
    BTN_X + BTN_Y
    BTN_START + BTN_SELECT + BTN_L + BTN_Y
    BTN_A
    BTN_DOWN
    BTN_X + BTN_Y
    BTN_START + BTN_SELECT + BTN_L + BTN_Y
    BTN_A
    BTN_DOWN
    BTN_X + BTN_Y
    BTN_START + BTN_SELECT + BTN_L + BTN_Y
    ……………………………………….

    Thank You !!!

    • Steven
      Posted 26. March 2015 at 23:40 | Permalink

      Im getting the same thing as you, i found that how the arduino interprets a button press is inverted. so if youre not pressing a button, it thinks you are. If you are pressing a button, it thinks youre not. This is regardless of whether or not you invert getButtons via getButtons(false), which puzzles me.

      Also, the A and B button detentions are switched.

      I have no solution, maybe the author has an idea?

      • Posted 27. March 2015 at 00:12 | Permalink

        Hey there!
        At the moment I don’t have any SNES pads here, so I can’t fiddle with the actual hardware. Does it make any difference when you call getButtons(false); ? (Line 29 in SNESpaduinoPrintToSerial example)
        Are your wires attached to the correct pins? Which model of SNES pad did you use? (I only tested the PAL/EU Version)
        Just to make sure: Delete %USERPROFILE%\Documents\Arduino\libraries\SNESpadunio
        and extract the git version (https://github.com/TacticalCode/SNESpaduino/archive/master.zip) to the libraries folder (rename to delete the “-master” in the folder name). Load, Compile and Flash the SNESpadunioPrintToSerial example and watch the serial monitor.
        The last time I checked, everything worked fine with my Arduino Mega R3 and original SNES pad.

        • Steven
          Posted 27. March 2015 at 03:51 | Permalink

          Thanks so much for the quick response, i reinstalled the librtary and i tested the code with getButtons(false) and still no luck. It would seem as though i have a different controller, the 5 wires on my controller are soldered directly to the board. my best guess is that is the problem.

  8. Steven
    Posted 7. April 2015 at 23:53 | Permalink

    Im back.

    SOOOOO, i have good news and bad news.

    Bad news is that the creators library ONLY WORKS WITH PAL/EU CONTROLLERS.
    After encountering problems that i discussed in my previous comments, i went out and bought a PAL controller to see if it would work. It does.

    If you have a non-PAL SNES controller, your serial monitor will be spammed as though everything is being pressed at once OR the only input button that will work is B, and when you press it it will trigger every button press.

    GOOD NEWS IS THAT IF YOU DONT HAVE A PAL CONTROLLER THERE IS A SOLUTION.
    The solution is in the form of another library by a different person, which can be found here
    https://code.google.com/p/nespad/

    This code is not as nice and neat as the OP’s, but it gets the job done. (You should thank me as finding it took some digging)

    Because the linked library is so old, you will have to go into the snespad.cpp file and change the “#include Wprogram.h” to #include Arduino.h”

    Hope this solved any problems.

    • Eastorik
      Posted 1. May 2015 at 22:43 | Permalink

      THANKS A LOT !

  9. Posted 11. May 2015 at 15:33 | Permalink

    You can submit one application and acquire several quotes from different lenders best natural heart supplements banks, lending institution and
    specialized auto banks in ca will often provide you with
    better interest levels compared to the dealers cannot match.

  10. Posted 7. June 2015 at 08:51 | Permalink

    I love what you gus are usually upp too. This kind of cleger work and exposure!
    Keeep up the supsrb works guys I’ve incorporated you guys to
    blogroll.

    my website claritin d side effects

11 Trackbacks

Achtung: Wordpress interpretiert bestimmte Zeichenfolgen als Markup und verändert diese. Nutzt für Programmcode lieber Gist oder PasteBin-Services und verlinkt die Code-Schnipsel.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>