Reading Sega Genesis controllers with Arduino


NOTICE: This research and implementation in this post is not 100% correct. Please check out my SegaController Arduino library for better code and How To Read Sega Controllers for details on how it works.


The Sega Genesis was my first and favorite childhood game console, so when I first picked up an Arduino a couple years ago, my first thought was to build something, anything, that used a Genesis controller. Unfortunately I got side-tracked by other projects, and the Arduino Uno I’d purchased got set aside.

Fast-forward to this year’s picade build, when I had to re-flash the main controller board, which at its heart is an Arduino Leonardo. Seeing how easy it was to work with, I finally decided to break out my Uno. After a couple sample sketches, I figured it was time start interfacing with some Genesis controllers.


I started poking around online to see what others had done, and couldn’t find quite what I was looking for. What I did find was plenty of information on how the three-button pads worked. Some used that info to implement full three-button support – others, it seems, were satisfied with having just some of the buttons working (essentially using the controller’s innate backward compatibility with the simpler Sega Master System’s two-button controller design). No one had six-button controllers working.

What I want is full three and six-button support, something that I can plug any Genesis controller into and it’ll “just work”, like an actual Genesis console. My requirements therefore are:

  1. Correctly reads connected three-button controllers.
  2. Correctly reads connected six-button controllers.
  3. Automatically detects which type of controller is connected, with hot-swapping.
  4. Bonus: Support more than one controller at a time.

The real godsend to the first two was finding Charles Rosenberg’s Sega Six Button Controller Hardware Info. There he describes almost everything you need to know about how Genesis controllers work. I highly recommend giving it a full read for the really gory details before continuing, but here’s a “quick” overview:

How Sega Genesis controllers work

All Genesis controllers use a standard nine-pin DB9 serial port. On your regular three-button controller, you really have a total of eight buttons: Up, Down, Left, Right, A, B, C, and Start. With nine pins to work with, Sega could easily have gone with one +5v in and eight outputs back to the console and be done with it. But instead, in the interest of backwards compatibility with the Sega Master System (and potentially other DB9 based controllers like the old Atari joysticks), they implemented a simple multiplexer circuit.

Essentially you have three control pins (+5v power, ground, select) and six output pins. By default, all of the output pins are set high (meaning a button press will bring the pin down to ground). The Genesis (or more specifically, the game running on the Genesis) sets the select pin (DB9 pin seven) low, then reads the state of the six output pins to get the states for the Up, Down, A, and Start buttons. Then the game toggles the select pin to high, and re-reads those same six output pins to get the states of the Up (again), Down (again), Left, Right, B, and C buttons.

DB9 Pin Select is low Select is high
1 Up Up
2 Down Down
3 Ground Left
4 Ground Right
5 Control: +5V
6 A B
7 Control: Select
8 Control: Ground
9 Start C

The algorithm is pretty straight forward to implement on the Arduino, polling the controller exactly the way a Genesis game would. This satisfies my first requirement. Now, things get a little more complicated with the six-button controller:

DB9 Pin Select is low Select is high Every 3rd select pulse
1 Up Up Z
2 Down Down Y
3 Ground Left X
4 Ground Right
5 Control: +5V
6 A B
7 Control: Select
8 Control: Ground
9 Start C

First, let’s call each dropping of the select pin to low then back to high a “select pulse”. Now, on every third select pulse the six-button controller will instead report back the states of the X, Y, and Z buttons (instead of Up, Down, and Left). On its face, it looks like we couldn’t have a game that supports both three and six-button controllers, because how does a game know what kind of controller is connected? On every third pulse how does a six-button enabled game know whether to use the first table or the second? On every third pulse, how does a six-button controller know not to report X, Y, Z for games that only support three-buttons? If the game and controller aren’t on the same page and they use the wrong mappings, they’ll record incorrect button presses.

How do the games and controllers make the right decisions?

One part of the answer (as described in Rosenberg’s notes) is in how often games actually poll the controller. The three-button controller uses dumb direct logic, which means it always uses the first table. It also means that technically you can poll the controller state super-fast (say every 50 microseconds) or super-slow (say every 20 milliseconds) and always get the same result. Now typically, a game is only going to poll the controller once per game frame (sixty times per second, or every 16.6 milliseconds). Which means, at the time of the six-button controller’s release, the vast majority of the games already published (which were three-button enabled only) only sent a single select pulse every ~16 milliseconds.

