Emulating a GameCube controller joystick with arcade buttons?

Status
Not open for further replies.

Alkamist

Well-known member
Hello everyone!

I have recently decided to build my own GameCube controller for Super Smash Brothers Melee.

I posted a thread about this on a different forum, here is the link if you want to look at it: http://forum.allaboutcircuits.com/threads/using-arcade-buttons-to-replace-an-analog-joystick.128295/

This is a video of the design I am trying to build: https://www.youtube.com/watch?v=UM-NKXS1m2I

Basically, I want to replace a 2 potentiometer joystick with 8 digital arcade buttons (4 cardinal directions, and 4 modifier buttons).

Here is how each potentiometer system would work:

- There are 4 buttons per potentiometer: one triggers full low, one triggers full high, and two are modifiers.
- The modifiers scale the output triggered by the low or high buttons to a configurable percentage from the middle (each modifier has its own percentage).
- The output to the potentiometer goes to the middle value when no buttons are pressed.
- If a either a low or high button is pressed after the other has been held down, the newer button press takes precedence.

I have some questions regarding hardware and software.

In the other thread I posted, I was given two suggestions. One was to output a PWM signal and filter it, and the other was to communicate with a digital potentiometer. I think a digital potentiometer seems like a much better idea. What do you think?

As for the code, I am plotting it out just using USB serial and watching my output there just to get my code right. I figure I can switch it to do whatever output I need later once I have the logic down. I am having some trouble though if anyone can help.

Right now, because of my mediocre knowledge of programming, I am resorting to using a bunch of if statements for the different cases of button combinations I can think of. This seems a bit clunky, is there a better way of doing this? Also, if I do use a digital potentiometer, is there any adverse effect to updating it constantly? Should I only be updating it when I need to or is it not a big deal? If it is a big deal, how can I write a system that only updates it when button changes are detected?

If anyone could give me some advice I would greatly appreciate it! Here is my incomplete code so far for reference:

Code:
void writeToDigitalPot (double inputValue);
int getPotOutput (boolean potLowCurrent,
                  boolean potLowPrevious,
                  boolean potHighCurrent,
                  boolean potHighPrevious);

// Buttons:
const int Left = 0;
const int Right = 1;
const int Down = 2;
const int Up = 3;
const int xMod1 = 4;
const int xMod2 = 5;
const int yMod1 = 6;
const int yMod2 = 7;

boolean LeftPreviousValue = 1;
boolean RightPreviousValue = 1;

void setup()
{
    Serial.begin (9600);

    pinMode (Left, INPUT_PULLUP);
    pinMode (Right, INPUT_PULLUP);
}

void loop()
{
    //---------Left Stick X-Axis----------

    boolean LeftCurrentValue = digitalRead (Left);
    boolean RightCurrentValue = digitalRead (Right);

    int xAxisPotValue = getPotOutput (LeftCurrentValue,
                                      LeftPreviousValue,
                                      RightCurrentValue,
                                      RightPreviousValue);

    writeToDigitalPot (xAxisPotValue);

    LeftPreviousValue = LeftCurrentValue;
    RightPreviousValue = RightCurrentValue;

    //---------Left Stick Y-Axis----------
}

void writeToDigitalPot (int inputValue)
{
    Serial.println (inputValue);
    delay (200);
}

int getPotOutput (boolean potLowCurrent,
                  boolean potLowPrevious,
                  boolean potHighCurrent,
                  boolean potHighPrevious)
{
    int potOutput = 129;

    boolean potLowJustPushed = potLowCurrent == 0
                            && potLowPrevious == 1;
    boolean potLowJustReleased = potLowCurrent == 1
                              && potLowPrevious == 0;

    boolean potHighJustPushed = potHighCurrent == 0
                             && potHighPrevious == 1;
    boolean potHighJustReleased = potHighCurrent == 1
                               && potHighPrevious == 0;

    if (potLowJustPushed)
    {
        potOutput = 0;
    }

    if (potHighJustPushed)
    {
        potOutput = 257;
    }

    if (potLowJustPushed && potHighJustPushed)
    {
        potOutput = 129;
    }

    if (potHighJustReleased && potLowCurrent == 0)
    {
        potOutput = 0;
    }

    if (potLowJustReleased && potHighCurrent == 0)
    {
        potOutput = 257;
    }

    if (potHighJustReleased && potLowCurrent == 1)
    {
        potOutput = 129;
    }

    if (potLowJustReleased && potHighCurrent == 1)
    {
        potOutput = 129;
    }

    if (potLowJustReleased && potHighJustReleased)
    {
        potOutput = 129;
    }

    return potOutput;
}
 
