[WIP] fdeluxes Game Boy Zero

Show off your completed Game Boy Zero, or post your build logs here!
User avatar
fdeluxe
Posts: 71
Joined: Tue Aug 23, 2016 10:16 am
Has thanked: 12 times
Been thanked: 27 times
Contact:

[WIP] fdeluxes Game Boy Zero

Post by fdeluxe » Mon Nov 07, 2016 2:11 pm

Hi,

I've reached a state where I am very eager to present you my Game Boy Zero build! It comes with some gimmicks, like a customizable RGB LED behind the speaker grill :D The color can be changed by simultaneously pressing the small mode button in the upper left and the A/X/Y button. The color is saved to the teensys EPROM and is preserved even though the system is shut off. The teensy also features a Keyboard/Mouse-Mode for games like Quake 3 Arena and retroarch-configuration and a simple Gamepad-Mode.

Right now I am handling volume control via software. I hooked up the potentiometer to the teensy and assigned volume-hotkeys to its values using triggerhappy. Unfortunately the deamon crashes very often and I have to use the ingame menu to control the volume :( I gonna change my wiring in the future to directly control the volume through the potentiometer.

I also want to ditch USB Audio in the future and go for PWM. I simply cannot stand that my splashscreen video has no sound :D

Splashscreen video (link in description): https://www.youtube.com/watch?v=-7M2h-G ... e=youtu.be
Teensy Code (sorry for the german documentation): http://pastebin.com/F7ybmifS

Code: Select all

/* Teensy mit zwei Modi: Gamepad mit Analogstick und Tastatur mit Maus (PC Modus)
 *  
 *  Standardmäßig ist der Gamepad-Modus aktiviert.
 *  Durch die Tastenkombination: Mode-Button+Select lässt sich zwischen den Modi wechseln
 *  Im PC-Modus wird der Analogstick als Maus erkannt und die normalen Knöpfe werden als Buchstaben ausgegeben. R1 und R2 fungieren als Maustasten.
 *  Weitere Kombos:
 *  Mode+DPAD_UP = Pfeiltaste Hoch
 *  Mode+DPAD_DOWN = Pfeiltaste Runter
 *  Mode+DPAD_LEFT = Pfeiltaste Links
 *  Mode+DPAD_RIGHT = Pfeiltaste Rechts
 *  Mode+B = Enter
 *  Mode+START = Escape
 *  Mode+A/X/Y = Farbwert erhöhen (maximal auf 10, dann springt er wieder auf 0)
*/
#include <Bounce.h>
#include <EEPROM.h>
#define NUM_KEYS 15
#define COMMON_ANODE

struct Key {
    char keycode;
    Bounce * bounce;
};

Key keys[NUM_KEYS];
char volumeLVLs[21];
Key key(char keycode, int pin) {
    Key * ret = new Key;
    ret->keycode = keycode;
    ret->bounce = new Bounce(pin, 10);
    pinMode(pin, INPUT_PULLUP);
    return *ret;
}

//Keyboard-Tastenbelegung
void setupKeys() {
    keys[0] = key('a', 0);
    keys[1] = key('w', 1);
    keys[2] = key('s', 2);
    keys[3] = key('d', 3);
    keys[4] = key('m', 4);
    keys[5] = key('n', 5);
    keys[6] = key('b', 6);
    keys[7] = key('v', 7);
    keys[8] = key('y', 8);
    keys[9] = key('x', 9);
    keys[10] = key('q', 10);
    keys[11] = key('e', 11);
    keys[12] = key('u', 12);
    keys[13] = key('l', 13);
    keys[14] = key('k', 14);
}
// Pseudo-Tasten zur Lautstärkeregelung über triggerhappy. Jedem Potentiometer Wert wird ein Button zugeordnet (temporäre Lösung)
void setupVolumeKeys() {
    volumeLVLs[20] = KEY_MINUS;         // 0%
    volumeLVLs[19] = KEY_EQUAL;         // 5%
    volumeLVLs[18] = KEY_LEFT_BRACE;    // 10%
    volumeLVLs[17] = KEY_RIGHT_BRACE;   // 15%
    volumeLVLs[16] = KEY_BACKSLASH;     // 20%
    volumeLVLs[15] = KEY_SEMICOLON;     // 25%
    volumeLVLs[14] = KEY_QUOTE;         // 30%
    volumeLVLs[13] = KEY_TILDE;         // 35%
    volumeLVLs[12] = KEY_COMMA;         // 40%
    volumeLVLs[11] = KEY_PERIOD;        // 45%
    volumeLVLs[10] = KEY_SLASH;         // 50%
    volumeLVLs[9] = KEY_CAPS_LOCK;      // 55%
    volumeLVLs[8] = KEY_END;            // 60%
    volumeLVLs[7] = KEY_INSERT;         // 65%
    volumeLVLs[6] = KEY_V;              // 70%
    volumeLVLs[5] = KEY_T;              // 75%
    volumeLVLs[4] = KEY_P;              // 80%
    volumeLVLs[3] = KEY_SCROLL_LOCK;    // 85%
    volumeLVLs[2] = KEY_PRINTSCREEN;    // 90%
    volumeLVLs[1] = KEY_PAUSE;          // 95%
    volumeLVLs[0] = KEY_I;              // 100%
}

//RGB LED-Pins
int redPin = 16;
int greenPin = 17;
int bluePin = 20;

//Change LED Color
void setColor(int red, int green, int blue) {
    #ifdef COMMON_ANODE
    red = 255 - red;
    green = 255 - green;
    blue = 255 - blue;
    #endif
    analogWrite(redPin, red);
    analogWrite(greenPin, green);
    analogWrite(bluePin, blue);
}

//Mode-Button Kombo-Buttons
Bounce modeButton = Bounce(15, 10);
Bounce upButton = Bounce(1, 10);
Bounce downButton = Bounce(2, 10);
Bounce leftButton = Bounce(0, 10);
Bounce rightButton = Bounce(3, 10);
Bounce selectButton = Bounce(4, 10);
Bounce startButton = Bounce(5, 10);
Bounce xButton = Bounce(9, 10);
Bounce yButton = Bounce(8, 10);
Bounce aButton = Bounce(7, 10);
Bounce bButton = Bounce(6, 10);

boolean pcMode = false;
boolean modeButtonPressed = false;
boolean colorChanged = false; // Only write to EPROM if color has changed
const int numButtons = 16; // 16 for Teensy, 32 for Teensy++

void setup() {

    //Debug-Nachrichten über Serial.println("Nachricht") verschicken
    Serial.begin(9600);

    //Setup the LED-Pins
    pinMode(redPin, OUTPUT);
    pinMode(greenPin, OUTPUT);
    pinMode(bluePin, OUTPUT);

    setupKeys();
    setupVolumeKeys();
    pinMode(15, INPUT_PULLUP);
    pinMode(16, INPUT_PULLUP);
    Joystick.useManualSend(true);

    for (int i = 0; i < numButtons; i++) {
        pinMode(i, INPUT_PULLUP);
    }
}

byte allButtons[numButtons];
byte prevButtons[numButtons];
int mapX;
int mapY;
int deadzone = 60;
int volumeLVL;
int deltaVolume = 0;
int volumeKey = 0;
float volumeRel = 0;
int red = EEPROM.read(0);
int green = EEPROM.read(1);
int blue = EEPROM.read(2);

void loop() {

    //Read potentiometer for volumecontrol
    volumeLVL = analogRead(21);

    if (volumeLVL < 4) volumeLVL = 0;
    if (volumeLVL > 1019) volumeLVL = 1023;

    //Convert Potentiometer value to array index
    volumeRel = 0.0195503421309873 * volumeLVL;
    deltaVolume = volumeKey - (int) volumeRel;
    volumeKey = (int) volumeRel;

    //Check if potentiometer value has changed
    if (deltaVolume != 0) {
        Serial.print("Volume = ");
        Serial.print(volumeKey * 5);
        Serial.println(" %");
        Keyboard.set_key1(volumeLVLs[volumeKey]);
        Keyboard.send_now(); // send the button press
        Keyboard.set_key1(0);
        Keyboard.send_now(); // send the button release
    }

    //Update button status
    modeButton.update();
    upButton.update();
    downButton.update();
    leftButton.update();
    rightButton.update();
    selectButton.update();
    startButton.update();
    aButton.update();
    bButton.update();
    xButton.update();
    yButton.update();

    //Check if mode-button is pressed
    if (modeButton.fallingEdge()) modeButtonPressed = true;
    if (modeButton.risingEdge()) modeButtonPressed = false;

    if (modeButtonPressed && selectButton.fallingEdge()) { //Switch Mode
        Serial.println("Mode changed");
        pcMode = !pcMode;
    }
    if (modeButtonPressed && startButton.fallingEdge()) { //Escape Key
        Serial.println("Escape");
        Keyboard.set_key1(KEY_ESC);
        Keyboard.send_now(); // send the button press
        Keyboard.set_key1(0);
        Keyboard.send_now(); // send the button release
    }
    if (modeButtonPressed && bButton.fallingEdge()) { //Enter
        Serial.println("Enter");
        Keyboard.set_key1(KEY_ENTER);
        Keyboard.send_now(); // send the button press
        Keyboard.set_key1(0);
        Keyboard.send_now(); // send the button release
    }
    if (modeButtonPressed && upButton.fallingEdge()) { //Up
        Serial.println("up");
        Keyboard.set_key1(KEY_UP);
        Keyboard.send_now(); // send the button press
        Keyboard.set_key1(0);
        Keyboard.send_now(); // send the button release
    }
    if (modeButtonPressed && downButton.fallingEdge()) { //Down
        Serial.println("down");
        Keyboard.set_key1(KEY_DOWN);
        Keyboard.send_now(); // send the button press
        Keyboard.set_key1(0);
        Keyboard.send_now(); // send the button release
    }
    if (modeButtonPressed && leftButton.fallingEdge()) { //Left
        Serial.println("left");
        Keyboard.set_key1(KEY_LEFT);
        Keyboard.send_now(); // send the button press
        Keyboard.set_key1(0);
        Keyboard.send_now(); // send the button release
    }
    if (modeButtonPressed && leftButton.fallingEdge()) { //Right
        Serial.println("right");
        Keyboard.set_key1(KEY_RIGHT);
        Keyboard.send_now(); // send the button press
        Keyboard.set_key1(0);
        Keyboard.send_now(); // send the button release
    }
    if (modeButtonPressed && xButton.fallingEdge()) { //Red
        Serial.println("Red changed");
        red += 25;
        if (red > 255) red = 0;
        colorChanged = true;
    }
    if (modeButtonPressed && yButton.fallingEdge()) { //Green
        Serial.println("Green changed");
        green += 25;
        if (green > 255) green = 0;
        colorChanged = true;
    }
    if (modeButtonPressed && aButton.fallingEdge()) { //Blue
        Serial.println("Blue chganged");
        blue += 25;
        if (blue > 255) blue = 0;
        colorChanged = true;
    }

    //write RGB-values to EPROM
    if (colorChanged) {
        colorChanged = false;
        EEPROM.write(0, red);
        EEPROM.write(1, green);
        EEPROM.write(2, blue);
    }

    setColor(red, green, blue);


    // Analog Stick Kalibrierung
    // Zu faul meine Kommentare wieder einzudeutschen... :)

    //Remap the data range
    mapX = map(analogRead(23), 185, 839, 0, 1023); 
    mapY = map(analogRead(22), 125, 830, 0, 1023); 

    //Deadzones
    if (mapX < 512 + deadzone && mapX > 512 - deadzone) mapX = 512;
    if (mapY < 512 + deadzone && mapY > 512 - deadzone) mapY = 512;
    if (mapX < 24) mapX = 0;
    if (mapY < 24) mapY = 0;

/*
    //Non-linear correction
        mapX=(int)(0.00000302*mapX*mapX*mapX-0.004631*mapX*mapX+2.577*mapX+1.23);
      if(mapX>1023) mapX=1023;
      if(mapX<0) mapX=0;
      
      mapY=(int)(0.00000302*mapY*mapY*mapY-0.004631*mapY*mapY+2.577*mapY+1.23);
      if(mapY>1023) mapY=1023;
      if(mapY<0) mapY=0;
*/


    //Send final values
    Joystick.X(mapX);
    Joystick.Y(mapY);

    // PC mode
    //Analogstick as mouse
    if (pcMode == true) {
        float X = (float) mapX;
        float Y = (float) mapY;
        float dX = 6 * ((X - 512) / 512); //scale the mousespeed by 6.
        float dY = 6 * ((Y - 512) / 512);
        Mouse.move(dX, dY, 0);

        for (int i = 0; i < NUM_KEYS; i++) {
            keys[i].bounce->update();

            if (keys[i].bounce->fallingEdge()) {
                if (i == 13) Mouse.press(MOUSE_RIGHT);
                else if (i == 14) Mouse.press(MOUSE_LEFT);
                else Keyboard.press(keys[i].keycode);
            } else if (keys[i].bounce-> risingEdge()) {
                if (i == 13) Mouse.release(MOUSE_RIGHT);
                else if (i == 14) Mouse.release(MOUSE_LEFT);
                else Keyboard.release(keys[i].keycode);
            }
        }
    }

    // Gamepad mode
    else {
        // read digital pins and use them for the buttons
        for (int i = 0; i < numButtons; i++) {
            if (digitalRead(i)) {
                // when a pin reads high, the button is not pressed
                // the pullup resistor creates the "on" signal
                allButtons[i] = 0;
            } else {
                // when a pin reads low, the button is connecting to ground.
                allButtons[i] = 1;
            }
            Joystick.button(i + 1, allButtons[i]);
        }
        Joystick.send_now();
    }
}
Here's my parts list: Special thanks to
[mention]wermy[/mention] for inspiring me and your awesome guides!
[mention]dominator[/mention] for that kick-ass screen surround!
[mention]prerunnerseth[/mention] for the button PCB!

[spoiler="Front"]Image
Image[/spoiler]
[spoiler="Back"]Image[/spoiler]
[spoiler="Side"]Image
Image[/spoiler]
[spoiler="RGB LED"]Image
Image
Image
Image
Image
Image
Image[/spoiler]

User avatar
wermy
Site Admin
Posts: 1346
Joined: Tue May 03, 2016 8:51 pm
Has thanked: 619 times
Been thanked: 1320 times
Contact:

Re: [WIP] fdeluxes Game Boy Zero

Post by wermy » Mon Nov 07, 2016 2:47 pm

Looks great! Love the RGB LED. :D
ImageImageImageImage

alexln
Posts: 20
Joined: Sat Sep 17, 2016 12:46 pm
Has thanked: 4 times
Been thanked: 3 times

Re: [WIP] fdeluxes Game Boy Zero

Post by alexln » Mon Nov 07, 2016 3:07 pm

This is a really cool clean build. Nice job!
Check out my sales thread. Two partly assembled GBZ
http://www.sudomod.com/forum/viewtopic.php?f=38&t=3866

User avatar
AustenFM
Posts: 55
Joined: Thu Jul 28, 2016 5:55 pm
Location: Houston, TX
Has thanked: 52 times
Been thanked: 20 times
Contact:

Re: [WIP] fdeluxes Game Boy Zero

Post by AustenFM » Mon Nov 07, 2016 8:27 pm

Looks great, awesome clean build!!

Love the L & R buttons~ I'm curious if you managed to keep the working cartridge reader with that snes L & R button setup?

Lpoolm
Posts: 392
Joined: Thu Jun 09, 2016 4:17 am
Location: uk
Has thanked: 76 times
Been thanked: 51 times

Re: [WIP] fdeluxes Game Boy Zero

Post by Lpoolm » Tue Nov 08, 2016 12:21 am

I like that splash screen!
Check out my modding and repair channel of retro and modern consoles:
https://www.youtube.com/channel/UCFz7yW ... GtQ/videos

User avatar
fdeluxe
Posts: 71
Joined: Tue Aug 23, 2016 10:16 am
Has thanked: 12 times
Been thanked: 27 times
Contact:

Re: [WIP] fdeluxes Game Boy Zero

Post by fdeluxe » Tue Nov 08, 2016 6:48 am

AustenFM wrote:Looks great, awesome clean build!!

Love the L & R buttons~ I'm curious if you managed to keep the working cartridge reader with that snes L & R button setup?
Unfortunatly not. I did a first build where I put the LR buttons a little deeper and could keep the cartridge reader. But I ditched this for ergonomic reasons. In the end the cartridge reader is just for nostalgia anyways :D

If you also want to use the SNES L&R buttons I would suggest that you put them like 1.00 - 1.50 cm higher than I did. In their current position I am still struggeling to find a comfortable way to press them.

Apis
Posts: 68
Joined: Mon Oct 31, 2016 11:44 am
Has thanked: 35 times
Been thanked: 33 times

Re: [WIP] fdeluxes Game Boy Zero

Post by Apis » Tue Nov 08, 2016 9:29 am

Looks like you didn't have to use the "vertical aligned buttons" like the Kite's build did to use the 3DS analog stick. Can I see the inside of your build to see how the psp stick is mounted?

Also, does anyone know if the Kite build will accept the psp analog stick? I can't ask in the Kite thread because it's locked.

User avatar
CaptainDurden
Posts: 133
Joined: Wed Sep 07, 2016 1:24 pm
Has thanked: 70 times
Been thanked: 48 times

Re: [WIP] fdeluxes Game Boy Zero

Post by CaptainDurden » Tue Nov 08, 2016 9:43 am

Apis wrote: Also, does anyone know if the Kite build will accept the psp analog stick? I can't ask in the Kite thread because it's locked.
I don't see why it couldn't.
Helder wrote:People spend so much time in asking questions and no time looking for an answer that is available.

User avatar
AustenFM
Posts: 55
Joined: Thu Jul 28, 2016 5:55 pm
Location: Houston, TX
Has thanked: 52 times
Been thanked: 20 times
Contact:

Re: [WIP] fdeluxes Game Boy Zero

Post by AustenFM » Tue Nov 08, 2016 10:02 am

fdeluxe wrote:
Unfortunatly not. I did a first build where I put the LR buttons a little deeper and could keep the cartridge reader. But I ditched this for ergonomic reasons. In the end the cartridge reader is just for nostalgia anyways :D

If you also want to use the SNES L&R buttons I would suggest that you put them like 1.00 - 1.50 cm higher than I did. In their current position I am still struggeling to find a comfortable way to press them.
Thanks for the reply! Yeah, I was worried that may be your answer, haha. I'd love to use the SNES L&R buttons -and- have a working cartridge reader since I already shelled out for a cartridge pcb. But I may have to resort to smaller L&R buttons to get it to work. Thanks for your input on ergonomics as well, this is something I'm working with myself.

Keep up the great work!

User avatar
fdeluxe
Posts: 71
Joined: Tue Aug 23, 2016 10:16 am
Has thanked: 12 times
Been thanked: 27 times
Contact:

Re: [WIP] fdeluxes Game Boy Zero

Post by fdeluxe » Tue Nov 08, 2016 1:01 pm

Apis wrote:Looks like you didn't have to use the "vertical aligned buttons" like the Kite's build did to use the 3DS analog stick. Can I see the inside of your build to see how the psp stick is mounted?

Also, does anyone know if the Kite build will accept the psp analog stick? I can't ask in the Kite thread because it's locked.
I will post some pics of the interior tomorrow. As for the analog stick, the placement is pretty easy since the stick fits right between the button pcb and the case. No need to leave a hole in the pcb! I just left the middle screw of the button pcb a little loose to prevent to much pressure on the stick so it wont get stuck.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest