Intellivision

Way back in September 2016 I made an adapter to use an Intellivision controller on a PC, here’s how I did that…

I decided that the simplest way would be to encode the inputs as keyboard keys, rather than a regular game controller as other people have done. This is for two reasons, one, it wont be used for anything other than playing specific emulated games and two, it has a digital 16 direction digital pad, which would make use with emulators a little trickier than it would need to be (digital to analog and back to digital is just a waste).

The way that the internals of the controller are designed are insane, but they do get the job done. It was more difficult than I expected to figure out what on earth was going on to decode it, with most button presses requiring more than one pin to be grounded at a time!

I had hoped to internalize the adapter, but that can’t happen. There is literally less than no space inside.

Here is a little techie info…

The controller uses a 9-pin interface, originally hard wired to the console, but later connected using a DB9 connector. The controller has an insane 15 buttons and 12 directions, which are read from different combinations of those wires being grounded. The ’16’ directions claimed are really just 12, with some of the directions combined, much like the way modern 4-way d-pads emulate 8 directions by pressing up+left for example.

I mapped the inputs to the following keys..

  +---+---+---+
X | 1 | 2 | 3 | X
  +---+---+---+
Y | 4 | 5 | 6 | Z
  +---+---+---+
  | 7 | 8 | 9 |
  +---+---+---+
  |BS | 0 |ENT|
  +---+---+---+

      p a b 
    n   |   d
    m---o---e
    l   |   f
      j i h  

Notice the two top side buttons are the same and the 12 directions are missing the 45 degree mapping, The only accurate way to do this was to actually send two keys for these directions, so up-right would send b+d at once.

As usual, here is the source for anyone else who want’s to do this…

#include <Keyboard.h>

/*
  +---+---+---+
X | 1 | 2 | 3 | X
  +---+---+---+
Y | 4 | 5 | 6 | Z
  +---+---+---+
  | 7 | 8 | 9 |
  +---+---+---+
  |BS | 0 |ENT|
  +---+---+---+
      p a b 
    n   |   d
    m---o---e
    l   |   f
      j i h  
  No 45 degree angles, the intellivision only pretended to have 16 directions, it was really 12.


     Intellivision - Arduino

5 <==-       Black - Ground
6    -==>   Yellow - 6
4 <==-         Red - 5
7    -==>     Blue - 7
3 <==-       Brown - 4
8    -==>    White - 8
2 <==-     Yellow* - 3
9    -==>     Red* - 9
1 <==-      White* - 2



*/

int myPin[8]={4,5,6,7,8,9,10,11};
unsigned char wire;
unsigned char oldWire=B11111111;
unsigned char buttonState;
int ledPin = 13; // choose the pin for the LED
bool ledOn = 0;

int counter=0;

void setup() {
  // begin serial com
   //Serial.begin(9600);
  
  // Set pins 2 to 9 as input and pull high
  for(int t=0; t<8; t++){
    pinMode( myPin[t] , INPUT_PULLUP );
  }

  pinMode(ledPin, OUTPUT);  // declare LED as output
  digitalWrite(ledPin, LOW);  // turn LED OFF

  // initialize control over the keyboard:
  Keyboard.begin();
}

