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 0×800 0×400 0×200 0×100 0×80 0×40 0×20 0×10 0×08 0×04 0×02 0×01

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.

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

9 Trackbacks

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>