Arduino Gamepads

Parts

The part used here is a LOLIN32 board. But Any ESP32 board can be used.

Some classic NES/ SNES game controllers with 7 pin connectors.

Where to get them

These links are the cheapest I could find and also supporting our work (affiliate). I also ordered my modules there
LOLIN32 Board (~$6.90)
But there are also cheap modules on Amazon and eBay:
Amazon.com  .ca  .de  .fr
Ebay   .de  .fr

SNES controller
Aliexpress (~$2.62)
Ebay  .de .fr

SNES Extension cord
Aliexpress (~$1.70)
Ebay  .de .fr

NES controller
Aliexpress (~$2.99)
Ebay  .de .fr

NES extension cord
Aliexpress (~$1.65)
Ebay  .de .fr

The oscilloscope came quite handy this project. I really like it, check it out:
Amazon.com .de .ca .fr

Setup

The controller connectors consist of 7 pins which are assigned like this:

VCC can be 5 or 3.3V. LATCH and CLOCK are output pins and DATA is an input pin. Multiple controllers can share the CLOCK and DATA but each controller need an individual DATA pin which should be pulled up to prevent button presses when the controller is disconnected.

Protocol

  1. Start with LATCH low and CLOCK high.
  2. The LATCH pin is set high for 12µs.
  3. Then low again and wait 6µs
  4. Read button state from DATA (all DATAs if multiple controllers)
  5. Set CLOCK low for 6µs
  6. Set CLOCK high for 6µs
  7. Repeat from step 4 until all buttons are read

This are the button indices:

Code

 

You can get all latest files from my github repository:
https://github.com/bitluni/ArduinoGameController

You can copy the GameControllers.h into your Arduino project and include it like this:

 

#include "GameControllers.h"

You need to have two shared pins between all controllers

const int LATCH_PIN = 16;
const int CLOCK_PIN = 17;

…and one data pin per controller

const int DATA_PIN_0 = 18;

This is how it’s initialized:

GameControllers controllers;

void setup()
{
  Serial.begin(115200); //prepare serial for text output 
  //initialize shared pins
  controllers.init(LATCH_PIN, CLOCK_PIN); 
  //activate first controller ans set the type to SNES
  controllers.setController(0, GameControllers::SNES, DATA_PIN_0);
}

To add more controllers just repeat setController with the controller index as first parameter and the individual controller type and data pin. SNES and NES controllers can be mixed.

To read the controllers you have to call poll once a loop. THen you can check for all buttons of all controllers just like this:

void loop()
{
  controllers.poll(); //read all controllers at once
  if(controllers.pressed(0, GameControllers::START)) //check if Start was pressed since last loop
  Serial.println("Start was pressed.");
  if(controllers.pressed(0, GameControllers::A, 20)) //if A button is hold down repeat after 20 loops
  Serial.print("A");
  if(controllers.down(0, GameControllers::B)) //check if B button it's currently pressed down
  Serial.print("B");
  delay(50); //read controller just ~20times a second
}

Tetris clone

The current state is really alpha but you can find it here:
https://github.com/bitluni/TetrisSpaceX

Links

Composite Video on the ESP32