NES Controller / GameBoy Button Translation


Yahtzee! Great work - looking forward to the video!

Yeah, saw your instagram post about the consolizer:

Let me know if you still need any help with the Arduino code - talking to a NES controller is a solved problem :slight_smile: @Mr.Blinky has some nice code for that:

VGA1306 (VGA-out for DIY Arduboys implemented on an FPGA!)
(Elliot Goofe) #2

Oh hell yeah! So this works for DMG and not just Arduboy? This was something I couldn’t fully get my head around. I really want to integrate a NES controller into the consolizer.


Just the output side of the code would need to be adjusted - to present the output ‘four buttons at a time’ like the DMG wants:

…you have sending button presses to the DMG working though, right? Just need the part for getting button inputs from the joypad?

(Elliot Goofe) #4

Was able to get half the buttons working: start, select, a, b, sort of. So half of that circuit. My buddy Postman helped me with getting that bit of code. I’m not the best myself with programming.

We had issues converting the 8 bits of data to 4 so the Gameboy could read it. In that Instagram post I have a video demoing pressing the A button that basically presses random buttons at a time.

Any info to help move forward would be much appreciated!

I made a diagram to show the button traces that go to the DAN225 diodes that communicate with the cpu for button presses if that helps anyone.

I would really love to see controls working without the need for the front PCB. I’ve already tested the board outputs video without it, - audio and buttons.


Post the code or a link to the code and it should be straightforward enough - heading to the beach, so might be a while before I can reply! :slight_smile:

(Elliot Goofe) #6
const int A_BUTTON         = 0;
const int B_BUTTON         = 1;
const int SELECT_BUTTON    = 2;
const int START_BUTTON     = 3;

const int DOWN_BUTTON      = 3;
const int UP_BUTTON        = 2;
const int LEFT_BUTTON      = 1;
const int RIGHT_BUTTON     = 0;

byte nesRegisterP14  = 0;    // We will use this to hold button states in first four bits pertaining to D-pad
byte nesRegisterP15  = 0;    // We will use this to hold button states in the second four bits of data pertaining to A, B, Select, and Start

int nesData = 4; //Data pin for NES Controler
int P14 = A4; //P14 pin on GameBoy's CPU, Set low to read d-pad input
int P15 = A5; //P15 pin on Gameboy's CPU, set low to read A, B, Start, Select

int nesClock = 2; //CLK pin for NES controller
int nesLatch = 3; //Latch pin for NES controller

/*P10-13 represent bits of controller info controlled by P14 and P15 states
P10 -> d-pad right or a
P11 -> d-pad left or b
P12 -> d-pad up or select
P13 -> d-pad down or start*/

int P10 = 6;
int P11 = 7;
int P12 = 8;
int P13 = 9;

byte readNesControllerP14()
  int tempData1 = 127;

  digitalWrite(nesLatch, HIGH);
  digitalWrite(nesLatch, LOW);
    // Up button
  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData1, UP_BUTTON);
  // Down button
  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData1, DOWN_BUTTON);

  // Left button
  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData1, LEFT_BUTTON);  
  // Right button
  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData1, RIGHT_BUTTON);

  return tempData1;

byte readNesControllerP15()
  int tempData2 = 127;

  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData2, A_BUTTON);
  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData2, B_BUTTON);
  // Select button
  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData2, SELECT_BUTTON);

  // Start button
  digitalWrite(nesClock, HIGH);
  digitalWrite(nesClock, LOW);
  if (digitalRead(nesData) == LOW)
    bitClear(tempData2, START_BUTTON);

    return tempData2;

void setup()
  //Setting input pins to inputs
  pinMode(nesData, INPUT_PULLUP);
  pinMode(P14, INPUT_PULLUP);
  pinMode(P15, INPUT_PULLUP);

  //Setting output pins to output
  pinMode(nesClock, OUTPUT);
  pinMode(nesLatch, OUTPUT);
  pinMode(P10, OUTPUT);
  pinMode(P11, OUTPUT);
  pinMode(P12, OUTPUT);
  pinMode(P13, OUTPUT);

  //setting initial states
  digitalWrite(nesClock, LOW);
  digitalWrite(nesLatch, LOW);