The six-button controller can use this to its advantage. Instead of dumb direct logic, it uses an IC to watch how often the select pulses come in. The IC knows that (given the game indicates it wants six-button mode), it should return the states of X, Y, and Z on every third select pulse. But it also knows that most games only support three-button mode, so a safe default is to just pretend to be a three-button controller and ignore reporting X, Y, and Z on every third pulse.

How does the controller decide? The frequency of the select pulses. If the IC only sees one select pulse every ~16 milliseconds, or one pulse per game frame, then its best bet is to take the safe route and assume three-button mode. In this way, the six-button controller is backwards-compatible, and most games will never get any incorrect button presses.

If that’s the case, how does a game indicate that it actually wants those X, Y, and Z buttons?

If the game believes that a six-button controller is attached, it will instead pulse the select line three times very quickly in one game frame. The first two times the game reads (and the controller reports) the button presses for three-button mode. Then the game pulses the controller a third time. At that point, the controller’s IC, seeing how quickly those pulses came in, presumes the game wants X, Y, and Z, so it reports X, Y, and Z.

So to sum up: if a game just wants the three-button control states, it pulses once every frame and uses the first table to read the results. If a game wants six-button control states, it pulses three times in one frame, using the second table to read the results. With this in mind, we can now read both controller types, which satisfies the first two of my requirements. We can easily implement an Arduino sketch that implements one or the other algorithm, if we already know which type of controller we’re going to have connected.

But what about my third requirement? What if we want one sketch that implements both modes? How do we make our board detect what kind of controller is connected?

This one took a little bit of experimenting to figure out, since Rosenberg’s notes don’t address the issue. Turns out the six-button controller’s IC has another trick up its sleeve with watching how fast those select pulses come in. As we just saw, since most games only expect three-button controls, the controller can default to three-button mode, and seeing slow pulses, will stay in three-button mode.

But now, if the game wants to check for a six-button controller, it can send rapid select pulses when a controller is connected, and if it’s a six-button controller, the IC will report that both the Up and Down buttons are being pressed at the same time!

Under normal circumstances this is impossible, as the controller’s d-pad rocks in the direction you press it. So with this neat trick, the controller lets the game know that a six-button controller is connected, giving the game to option to start polling the controller in six-button mode.

The way we implement this is simple: by default we poll in three-button mode very quickly. For three-button controllers, this works perfectly. After every pulse, we can check for both Up and Down being pressed at the same time. If we see that, we know a six-button controller is attached, so we switch to six-button mode, pulsing more slowly so that we don’t reset the IC.

This solves the first part of my third requirement: detecting when a six-button controller is connected. But what about the other way? The way it stands, once we connect a six-button controller, and our board switches to six-button polling, it’s stuck that way until we reset the board. If we hot-swap from a six-button to a three-button controller, we’ll get those annoying paired inputs (specifically, pressing Up will return Up and Z, Down will return Down and Y, Left will return Left and X).

What we need is a way of knowing when a controller is disconnected, so that we can switch back to the default three-button polling. Turns out we have everything we need in the tables above, something that works for both three and six-button controllers.

At the very beginning I said that by default the console puts all six of the DB9 output pins high, so that a button press causes the pin to drop low. So if no controllers are connected those output pins should stay high. Only a button press from a connected controller will drop a pin low, right? We could just press a button to let the board know we have a controller connected, but wait, there’s a better way!

As we can see in the tables above, when the select pin is low, DB9 pins three and four both go low, regardless of any button presses. So in effect, the controller presses imaginary buttons on pins three and four when select is low automatically. So, all we have to do is watch those pins – if they go low when select is low, then we know a controller is connected. If they’re high when select is low, it means the controller is no longer connected.

In implementation terms, when select is low, we can simply check those two pins like we would for any other button, and map the results of those imaginary “On” buttons. Watching those “buttons” we know when a controller is connected or not, and therefore we can easily switch back to three-button mode when a controller is disconnected. With that we now have everything we need to satisfy my main three requirements for the board. As for the 4th and final bonus requirement, recognizing that we only needed seven pins to read one controller, we’ve got plenty of left-over pins on the Uno to cover connecting one more.