Normal hammer for the if statments is case https://www.arduino.cc/en/Reference/SwitchCase

though you have some more complex logic in yours that mean there really isn't a clever fix. An option that can work when remapping inputs in some way is to have one or more arrays and pull things apart that way. So if mapping button combinations to pot values you could have an array that allows lookup of button combinations to a pot value. The digital pots will cope with a fairly high write rate. If you push them too hard you might get odd results because of the way the produce a result by switching Resistance in and out but you would have to try pretty hard to acheive that, so can probably just update them every pass through the main loop. Do watch out for the limitations with digital pots in terms of needing a shared ground. If you want to trade cost for time you could also build your own by using transistors and resistors, say three for each channel that in combinations between all off and all on got the values you needed. much less elegant than digipots so could indeed cost a lot of time to get working.

Did actually build a system sort of like this at one stage using a bank of 10 resistors to fake the input to a thermostat by toggling pins between output and input to produce and adjustable parallel resistance to ground. Didn't work very well since you don't get 10 to power 2 values, more like 30 useful ones since because of the way parallel resistance works most end values are almost identical.
 
Thank you for the information!

I spent some time today writing the code and I believe I figured out a good way of doing what I need. I have tested my code with serial output, and unless I overlooked something, everything seems to be working. Now I just need to order some digital pots online and modify the code to write to them.

I don't think I'll build my own digital pots because I am a rookie with electronics. I don't think I am quite up to that task yet.

I am planning on using these potentiometers: https://www.sparkfun.com/products/10613
They are 10k, which I am hoping is ok. I haven't tested to see what the resistance of the GameCube joystick potentiometers are; I'm not entirely sure I even know how to do that. If anyone can give me advice, or if you know outright that these 10k pots will work, it would help me a lot.

I am also planning on using Attinys as my microcontrollers. I don't want to use my Teensy in my actual controller, and I would like the microcontrollers to be powered by the GameCube controller board.

It looks like I will need an Attiny84 (for the left stick with modifiers) and an Attiny85 (for the c-stick, since it needs no modifiers). Does this seem like a good plan?

I am also confused if my Teensy 3.2 board can even program the Attiny boards. Can anyone verify if it can? If someone could explain how or point me to that information it would really help.

My last question is: can the Attinys operate these potentiometers? From what I have read they can, I would just like to be sure.

The only reason I ask so many questions is to save money. I could easily order parts and do testing, but I would rather avoid costly mistakes if I can learn from online sources first. If anyone can help, I would greatly appreciate it!

Here is my new code if anyone is interested:

Code:
void writeToDigitalPot (int inputValue);
int getPotValue (int potLowPin, int potHighPin, int &potPressOrder, int inputPotResolution);
int applyPotModifiers (int potFullValue, int mod1Pin, int mod2Pin, int inputPotResolution);

const int masterPotResolution = 257;

// Buttons:
const int lsLeft = 0;
const int lsRight = 1;
const int lsDown = 2;
const int lsUp = 3;
const int xMod1 = 4;
const int xMod2 = 5;
const int yMod1 = 6;
const int yMod2 = 7;
const int cLeft = 8;
const int cRight = 9;
const int cDown = 10;
const int cUp = 11;

//Potentiometer low/high press-order states:
//0 means low was pressed first.
//1 means high was pressed first.
//-1 means neither was pressed first.
int lsXOrder = -1;
int lsYOrder = -1;
int cXOrder = -1;
int cYOrder = -1;