void loop() {

  delay(5);
    wire = 0; // clear byte
    for(int t=0; t<8; t++){
      wire |= ((digitalRead(myPin[t])==LOW ? 1:0)<<(7-t));
    }

  if(wire != oldWire){
    Keyboard.releaseAll();
    oldWire = wire;
    ledOn = 1-ledOn;
    digitalWrite(ledPin, ledOn);  // turn LED OFF
  }
  
    buttonState = wire;
    if(wire == 0){
   //   Keyboard.releaseAll();
    }

int done = 0;
    if((buttonState & B00001010) == B00001010){ Keyboard.press('x'); done = 1;}
    if((buttonState & B00000110) == B00000110){ Keyboard.press('y'); done = 1;}
    if((buttonState & B00001100) == B00001100){ Keyboard.press('z'); done = 1;}
    
    if(done == 0){
      switch(buttonState){
        case B00011000: Keyboard.press('1'); break;
        case B00010100: Keyboard.press('2'); break;
        case B00010010: Keyboard.press('3'); break;
        case B00101000: Keyboard.press('4'); break;
        case B00100100: Keyboard.press('5'); break;
        case B00100010: Keyboard.press('6'); break;
        case B01001000: Keyboard.press('7'); break;
        case B01000100: Keyboard.press('8'); break;
        case B01000010: Keyboard.press('9'); break;
        case B10001000: Keyboard.press(KEY_BACKSPACE); break;
        case B10000100: Keyboard.press('0'); break;
        case B10000010: Keyboard.press(KEY_RETURN); break;
  
        case B01000000: Keyboard.press('a'); break;
        case B01000001: Keyboard.press('b'); break;
        case B01100001: Keyboard.press('b'); Keyboard.press('d'); break;
        case B01100000: Keyboard.press('d'); break;
        case B00100000: Keyboard.press('e'); break;
        case B00100001: Keyboard.press('f'); break;
        case B00110001: Keyboard.press('f'); Keyboard.press('h'); break;
        case B00110000: Keyboard.press('h'); break;
        case B00010000: Keyboard.press('i'); break;
        case B00010001: Keyboard.press('j'); break;
        case B10010001: Keyboard.press('j'); Keyboard.press('l'); break;
        case B10010000: Keyboard.press('l'); break;
        case B10000000: Keyboard.press('m'); break;
        case B10000001: Keyboard.press('n'); break;
        case B11000001: Keyboard.press('n'); Keyboard.press('p'); break;
        case B11000000: Keyboard.press('p'); break;
  //      default: Keyboard.releaseAll();
      }
    }
  
  
}

Final version, kept the above just in case.
This one is a solderless solution (if your Arduino (or clone) already has pin headers) So you can just plug the version 1 controller straight into your Arduino and change the pin numbers to match.

Arduino - Intellivision
    GND - 5
     D0 - 4
     D1 - 3
     D2 - 2
     D3 - 1
     D4 - 9
     D5 - 8
     D6 - 7
     D7 - 6

For my final version, I substituted GND for C2 simply because it was next to D0, and set it to OUTPUT and LOW so that it would act as Ground.

#include <Keyboard.h>

#define DIRMASK B11110001
#define ACTIONMASK B00001110
#define KEYMASK B1111110

int numPad[12]={
  B00011000, // 1
  B00010100, // 2
  B00010010, // 3
  B00101000, // 4
  B00100100, // 5
  B00100010, // 6
  B01001000, // 7
  B01000100, // 8
  B01000010, // 9
  B10001000, // Clear
  B10000100, // 0
  B10000010  // Enter
 };
int numKey[12]={'1','2','3','4','5','6','7','8','9',KEY_BACKSPACE,'0',KEY_RETURN};

/*
  +---+---+---+
X | 1 | 2 | 3 | X
  +---+---+---+
Y | 4 | 5 | 6 | Z
  +---+---+---+
  | 7 | 8 | 9 |
  +---+---+---+
  |BS | 0 |ENT|
  +---+---+---+
      p a b 
    n   |   d
    m---+---e
    l   |   f
      j i h  
  No 45 degree angles, the intellivision only pretended to have 16 directions, it was really 12.

*/

// Arduino Micro digital pins
//int myPin[8]={5,4,3,2,9,8,7,6};

// Mettairtech mattairtech mt-db-u2 digital pins
int myPin[8]={16,15,14,13,20,19,18,17};
int GND = 12;

unsigned char wire;
unsigned char oldWire=B11111111;
unsigned char buttonState;
int ledPin = 13; // choose the pin for the LED
bool ledOn = 0;

int counter=0;

void setup() {
  
  // begin serial com
  Serial.begin(9600);
  
  
  // Set pins 2 to 9 as input and pull high
  for(int t=0; t<8; t++){
    pinMode( myPin[t] , INPUT_PULLUP );
  }

  pinMode(GND, OUTPUT);
  digitalWrite(GND, LOW);
  
 // pinMode(ledPin, INPUT_PULLUP);  // declare LED as output
 // digitalWrite(ledPin, HIGH);  // turn LED OFF

  // initialize control over the keyboard:
  Keyboard.begin();
}