The Sketch

Ok, so now for the sketch. Our basic algorithm is the following:

  • Default to three-button polling as fast as possible, using the first table and select pulsing algorithm.
  • If you ever see both Up and Down pressed at the same time, switch to six-button polling, using the second table and select pulsing algorithm.
  • If you ever see the “On” button state go away, switch back to three-button controller polling.
 * Sega Controller Reader
 * Author: Jon Thysell <>
 * Version: 1.0
 * Date: 7/26/2014
 * Reads buttons presses from Sega Genesis 3/6 button controllers
 * and reports their state via the Serial connection. Handles hot
 * swapping of controllers and auto-switches between 3 and 6 button
 * polling patterns.

// Controller Button Flags
const int ON = 1;
const int UP = 2;
const int DOWN = 4;
const int LEFT = 8;
const int RIGHT = 16;
const int START = 32;
const int A = 64;
const int B = 128;
const int C = 256;
const int X = 512;
const int Y = 1024;
const int Z = 2048;

// Controller DB9 Pin 7 Mappings
const int SELECT[] = { 8, 9 };

typedef struct
  int player;
  int pin;
  int lowFlag;
  int highFlag;
  int pulse3Flag;
} input;

// Controller DB9 Pin to Button Flag Mappings
// First column is the controller index, second column
// is the Arduino pin that the controller's DB9 pin is
// attached to
input inputMap[] = {
  { 0,  2,  UP,    UP,     Z}, // P0 DB9 Pin 1
  { 0,  3,  DOWN,  DOWN,   Y}, // P0 DB9 Pin 2
  { 0,  4,  ON,    LEFT,   X}, // P0 DB9 Pin 3
  { 0,  5,  ON,    RIGHT,  0}, // P0 DB9 Pin 4
  { 0,  6,  A,     B,      0}, // P0 DB9 Pin 6
  { 0,  7,  START, C,      0}, // P0 DB9 Pin 9
  { 1,  A0, UP,    UP,     Z}, // P1 DB9 Pin 1
  { 1,  A1, DOWN,  DOWN,   Y}, // P1 DB9 Pin 2
  { 1,  A2, ON,    LEFT,   X}, // P1 DB9 Pin 3
  { 1,  A3, ON,    RIGHT,  0}, // P1 DB9 Pin 4
  { 1,  A4, A,     B,      0}, // P1 DB9 Pin 6
  { 1,  A5, START, C,      0}  // P1 DB9 Pin 9

// Controller State
int currentState[] = { 0, 0 };
int lastState[] = { -1, -1 };

// Default to three-button mode until six-button connects
boolean sixButtonMode[] = { false, false };

void setup()
  // Setup input pins
  for (int i = 0; i < sizeof(inputMap) / sizeof(input); i++)
    pinMode(inputMap[i].pin, INPUT);
    digitalWrite(inputMap[i].pin, HIGH);

  // Setup select pins
  for (int i = 0; i < 2; i++)
    pinMode(SELECT[i], OUTPUT);
    digitalWrite(SELECT[i], HIGH);


void loop()

void readButtons()
  for (int i = 0; i < 2; i++)
    if (sixButtonMode[i])

void resetState(int player)
  currentState[player] = 0;

void read3buttons(int player)
  // Set SELECT LOW and read lowFlag
  digitalWrite(SELECT[player], LOW);


  for (int i = 0; i < sizeof(inputMap) / sizeof(input); i++)
    if (inputMap[i].player == player && digitalRead(inputMap[i].pin) == LOW)
      currentState[player] |= inputMap[i].lowFlag;

  // Set SELECT HIGH and read highFlag
  digitalWrite(SELECT[player], HIGH);


  for (int i = 0; i < sizeof(inputMap) / sizeof(input); i++)
    if (inputMap[i].player == player && digitalRead(inputMap[i].pin) == LOW)
      currentState[player] |= inputMap[i].highFlag;

  // When a six-button first connects, it'll spam UP and DOWN,
  // which signals the game to switch to 6-button polling
  if (currentState[player] == (ON | UP | DOWN))
    sixButtonMode[player] = true;
  // When a controller disconnects, revert to three-button polling
  else if ((currentState[player] & ON) == 0)
    sixButtonMode[player] = false;


void read6buttons(int player)
  // Poll for three-button states twice

  // After two three-button polls, pulse the SELECT line
  // so the six-button reports the higher button states
  digitalWrite(SELECT[player], LOW);
  digitalWrite(SELECT[player], HIGH);

  for(int i = 0; i < sizeof(inputMap) / sizeof(input); i++)
    if (inputMap[i].player == player && digitalRead(inputMap[i].pin) == LOW)
      currentState[player] |= inputMap[i].pulse3Flag;


void sendStates()
  // Only report controller states if at least one has changed
  boolean hasChanged = false;

  for (int i = 0; i < 2; i++)
    if (currentState[i] != lastState[i])
      hasChanged = true;

  if (hasChanged)
    for (int i = 0; i < 2; i++)
      Serial.print((currentState[i] & ON) == ON ? "+" : "-");
      Serial.print((currentState[i] & UP) == UP ? "U" : "0");
      Serial.print((currentState[i] & DOWN) == DOWN ? "D" : "0");
      Serial.print((currentState[i] & LEFT) == LEFT ? "L" : "0");
      Serial.print((currentState[i] & RIGHT) == RIGHT ? "R" : "0");
      Serial.print((currentState[i] & START) == START ? "S" : "0");
      Serial.print((currentState[i] & A) == A ? "A" : "0");
      Serial.print((currentState[i] & B) == B ? "B" : "0");
      Serial.print((currentState[i] & C) == C ? "C" : "0");
      Serial.print((currentState[i] & X) == X ? "X" : "0");
      Serial.print((currentState[i] & Y) == Y ? "Y" : "0");
      Serial.print((currentState[i] & Z) == Z ? "Z" : "0");

      Serial.print((i == 0) ? "," : "\n");
      lastState[i] = currentState[i];

All you have to do is upload the sketch and connect the controller’s DB9 pins to the Arduino following the mapping in inputMap in the code. Then start up the Serial Monitor so you can see the output from the controller on your PC.

Here’s a closeup of how I’ve wired my Uno to a male DB9 breakout board (you can wire straight to the controller, or a male DB9 port, but I found the board the easiest solution):


The sketch is also set up for a second controller connected to the analog pins on the other side of the Arduino, though I only had one male DB9 breakout board. Also note that this is my first real Arduino sketch, so I’m sure there are some best practices I’m breaking in my design.

I can already see room for future improvements. Right now I report the controller states over the serial connection as strings – easy to debug, but slow and wasteful. Of course, in your own sketches, you can just read the currentState integers directly.

Hope this helps anyone else out there trying to interface with Genesis controllers. Happy hacking!


PS. Obviously in the process of plugging and unplugging controllers, you may see some errant random button presses recorded. In the world of video games, this is to be expected, and only lasts for a second. If however, you’re planning on doing anything “bad” with a button press (say enabling a thermonuclear detonator), you might want to avoid hot-swapping controllers.

PPS. Final note, concerning the six-button controller’s “mode” button. Some games (notably Ms. Pac Man), don’t follow the rule of only polling the controller once per game frame, and select pulses more often. This causes erratic behavior as incorrect buttons presses are recorded. Ostensibly, when you plug in a six-button controller with the mode button held down, that signals the IC in the controller to always be in three-button mode and never report X, Y, or Z. Unfortunately, I couldn’t get it to work with my sketch and gave up because I saw no reason to limit my six-button controller to three-buttons anyway.

Update 29-SEP-2014: I’ve uploaded a new version of the sketch in Sega Genesis controllers and Arduino revisited, which includes support for reading the “Mode” button and reporting button presses as keyboard key presses (on compatible Arduino boards).

Update 26-JUN-2017: The source is now available on GitHub here.

Update 28-JUN-2017: I’ve announced a newer, stable, reusable version at Introducing the SegaController Arduino library.

What I use in 2012, Part 1: Hardware

I like to see how people work; especially for those whose work is mostly on the computer. So in the spirit of Paul Thurrott‘s What I Use for Home and Office Technology, and Lifehacker‘s How I Work series, I present the following list of what technology I use at home.

Note: I don’t endorse anything here beyond the implicit “this is what I actually use at home.”


Hester: Lenovo ThinkPad T420 (Notebook)

Hester is my primary machine, and is named after the main character in my Guineawick Tales stories. It’s got a 2.6GHz Intel Core i5 CPU and 8GB of RAM. It boots from a zippy 80GB SSD, and has second 500GB hard drive for storage. It has a 14″ 1600×900 screen and a 9-cell extended battery; I like my machines light and easy to travel with.

I love and use the TrackPoint almost exclusively, only using a Microsoft Bluetooth Notebook Mouse 5000 when I want a mouse, since Hester has Bluetooth built-in and that means no USB dongle.

Hester currently runs Ubuntu 11.10 “Oneiric Ocelot”, and has never seen a copy of Windows outside of a virtual machine. But more on the software in Part 2.

Cortana: ASUS EeePC 1000HA (Netbook)

Cortana is my secondary “swings in to save the day” machine, named after the Halo character. It’s got a 1.6GHz Intel Atom CPU and 2GB of RAM. It came with a 160GB hard disk, which I replaced with a 32GB SSD. The model didn’t offer Bluetooth when I bought it, but that didn’t stop me from installing the radio from another laptop anyway.

Cortana has a 10″ 1024×600 screen, which, along with the poor Adobe Flash support, is really its only weakness. When the original battery died, I replaced it with a monster 12-cell that gives me a whopping 14 hours battery life (only 8 with WiFi on).

Cortana spent its longest time running Ubuntu 10.10 “Maverick Meerkat”, but has also run Ubuntu 11.04 “Natty Narwhal”, Windows XP Home, Windows 7 Home Premium and Ultimate, as well as Windows 8. Last I checked it’s running Windows 7 Ultimate (I flatten this machine so much it’s hard to keep track).

I’ve won three NaNoWriMos on Cortana. It’s saved my butt at work on numerous occasions. This little machine has proved its worth so many times I’m probably going to bronze it when it finally dies.

Serenity: Dell Vostro 200 Slim (Desktop)

Serenity was my primary machine for four years until I bought Hester, and is named for the Firefly ship. It has a 3.0GHz Intel Core 2 Duo CPU and 4GB RAM. It boots from its original 80GB hard drive, but has an additional 1TB drive for storage.

It powers two 22″ 1920×1080 Dell S2209W monitors with a GeForce 8400 GS video card, and I used a Logitech Trackman Marble Trackball along with a Logitech Classic Keyboard 200.

Serenity started its life running Windows XP Pro, but then moved on to a long life with Ubuntu, starting with 7.10 “Gutsy Gibbon” and surviving 8 in-place upgrades to 11.10 without a hitch. It is only after Hester became my primary machine that I put Windows 7 Ultimate on Serenity, namely as a joint machine for Anne and I. Unfortunately, I find my lifestyle doesn’t require a desktop these days (and the desk to support it), and so Serenity has migrated into the closet indefinitely.

Horatio: MSI Wind Nettop 100 (Server)

Horatio is my personal file/backup/utility server, named after Horatio Hornblower. It’s got a 1.6GHz Intel Atom CPU and 1GB of RAM. It has two low-power hard drives, for a total of 2.5TB of storage. As a nettop with green hard-drives, it uses only a miniscule 35W of power.

The primary purpose of Horatio is to be a backup server. All of my other machines backup daily to Horatio. I also store my entire media collection here, so that I can stream it to whatever machine I’m currently on.

Horatio runs Ubuntu 12.04.

Franklin: ASUS EB1007-B0410 EeeBox Mini (Server)

Franklin is my remote backup server, named after Benjamin Franklin. It’s got a 1.6GHz Intel Atom CPU (gotta love those Atoms!) with 1GB RAM and a 250GB hard drive.

The primary purpose of Franklin is to store backups of my backups, off-site from my home. As all of my machines backup to Horatio on a regular basis, so does Horatio backup to Franklin. Because of the lack of storage space (I wanted a tiny, silent machine)  I only backup my personal data and music to Franklin. Movies and other video content only live on Horatio for the time being.

Franklin runs Ubuntu 12.04.


Right now I carry an HTC Trophy running Windows Phone 7.5, which is named Jacobi after a character in my upcoming Guineawick Tales novel, Hester and the Kookaburra King. I’ve got an extended battery so I can go two days with heavy use and not charge.

I moved earlier this year, and as an experiment I used Jacobi as my primary computing device for a little over a month, while everything else was packed away. Email, web browsing, gaming, music, movies and reading. The phone held up remarkably well- enough that if I wasn’t a software developer or a writer, I could live pretty happy with just my phone. (You believe me, right?)

My previous phone was an LG Optimus S running Android 2.3.3, and the phone before that was the ill-fated Palm Pre. In general I like smaller phones; I for one am against the trend of larger, flatter devices.

Portable Devices

SanDisk Sansa Clip+

This $50 MP3 player is the best I’ve ever owned, and that’s including the Cowon iAudio5 that survived my service in Africa. My Sansa Clip+ has 4GB storage built-in, and I’ve added a 16GB card so I can carry my entire music collection plus podcasts and audiobooks.

While the original factory software was pretty good, I upgraded to the Rockbox open-source firmware, which really makes this little player shine. It lives mostly in my car, mounted to the dash, but I also clip it to my pocket when I go running.

Pocketbook 360

I’ve written about my PB360. Twice in fact. I still think that, even years after its original release, it still holds its own very well against the latest crop of Nooks and Kindles.

However, I’ll admit that the hassle of carrying a second device around means I hardly use my PB360 any more. I just want to read way more often than I want to carry around an e-ink reader. I do the majority of my reading on my phone these days; it’s a lot quieter and works in the dark.

Dingoo A320

I’m a big retro-gaming fan, and while I appreciate the strides in touch-screen based gaming on phones, give me a Sega Genesis and a controller any day. My Dingoo A320, on which I’ve installed Linux, lets me carry around pretty much every retro game, on every retro system, that I could ever want to play, and do it really well. When I want to play old games, this is where I go.


It’s amazing how quickly this little step counter as become “attached to my hip”. (Pun way, way intended). I’ve only had a Fitbit for a few months, but I think I’ve only ever forgotten to carry it once (and believe me, it bothered me all day).

I don’t put too much stock into its numbers- mainly it serves as a physical reminder for me to take the stairs over the elevator, to get up and take breaks from my desk at work. It’s just a really geeky string tied to my finger, but it works too well for me to give it up.

Home Technology

Internet, TV

I get Comcast High Speed Internet and average ~60Mbps down, ~15 Mbps up. I pay for TV service because it lowers my Internet bill, though I’m a cord-cutter in spirit: I have no cable-box and I haven’t hooked up a TV to the cable in several years.

Xbox 360

I work at Xbox, so it’s no surprise that I have an Xbox 360 in my home. Two, if you count Anne’s. Nothing special about it, other than a 250GB upgrade, though I do have a MadCatz Street Fighter IV Fightstick that I replaced the guts with a higher quality joystick and arcade machine buttons. I use it mainly for playing Pac-Man though.

My Xbox is set up in my game room / office with an Onkyo 5.1 surround system and (for now) a Insignia 32″ 720p HDTV. My 40″ Samsung 1080p HDTV is currently serving the living room, along with the other Xbox, an LG soundbar, and an LG Blu-ray player.

We have two Logitech Harmony 610 remotes, one for the living room, one for the game room. They’re perfect, and essential for keeping everything in sync. Haven’t had to touch the original remotes for anything in years.

Everything Else

These are just the things that I think of when I think of “what I use”. Believe me, I have lots more hardware lying around, though I try to regularly sell off or toss what I don’t use any more. Everything except cables: you can never have too many extra cables.

I have a Wii that’s ostensibly set up for retro gaming, though I haven’t powered it on more than a dozen times in the past couple years. I have a digital camera that I religiously charge the batteries for trips and events, but always forget to take pictures with.

“Too Long, Didn’t Read” Summary

I am a nerd with way too many toys and I’m rarely satisfied unless I’ve broken their warranty and made them do more than the manufacturer intended. Especially if it means getting a longer battery life. I prefer Linux over Windows, except with my phone.

And remember, this is just my personal stuff- none of this includes the tech I use for my work as an engineer at Microsoft. Hmmm, that might be an interesting post…


Update (9/22/12): Be sure to check out What I use in 2012, Part 2: Software.

P.S. So what do you use at home? Leave a comment below!