void setup()
{
    Serial.begin (9600);

    pinMode (lsLeft, INPUT_PULLUP);
    pinMode (lsRight, INPUT_PULLUP);
    pinMode (lsDown, INPUT_PULLUP);
    pinMode (lsUp, INPUT_PULLUP);
    pinMode (xMod1, INPUT_PULLUP);
    pinMode (xMod2, INPUT_PULLUP);
    pinMode (yMod1, INPUT_PULLUP);
    pinMode (yMod2, INPUT_PULLUP);
    pinMode (cLeft, INPUT_PULLUP);
    pinMode (cRight, INPUT_PULLUP);
    pinMode (cDown, INPUT_PULLUP);
    pinMode (cUp, INPUT_PULLUP);
}

void loop()
{
    //---------Left Stick X-Axis----------   
    int lsXValue = getPotValue (lsLeft, lsRight, lsXOrder, masterPotResolution);

    lsXValue = applyPotModifiers (lsXValue, xMod1, xMod2, masterPotResolution);

    writeToDigitalPot (lsXValue);

    //---------Left Stick Y-Axis----------    
    int lsYValue = getPotValue (lsDown, lsUp, lsYOrder, masterPotResolution);

    lsYValue = applyPotModifiers (lsYValue, yMod1, yMod2, masterPotResolution);

    writeToDigitalPot (lsYValue);
    
    //----------C-Stick X-Axis------------
    int cXValue = getPotValue (cLeft, cRight, cXOrder, masterPotResolution);

    writeToDigitalPot (cXValue);

    //----------C-Stick Y-Axis------------
    int cYValue = getPotValue (cDown, cUp, cYOrder, masterPotResolution);

    writeToDigitalPot (cYValue);

    //------------------------------------
    delay (200);
}

void writeToDigitalPot (int inputValue)
{
    Serial.println (inputValue);
}

int getPotValue (int potLowPin, int potHighPin, int &potPressOrder, int inputPotResolution)
{ 
    int potMin = 0;
    int potMax = inputPotResolution;
    int potMiddle = ceil (inputPotResolution / 2.0);
    
    boolean lowIsPressed = !digitalRead (potLowPin);
    boolean highIsPressed = !digitalRead (potHighPin);
    boolean lowWasPressedFirst = lowIsPressed && (potPressOrder == 0);
    boolean highWasPressedFirst = highIsPressed && (potPressOrder == 1);

    // Low Cases
    if (lowIsPressed && highWasPressedFirst)
    {
        potPressOrder = 1;
        return potMin;
    }
    if (lowIsPressed && !highIsPressed)
    {
        potPressOrder = 0;
        return potMin;
    }

    // High Cases
    if (lowWasPressedFirst && highIsPressed)
    {
        potPressOrder = 0;
        return potMax;
    }
    if (!lowIsPressed && highIsPressed)
    {
        potPressOrder = 1;
        return potMax;
    }

    // Middle Cases
    if (!lowIsPressed && !highIsPressed)
    {
        potPressOrder = -1;
        return potMiddle;
    }
    if (lowIsPressed && highIsPressed && (potPressOrder == -1))
    {
        potPressOrder = -1;
        return potMiddle;
    }

    return potMiddle;
}

int applyPotModifiers (int potFullValue, int mod1Pin, int mod2Pin, int inputPotResolution)
{
    int potMiddle = ceil (inputPotResolution / 2.0);
  
    double mod1Decimal = 0.40;
    double mod2Decimal = 0.60;
    double combinedModDecimal = 0.80;
    
    boolean mod1IsPressed = !digitalRead (mod1Pin);
    boolean mod2IsPressed = !digitalRead (mod2Pin);

    if (mod1IsPressed && !mod2IsPressed)
    {
        if (potFullValue < potMiddle)
        {
            return potMiddle - potMiddle * mod1Decimal + 0.5;
        }
        if (potFullValue > potMiddle)
        {
            return potMiddle + potMiddle * mod1Decimal + 0.5;
        }
    }
    if (!mod1IsPressed && mod2IsPressed)
    {
        if (potFullValue < potMiddle)
        {
            return potMiddle - potMiddle * mod2Decimal + 0.5;
        }
        if (potFullValue > potMiddle)
        {
            return potMiddle + potMiddle * mod2Decimal + 0.5;
        }
    }
    
    if (mod1IsPressed && mod2IsPressed)
    {
        if (potFullValue < potMiddle)
        {
            return potMiddle - potMiddle * combinedModDecimal + 0.5;
        }
        if (potFullValue > potMiddle)
        {
            return potMiddle + potMiddle * combinedModDecimal + 0.5;
        }
    }

    return potFullValue;
}
 