void readPad(){
  // Stupidly digital pin 13 also has an LED on it, so we must force it to input over and over.
  pinMode(ledPin, INPUT_PULLUP);  // declare LED as output
  digitalWrite(ledPin, HIGH);  // turn LED OFF
  delay(25); // debounce

  wire = 0; // clear byte
  for(int t=0; t<8; t++){
    wire |= ((digitalRead(myPin[t])==LOW ? 1:0)<<(7-t));
  }
  printBits(wire);
}

void loop() {

  readPad();
  if(wire != oldWire){
    Keyboard.releaseAll();
    readPad();
    oldWire = wire;
  }
    buttonState = wire;

    switch(buttonState & ACTIONMASK){ // side buttons
      case B00001010: Keyboard.press('x'); break;
      case B00000110: Keyboard.press('y'); break;
      case B00001100: Keyboard.press('z'); break;
    }

    // keypad (telephone) buttons
    bool pressed = 0;
    for(int t=0; t<12; t++){
      if((buttonState & numPad[t]) == numPad[t]){ Keyboard.press(numKey[t]); pressed = 1;}
    }

    if(pressed == 0){
      switch(buttonState & DIRMASK){ // disc directions
        case B01000000: Keyboard.press('a'); break;
        case B01000001: Keyboard.press('b'); break;
        case B01100001: Keyboard.press('b'); 
                        Keyboard.press('d'); break;
        case B01100000: Keyboard.press('d'); break;
        case B00100000: Keyboard.press('e'); break;
        case B00100001: Keyboard.press('f'); break;
        case B00110001: Keyboard.press('f'); 
                        Keyboard.press('h'); break;
        case B00110000: Keyboard.press('h'); break;
        case B00010000: Keyboard.press('i'); break;
        case B00010001: Keyboard.press('j'); break;
        case B10010001: Keyboard.press('j'); 
                        Keyboard.press('l'); break;
        case B10010000: Keyboard.press('l'); break;
        case B10000000: Keyboard.press('m'); break;
        case B10000001: Keyboard.press('n'); break;
        case B11000001: Keyboard.press('n'); 
                        Keyboard.press('p'); break;
        case B11000000: Keyboard.press('p'); break;
      }
    }    
}


void printBits(byte myByte){
 for(byte mask = 0x80; mask; mask >>= 1){
   if(mask  & myByte)
       Serial.print('1');
   else
       Serial.print('0');
 }
 Serial.println('.');
}

Here are how the controls are mapped. Stole an image, plonked a credit along the top.

Remember, The Intellivision doesn’t really have NorthEast, SouthEast, SouthWest or NorthWest, so don’t bother mapping thos in your emulator, just make sure you have NorthNorthEast, NorthEastEast, SouthEastEast, SouthSouthEast etc.

To use this in the ‘Nostalgia’ Intellivision emulator, just replace the following section in input.cfg…

[CONTROLLER 0]
<keyboard>
Keypad 0="0",""
Keypad 1="1",""
Keypad 2="2",""
Keypad 3="3",""
Keypad 4="4",""
Keypad 5="5",""
Keypad 6="6",""
Keypad 7="7",""
Keypad 8="8",""
Keypad 9="9",""
Keypad Clear="BACKSPACE",""
Keypad Enter="RETURN",""
Disc E="E",""
Disc ENE="D",""
Disc NE="",""
Disc NNE="B",""
Disc N="A",""
Disc NNW="P",""
Disc NW="",""
Disc WNW="N",""
Disc W="M",""
Disc WSW="L",""
Disc SW="",""
Disc SSW="J",""
Disc S="I",""
Disc SSE="H",""
Disc SE="",""
Disc ESE="F",""
Button Top="X",""
Button Left="Y",""
Button Right="Z",""

The all that’s left is to bung it into a plastic box and gift it to your loving girlfriend…

 

Now, unlike most of my projects, someone actually liked this one enough to do something with it.

https://github.com/drgruney/Intellivision_USB

So head on over to see what they did!