void loop()

  // Quickly pulse the nesLatch pin so that the register grab what it see on
  // its parallel data pins.

  if(analogRead(P14) > 127)
    nesRegisterP14 = readNesControllerP14();

    digitalWrite(P10, bitRead(nesRegisterP14, RIGHT_BUTTON));
    digitalWrite(P11, bitRead(nesRegisterP14, LEFT_BUTTON));
    digitalWrite(P12, bitRead(nesRegisterP14, UP_BUTTON));
    digitalWrite(P13, bitRead(nesRegisterP14, DOWN_BUTTON));

  if(analogRead(P15) <= 127)
    nesRegisterP15 = readNesControllerP15();

    digitalWrite(P10, bitRead(nesRegisterP15, A_BUTTON));
    digitalWrite(P11, bitRead(nesRegisterP15, B_BUTTON));
    digitalWrite(P12, bitRead(nesRegisterP15, SELECT_BUTTON));
    digitalWrite(P13, bitRead(nesRegisterP15, START_BUTTON));

Serial.println("P14 val");
Serial.println("P15 val");


(Pharap) #7

I’ve formatted your code for you. You might want to have a read of this:

Particularly this section. Knowing markdown comes in very handy.

(Don’t let the onebox fool you, it’s a page on the project’s wiki. Really it ought to be a separate repo or a gist or something.)


OK, have adapted @Mr.Blinky’s code accordingly, and edited the pin numbers to match the ones used in your code - here you go:

…let me know how that goes?

(Elliot Goofe) #9

Is this supposed to be in the code? Should we be defining it as a byte? There’s no function to feed these values into.

Tried uploading the code. The buttons sort of work, other times it freezes or resets.


Might work better using interrupts for P14 / P15, will set up something and play here - what is the specific Arduino board you are using?

(Elliot Goofe) #11

M0 with samd21. We are using “hard coded” interrupts. It’s sort of working. We have glitchy dpad control and combos of start/a start/b.

I’ll post the updated code with comments in my Google drive.


SAMD21 is 3.3V though? (and a bit of overkill? :slight_smile:) I have it working and pretty stable now on a 5V Pro Micro (if you have a Leonardo / Micro / Pro Micro around you can use the same code and pin assignments, otherwise would need to adjust the PORT / PIN commands to be specific to your board):

…didn’t have a NES controller close-to-hand, so used this ASCII Stick instead! :smile:

(Elliot Goofe) #13

Hehe yes a bit overkill. I’ll use a Pro Micro. Testing currently.

Just wondering what _BV is reffering to? I’m just making sure I don’t need to add anything else to compile.

Getting errors about PortF when compiling.

Are you including arduboy2core.cpp?


There is nothing else to add, should compile on its own. Errors about PORTF would mean you don’t have the right board selected? Pro Micro isn’t built-in to the Arduino IDE boards, but you can just select Leonardo.

(Elliot Goofe) #15

Thank you. I had to program a generic Pro Micro as a Leonardo. Trying to get it to work now. *Fingers crossed

Still having issues… :confused:

(Elliot Goofe) #16

I think the issue might stem from using a NES controller and you are using that ASCII controller. The NES uses a 4021 shift register IC. Which makes plugging the input to the Gameboy harder.


No, the ASCII Stick is a NES / Famicom controller with a 4021 inside - just had a weird form-factor… could you post a photo of your wiring to the Pro Micro? Did you follow the pin assignments in the code:

//DMG button driver pins
#define P10  A0
#define P11  A1
#define P12  A2
#define P13  A3
#define P14   2
#define P15   3

//NES controller pins

(Elliot Goofe) #18

Ah okay. My mistake. Here is a shot of the wiring. Sorry for the mess.


Wow :slight_smile: Heading out, so I’ll try and take a closer look later on - assuming that you are inserting pins on the breadboard to simulate button presses?

(Elliot Goofe) #20

Yup. The chip was from a controller with a broken pcb, so I had to remove that to test. This should work with a SNES controller too right?