The Atiny84 can do that, but I've found them tricky to get working and a nightmare to debug and unless you are pretty good at working in a very basic CPU would suggest not using them. Note that the sparkfun digital pots do not come with example code, though there is something linked in the comments, before ordering suggest looking at that and making sure it at least still compiles.

To measure the hardware grab a multimeter and check what range of resistances you get from ground to control pin.

Will question though, where are you planning to plug this in? The game cube controllers use a serial interface as far as I know so if you wanted to make emulate one you would be producing serial data. If you plan to gut an existing controller and wire to it, would be far more robust to skip the micro and just make your buttons connect R values to the controller board.
 
Are you suggesting that I just use the Teensy board? My problem with that is that I want it to be powered by the GameCube board itself. Is there a way to do that without using the USB slot?

I am planning on using an existing controller board. When I posted on allaboutcircuits.com, my original plan was to not use a microcontroller, but I was informed by posters there that I needed to use one. Could you explain how I would get by without one? And even if I could, certainly it wouldn't follow the complex logic in my program to have newer inputs take precedence. Buttons pushed at the same time would cause problems wouldn't they?
 
If the Google controller pinout is right there is 3.3V and 5V going to the existing controler board. You can solder that to either the 5V vin or the 3.3V pin to power a Teensy3. Side not on Teensy power:

Teensy3.x/lc use a 3.3V chip so the 5V USB is regulated via an onboard regulator down to 3.3V, however the power setup works fine if you just supply 3.3V and leave the 5V alone if that's how things work best, but of course you don't magically get 5V out of the Vin pin or anything.

In this case would tend to steal the 5V run it to the Vin pin and gnd to gnd and know that I had both voltages for whatever I needed. The USB cable just happens to be a convient source of 5V no different to any other. If you do this, do note that you shouldn't have USB connected while also powering things from the game cube. Simple solution is to not plug in both at once, more complex solution is to look at the reference card and flip the Teensy over and cut the little trace that connects USB to Vin
https://www.pjrc.com/teensy/external_power.html (not picture shows an older Teensy, but power pad position is the same)

Going back to your original project I'd be looking at something like
https://github.com/NicoHood/Nintendo
And throw the whole idea of trying to have both the Nintendo PCB and my own hardware Frankensteined together. Or I'd keep the PCB and it's electronics and just wire two chains of resistors (one for each axis) and short them with my direction buttons and have it all done with no CPU involved. Getting the 'fine control' button to work in this mode would be a bit tricky but doable with the right buttons (normally closed contacts).
 
Unfortunately I don't have nearly enough experience with electronics to work out a system without a microcontroller. Unless someone is willing to provide instructions on exactly how to do it, I am going to have to go the microcontroller route.

That gamecube controller library is interesting. I'll have to do some research and testing and see if I can get it working. It would be nice to not have to use a GameCube controller board at all. Thank you for the help so far!
 
After some experimentation today, I can't seem to get that GameCube controller library to compile. It needs to use a 16 MHz speed to work, and when you set the Teensy to 16 MHz, it throws tons of strange errors like not knowing what bools are. If you set the IDE to use Arduino Uno, it will compile properly.

Unfortunately, I don't have an Arduino Uno, and even if I did, it doesn't have enough pins for me to use. I need to connect 22 individual buttons. Unless I can figure something out, it looks like I am going to have to go with the Frankenstein option.
 
It's your project, but would suggest that the Nicohood library plus:
http://playground.arduino.cc/Code/Keypad
Running on a uno or clone would be the easiest way to get something you can get out and rumble with.

Looking at https://github.com/NicoHood/Nintendo/blob/master/src/Gamecube_N64.c I can see why it's locked to 16mhz and Atmega since it's doing NOPs to get mark/space right so not easy to make it portable to any other CPU or speed, sorry for sending you down that path since had assumed it would be using 'delay()'.

With that out of the way would still suggest a good starting point is building a hard wired D-pad. Gives you a chance to try buttons and physical build (shop around for buttons since some are pretty rubbish).

Idea is to change the pot https://en.wikipedia.org/wiki/Potentiometer
to a restive divider https://en.wikipedia.org/wiki/Voltage_divider#Resistive_divider_2
with four elements in it, two of which can be shorted by buttons (and whole setup duplicated for the other axis)
Code:
+v for original axis--R1=300ohms----r2=2.5k-----r3=2.5k----r4=300ohm--gnd
                                  |          |           |
                                  --buton1-----button2---
                                             |
                               Original stick axis wire
So in normal state with both bottons unpressed you get mid range voltage on the axis sense wire. If you press one button you bypass that resistor and shift the axis sensed voltage in that direction. R1+R2+R3+R4 should add up to roughly the total range of the original pot, which needs to be removed from circuit (so don't use a good controller for this).

R1 and R4 are there to deal with the case of both buttons being pressed, which would short things and generally be bad with just two buttons, and will mean you can't get full travel out of the buttons wired like this (one problem with this setup) which may or may not matter depending on how the game was setup. Also means you don't get your modifier button. For that you'd need a arcade botton that has normally closed contacts, which a quick survey of my bits box suggests is present on about half of them, but generally the more expensive ones. If you head down this route and basic config works will show how to add them.

Anyway doing things this way costs you 8 resistors over what you already need, will be just as fast as the original controller (Digi pots will add a delay) and can be knocked up and either proven or disproven quickly and generally get you back to the game. And once you have all the hardware built, grafting a micro of your choice in later is perfectly possible to add the final polish to the project.

Don't want to turn you off the micro controller route, but this would be a big and complex project and you don't seem to have the budget to afford mistakes, nor the time to learn how to not make them and would like to see you have something that is almost good enough in a couple of hours that can be improved and expanded upon later rather than spending a fair bit of money to get a lot of frustration.

What your Teensy will work well for is if you want to make two copies of your button setup, since it can be a USB keyboard/and or joystick (see file-examples-teensy-usbkeyboard) and give you a PC or Xbox button controller.
 
Last edited:
Thanks for the informative response!

I can see how that system of resistors would work. I think I can get away with not having the full range of motion on the potentiometers. At the very least I can use that for the C-stick since I don't need modifiers for it. I would actually prefer going this route, but I don't really know how to get the modifiers in there. I have some trimpots that I bought that I could use for them so I can fine tune them. That is important because I don't know the exact percentages I need yet.

These are the buttons I am using: https://www.focusattack.com/sanwa-obsf-24mm-pushbutton-white/
They are the same buttons that are used on the controller I am basing my design off of.

Would the digital pots really add a noticeable delay?
 
I think I have come up with something that might work. If you go to http://www.falstad.com/circuit/circuitjs.html you can import the following text.

Code:
$ 1 0.000005 19.867427341514983 61 5 43
r 768 352 864 352 0 5000
r 896 352 992 352 0 5000
r 672 384 768 384 0 300
r 992 384 1088 384 0 300
s 768 464 880 464 0 1 false
s 880 464 992 464 0 1 false
w 768 384 768 464 0
w 992 384 992 464 0
R 672 384 640 384 0 0 40 5 0 0 0.5
g 1088 384 1104 384 0
r 768 304 880 304 0 700
w 768 304 768 352 0
w 768 352 768 384 0
w 992 304 992 352 0
w 992 352 992 384 0
w 864 384 864 352 0
w 896 384 896 352 0
w 880 416 880 464 0
w 864 384 880 416 0
w 896 384 880 416 0
s 880 304 992 304 0 1 false
s 880 256 992 256 0 1 false
r 768 256 880 256 0 2000
w 768 304 768 256 0
w 992 256 992 304 0

Does this seem plausible?
 
I'm not quite clear on what the circuit is trying to do, other than being a nice demo for inductive resonance. A workable solution without NC switches but using a micro controller is:
JoystickEmulation.png
Idea is that rather than using the power and ground connections on the PCB we use pins that are either on, or disabled rather than the normal on/off states.

There are a lot of different ways to do this using variably complex code and numbers of pins but this was the first that I came up with.

R5 and micro controller pin LSP2 is there to provide the modifiers and is normally left disabled and not impacting the circuit.

So conditions are:
No buttons pressed - LSP1 output - high and LSP3 output LOW -LSP2 input/highz- to_GC is half way between them
direction 1 button pressed - LSP1 Input/high z - LSP3 output LOW - to_GC is pulled low
direction 2 button pressed - LSP1 output HIGH - LSP3 input/high z - to_GC is pulled high
direction 1 button pressed+mode - LSP1 output - high and LSP3 output LOW - LSP2 pulled low - to_GC is pulled lower than mid range but not all the way
direction 2 button pressed+mode - LSP1 output - high and LSP3 output LOW - LSP2 pulled high - to_GC is pulled higher than mid range but not all the way to +ve

Key thing is that the micro controller output voltages MUST be the same as the ones applied to the pots so first step is to confirm they really are 3.3v.

A simpler option codeing wise but less flexible would be to use the circuit in the previous post, but have two resistors on each switch and two micro controller pins tapped there and a single input from the mod button, allowing the micro to adjust the bias based on the mod button state, but removing sensing of the direction buttons if you wanted to get clever with those.

Edit - the minimal option using three micro pins would work well if you do want to go the Atiny route, the circuit above would be better suited to a Teensy since it would be perfectly possible to have code running that turned it into a USB gamepad as well.
 
Last edited:
At the link I sent you you have to import the text that I pasted. The inductor circuit you saw is just there by default.

I added some labels to my circuit. It is the circuit you posted before but I added resistors in parallel that are activated by the modifier buttons. At the upper left corner of the screen on this page http://www.falstad.com/circuit/circuitjs.html go to file and "import from text", paste in the following:

Code:
$ 1 0.000005 19.867427341514983 61 5 43
r 768 352 864 352 0 5000
r 896 352 992 352 0 5000
r 672 384 768 384 0 300
r 992 384 1088 384 0 300
s 768 464 880 464 0 1 false
s 880 464 992 464 0 1 false
w 768 384 768 464 0
w 992 384 992 464 0
R 672 384 640 384 0 0 40 5 0 0 0.5
g 1088 384 1104 384 0
r 768 304 880 304 0 700
w 768 304 768 352 0
w 768 352 768 384 0
w 992 304 992 352 0
w 992 352 992 384 0
w 864 384 864 352 0
w 896 384 896 352 0
w 880 416 880 464 0
w 864 384 880 416 0
w 896 384 880 416 0
s 880 304 992 304 0 1 false
s 880 256 992 256 0 1 false
r 768 256 880 256 0 2000
w 768 304 768 256 0
w 992 256 992 304 0
w 880 512 880 464 0
x 848 538 916 541 0 24 To GC
x 906 282 964 285 0 24 Mods

I'm afraid your suggestion might be going over my head. I'm not entirely sure what LSP means. Are those digital i/o pins on the Teensy?

This is how I am interpreting what you are saying:
- Run my buttons like the left part of your picture shows to separate digital pins.
- Process with microcontroller code.
- Use different digital out pins in series with resistors connected to where the wiper inputs for each axis on the GC controller.

Is this what you are saying? Sorry if these are novice questions, trying my best to keep up!
 
That's pretty much what I was looking at. Key trick is that pins can be used as more than basic inputs or outputs. By wiring as above you can manipulate the three control pins to be either high, low or not allowing any current (high z, where z is impedance which is a fancy word for resistance), giving a range of options.

Your circuit will work with a bit of tweaking, but uses the modifiers different to how I thought you had intended. Was the plan that the modifer was like a shift key that you held while pressing another button, or is the plan to have two mod buttons per axis, where you press either 'full force up' or 'half(ish) force' up?
If the plan is to have big push and little push buttons this should work:
$ 1 0.000005 19.867427341514983 61 5 43
r 432 352 528 352 0 2500
r 752 352 848 352 0 2500
r 336 384 432 384 0 300
r 848 384 944 384 0 300
s 528 400 640 400 0 1 false
s 736 400 848 400 0 1 false
w 432 384 432 400 0
R 336 384 304 384 0 0 40 5 0 0 0.5
g 944 384 960 384 0
r 528 352 640 352 0 2500
w 528 304 528 352 0
w 432 352 432 384 0
w 848 352 848 384 0
w 640 352 640 400 0
w 640 400 640 544 0
w 736 400 640 400 0
s 528 304 640 304 0 1 false
s 640 304 752 304 0 1 false
r 640 352 752 352 0 2500
w 640 352 640 304 0
w 752 304 752 352 0
w 528 400 432 400 0
w 848 400 848 384 0

Much the same as your layout but keeps the normal total resistance values higher. To make it adjustable just replace the pairs of 2.5k with a 5k pot with the switch wired between the wiper and one end. This means you can adjust the mod button effect over the full range.
 
The way I wanted it to work is like this (just consider one axis, we'll say the X axis):

- If you push left, it goes 100% to the left.
- If you push right, it goes 100% to the right.
- The modifier keys don't do anything unless a directional button is held.
- The modifier keys simply scale the direction you press more toward the center.

I think my circuit accomplishes this. And yeah I was planning on putting a pot in place of the modifier resistors.

You said that it would work with a bit of tweaking? What kind of tweaking would I need to do?


And about using the microcontroller, so the pins can be in 3 states? How do I set a pin to high z?
 
https://www.arduino.cc/en/Reference/pinMode

So things would look something like
Code:
if (digitalRead(upPin)==0) //using internal pullups so zero equals button pushed
{
   if (digitalRead(upModPin)==0) {
     pinMode(upPosPin,OUTPUT);
     digitalWrite(upPosPin,HIGH);
     pinMode(upNegPin,INPUT);
    // digitalWrite(upNegPin,LOW);     commented out since on a non teensy this will screw up pinmode.
     pinMode(upModPin,OUTPUT);
     digitalWrite(upPosPin,HIGH);
    } else  
    {
     pinMode(upPosPin,OUTPUT);
     digitalWrite(upPosPin,HIGH);
     pinMode(upNegPin,INPUT);
    // digitalWrite(upNegPin,HIGH);     
     pinMode(upModPin,INPUT);
   //  digitalWrite(upPosPin,HIGH);

    }
}
With another 3 copies for the down and left/right pins. Using code you can have a single mod button for all axis, 2 or four depending on how you want to use it.

Looking at the hardware solution

If you look at the output voltage (mouse over) as you try various combinations in your circuit while you will find that while the mod keys don't change the 'no movement buttons down' voltage they do change the voltage if you press mod+the wrong direction. If you had NC buttons what you want would be easy to do but with NO buttons and staying away from transistor logic to get your mapping will need the micro controller. My design will mean the mod keys will make you move as soon as they are pressed, with the normal move button over-ridding them.
 
I think you might be misunderstanding the modifier system still. That or I am misunderstanding something.

I'll try to explain it better, lets consider the X axis again:

- There are two modifier buttons that work for both directions.
- The modifiers have different percentages.
- So lets say modifier 1 is 40%, and modifier 2 is 60%.
- If I hold left with no mods, it is 100% to the left.
- Now I push mod 1, it jumps to 40% to the left.
- If I push right and let go of left, but still hold down mod 1, it goes to 40% to the right.
- Mod 2 does the same thing, but just with 60%.

So there is no "wrong" direction, the mods just apply to the axis itself, not a specific direction. As far as I can tell, the circuit I made follows these rules.
 
With you on your modifier setup now, and yes that gets tricky to do without a micro since applying the modifiers would start involving some fun transistor logic and also why I was initially considering micro plus two digital pots rather overkill.

Adding two levels of modifier to the micro controller driven setup is easiest done using a second mod pin with a different resistor value. I'm sure there is a clever way to achieve the needed mix of outputs without needing four output pins per axis but not seeing it at the moment.
 
Well I will order a package of resistors that has a lot of different kinds. That way I can test out my circuit. I'll probably end up needing the resistors anyway and it isn't very expensive.

If I can't get my circuit to work, I'll have to try your suggestion. I still don't quite understand it, but it will probably just take some time. I am learning as I go along.
 
Finally got around to removing the left thumbstick from the GC controller board. I verified today that my circuit works as I expected. My plan now is to get some perf board so I can implement 4 of these circuits in a more permanent and clean fashion.

If anyone has any tips or suggestions for me I would definitely welcome them! I am looking to implement this circuit as cleanly and easily as possible.

Here is my newest circuit for reference (go to http://www.falstad.com/circuit/circuitjs.html and import the following text in the file menu):

Code:
$ 1 0.000005 19.867427341514983 61 5 43
r 752 400 864 400 0 5000
r 864 400 976 400 0 5000
r 624 352 720 352 0 300
r 1008 352 1104 352 0 300
s 752 368 864 368 0 1 false
s 864 368 976 368 0 1 false
R 1104 352 1136 352 0 0 40 5 0 0 0.5
g 624 352 608 352 0
r 864 336 976 336 0 700
s 752 336 864 336 0 1 false
s 752 304 864 304 0 1 false
r 864 304 976 304 0 2000
w 752 304 720 352 0
w 752 336 720 352 0
w 752 368 720 352 0
w 720 352 752 400 0
w 1008 352 976 400 0
w 1008 352 976 368 0
w 1008 352 976 336 0
w 1008 352 976 304 0
w 864 368 864 400 0
w 864 432 864 400 0
x 807 272 1091 275 0 24 Modifiers (can be trimpots)
x 780 466 990 469 0 24 To controller (wiper)

Also, thank you GremlinWrangler. You were a very big help to me!
 
Glad to hear it's working. Perf board is a reasonable choice for this. Main things are to make sure that you can pull things apart again, since Murphy will mean that you need to do it at least once so either make the wires long enough or use plugs to allow unfolding things. Don't stint on space either since while you can fold it all up small makes errors more likely. Basic idea is to have four clearly identical setups on the board that are easy to layout and wire and with separation so any solder mistakes don't matter.

Any join that is just solder think about strain relief since this build will cop a beating so try to leave slack in wires, make sure everything is glued or bolted in place. And work out how to protect the cable coming out the back of the thing so it doesn't tear out. Classic solution is to knot the cable, but this should have the original controller strain relief so if possible clamp that so it's still doing it's job to protect against bends and pulls.
 
Thanks for the tips!

I have another question: in my circuit that I posted, there are those 300 ohm resistors on both sides. I know this prevents a short when both direction buttons are pressed, but how low do you think I can go on those without adversely affecting the GC PCB?
 
Good question

Assuming it's 3.3V logic the all buttons pressed fault current is 2 * 3.3/(300+300)=11 ma which isn't going to excite much, but is close to the limit a micro controller can drive if it's what is up stream. Probably not the case but a worst case assumption.

Redoing the math for 50 mA would PROBABLY be ok (60 ohms) but depends if there are any components in the line that are current sensitive (probably not, but who knows). Going past 100mA starts to risk thin wire, and 500mA is the limit for a USB powered device so would expected the gamecube to start having trouble around then as well.

Short answer is the board would have been designed for a nearly constant current through the original pot. If the design is basic and given you don't have rumble or other peripherals running then there should be plenty of head room but if somebody got clever and is using components for multiple purposes then all bets are off.

Methods are to either use a meter to check for any components between the original pot and the power/ground connections or give it a go and see if anything goes pop. If you have a multimeter also check if the 3.3v supply droops at all during your test. This will start to upset the controller IC, but may also start to break things inside the host console as well which is not something you want.
 
Thanks for the advice.

When I checked my circuit originally it seemed to all work properly, but I didn't test anything like pushing additional buttons. I'll have to do some further tests when I get my protoboards in place. Right now it is a pain because there are tons of loose wires and nothing is held in place; I don't have enough hands to test it all.

If it is potentially dangerous for a console, it wouldn't hurt my computer would it? Right now I am doing testing through a GameCube to USB adapter, which is powered by the USB.
 
It certainly can, but shouldn't.

What should happen if you draw to much power is that the USB port will report the fault and shut down. If that process fails though then you end up with things going pop. Have a dead USB port due a wiring mishap but I guess even there at least it didn't damage the whole mother board so the protective components did what they needed to and act as a reminder to be more carful.

As soon as you have bare wires around anything, you are trusting an unknown designer to have accepted increased cost and reduced performance to deal with a very rare event. This is in fact why I suggested those resistors in the first place, to add a layer of safety against something that in theory will never happen (both buttons pushed) but seemed possible and the consequences severe enough to complicate the design with them.
 
Status
Not open for further replies.
Back
Top