Game Boy Zero

From TheBeard Science Project Wiki
Jump to: navigation, search

The Game Boy Zero is a custom portable game machine that is capable of storing and playing thousands of games ranging from Atari 2600 to Sony Playstation. It's made from an original Nintendo Game Boy enclosure and a Raspberry Pi Zero computer. It's powered by a rechargeable lithium-polymer battery. It includes built-in audio, video, controls, optional HDMI video output, and a USB port for additional controllers.

DSC00360.JPG

DSC00373.JPG
Screen01.png

My good friend commissioned me to build this for him. It was a great opportunity to learn about different video and audio solutions, like I2S (Inter-IC Sound Bus) digital audio, and implementing RetroGame a utility for mapping GPIO (General Purpose Input/Output) signals to a USB input device.

Wermy from Sudomod did a similar project and I got a lot of ideas and information from his blog.

One very key difference between Wermy's Game Boy and mine is that he used an all-in-one board that included: a USB hub for button inputs, pulse-width modulation (PWM) filter, audio amplifier, and analog stick input. I would have liked to use the same all-in-one board, but I wasn't able to get one at the time. Besides, doing it differently was more educational for me. I wanted to use general-purpose parts to make my Game Boy Zero and learn more about some different technologies.

Another difference is that Wermy made some 3D printed parts and offered them for sale in his store, but I made some 3D printed parts and I'm offering them for free on Thingiverse (link).

Lastly, Wermy made a custom Game Boy cartridge that had an SD card in it to store the OS and games. It was a neat aesthetic, but I decided not to do that. A cartridge does make it easier to remove the SD card, but it would have been a lot of work and my friend didn't necessarily want it.

Key Features:

  • Original Game Boy design
  • Analog video display (with adjustable image settings)
  • I2S digital audio (mono)
  • Built-in speaker
  • Volume control potentiometer
  • 3.5mm headphone socket (disables speaker when plugged in)
  • Rechargeable Lithium-Polymer (LiPo) battery
  • Power management with micro USB charging port
  • USB 2.0 for additional controllers or other devices
  • HDMI alternative video output
  • Added buttons: X, Y, Left/Right triggers
  • Safe-shutdown button
  • 128GB storage

Components:

  • Aftermarket DMG-01 case (source)
  • BW 3.5 Inch TFT LCD Monitor for Car (source)
  • Adafruit I2S 3W Class D Amplifier MAX98357A (source)
  • 8 ohm speaker (28.5mm diameter; from junk laptop)
  • B103 10k ohm wheel potentiometer (source)
  • 3.5mm headphone socket (source)
  • 3.7v 2500mAh LiPo battery (51mm x 65mm x 8mm) (source)
  • Adafruit Powerboost 500C (source)
  • USB 2.0 port (came with the PowerBoost) and micro USB breakout board (source)
  • Raspberry Pi Zero 1.3 (source)
  • 4-button PCB and button kit (source)
  • tactile buttons, diodes, resistors, LEDs (from miscellaneous parts)
  • 128GB Sandisk Extreme PRO micro SD card (source)

Update: I've since found a nice kit with a case, button PCB, speaker, and other plasticware (source).

Video

File Downloads

Filename Description Size Modified Link

RetroBoy_FINAL_1.0.img.gz

SD Card image of my completed Retropie install.
4GB uncompressed; can expand to any size.
777M 4/3/2018

Download

Game_Boy_DMG-01_Button_Well_and_Screw_Bracket.zip

3D print files (STL). 274K 4/3/2018

Download

RetroGame.zip

Install script for controller drivers. 2.7K 4/3/2018

Download

RetroBoy_Configs.zip

Example config files. 14M 4/3/2018

Download

Scripts.zip

Miscellaneous scripts. 411K 4/3/2018

Download

checksum.md5

Checksums for all files (md5). 293B 4/3/2018

Download

checksum.sha512

Checksums for all files (SHA512). 773B 4/3/2018

Download

Hardware

Game Boy Enclosure (DMG-01)

Removing Material

To make room for all the additional components I had to remove a lot of material from the case, especially the battery compartment. This is by far the most frustrating part of the project, so work slowly and measure often.

It's important to remove material incrementally and only remove what you need! In other words, when you've chosen a place to put something, grind away enough to just fit that component. As you progress and add new components, grind away more as needed.

Don't remove critical structure unless you need to! Use a marker to mark the screw holes and find a way to work around them.

I used a Dremel to remove most of the material where appearance is not important, and I used an X-Acto knife to make more precise cuts. I was pretty satisfied with the cut around the screen. I used a caliper to define the width of the edge, running it along the inner edge of the recession leaving a scratch mark outlining exactly where I wanted to cut. An X-Acto knife, some small fine-tooth files (both round and triangular), and sand paper were my weapons of choice. Oh, and lots of patience.

DSC00195.JPG DSC00147B.JPG

The button holes were easily positioned using the paper template provided with my button PCB (if the seller's listing doesn't mention providing a template, ask them if it comes with one). I marked the drill points with an awl and used a step drill bit to cut the holes, which is nice for two reasons: 1) it starts with a small bit and makes it easier to start the hole, and 2) each step chamfers the edge for the previous step. I drilled from the outside of the case because it gives it a cleaner edge.

DSC00148.JPG Say "yes" to step drill bits

The template said to drill it to 7/16 inch, but you should always err on the safe side and drill it smaller, see how the button fits, then drill more as needed.

Another thing I had to do was cut a new slot for the volume knob, as the original slot is being used for HDMI. I first outlined the area I wanted to cut with blue painter's tape. I then used a "scooping" technique with an X-Acto knife to get reasonable precision. I've drawn a crude graphic illustrating my technique.

DSC00363B.JPG
DSC00361.JPG

RetroBoy removing material.png

3D Printed Parts

Unfortunately, I had to remove some of the screw posts to make room for the screen. I made a 3D printed bracket that provides screw holes behind the screen. I also created several stand-offs and mounting brackets for various things, but they are not critical to the structural integrity of the case. If you don't have a 3D printer, you can order similar parts from Sudomod here and here. Otherwise, you can download my files for free from Thingiverse (link).

The button wells are also important to keep the buttons in place. After gluing them in, put the buttons in and test them out. If it doesn't feel quite right, wrap some fine-grit sand paper around a screwdriver (or something round) and sand down any edges that are catching on the buttons.

DSC00155.JPG DSC00154.JPG

I also printed various small blocks and used scrap 3D print pieces to act as spacers. I didn't include these because anyone can use scrap material to fill gaps and what not.

I printed everything in ABS, 100% infill, a raft, and no supports. In case you want to know, my printer is a CTC Bizer (the first model). I bought it when it was $300, and I've modified it so heavily that it's pretty much an entirely different printer. I get very decent prints for a total cost of no more than $400 (yes, I'm bragging).

Buttons

The button PCB that I bought is simply an arrangement of contacts for silicone keypad switches that act as the control inputs. There are no actual components on this board, only button contacts and a row of through-hole solder points.

DSC00158.JPG DSC00156.JPG

Custom Ordered Parts

I ordered some cosmetic parts from http://www.retrofresh.uk/ and they really make the project complete! The screen cover was essential to hide the rough-cut screen bezel and give it an original Game Boy look. I also bought a couple of cartridge labels with some beautiful original art (many are more intricate than the one pictured below). The aftermarket cartridge I bought was just an eBay buy. I love how it just says GAME!

DSC00359.JPG
DSC00365B.JPG

Original Nintendo Game Boy.

Structural Integrity

Just an extra note about structure: imagine the device being dropped and try to imagine the weak points. I tend to apply glue very liberally and I put kapton tape wherever I see potential for electrical shorts (other kinds of tape will do). I may also add strips of foam, popsicle sticks, 3D printed parts, and more. Sometimes it's prudent to screw things down in addition to gluing them (the ol' screw-n-glue). Time is very costly to me, so time spent servicing devices repeatedly is better spent reinforcing them once.

Raspberry Pi Zero

The Raspberry Pi Zero 1.3 is pretty self explanatory. I decided not to use the Zero W version because my friend wasn't going to use the built-in Wi-Fi and battery life was already severely limited. I added a small heat sink to the CPU for good measure. There isn't much else to say about it, so here are some reference materials.

Some technical specs and other info: https://www.raspberrypi.org/documentation/hardware/raspberrypi/README.md

Pi pinout.png Pi zero.jpg
Note: Throughout this page, when I reference a GPIO pin, I'm referring to the NAME, not the Pin#. For example, the second pin down on the left I will refer to as GPIO02, not pin 03. I may say "GPIO pin 2" to mean GPIO02.

Back-side solder pads:
Pi pads.jpg

Composite out:
Pi tv.jpg

SD Card

During installation and testing I used a 4GB Sandisk micro SD card. This makes it faster and easier to make daily backup images. In the final product I installed and expanded the image onto a 128GB Sandisk Extreme PRO. The Extreme PRO version is more expensive, but I wanted to use an SD card with wear leveling. This was important because the OS is installed on the Ext4 file system. Ext4 is a journaling file system, which is a "file system that keeps track of changes not yet committed to the file system's main part by recording the intentions of such changes in a data structure known as a journal" [1].

Sd.jpg

Why is this a problem for an SD card? It generally increases the number of writes to disk and will wear out the SD card faster. This really sucks for the Raspberry Pi because the OS is meant to be installed on an SD card, and almost all Pi-based Linux distros come on Ext4.

Why do Raspberry Pi OS images come on Ext4 file systems?
Probably because a journaling file system is better able to handle an abrupt system halt, like unplugging the system. Raspberry Pi's are often used for applications that require that kind of flexibility. The thing doesn't even have a power button.

What is wear leveling?
"A technique for prolonging the service life of some kinds of erasable computer storage media." [2]

So what are my options?

  1. Use an SD card that has wear leveling such as a SanDisk Extreme PRO (not SanDisk Ultra).
  2. If you have a choice, use a non-journaling file system, such as Ext2.
  3. If your application calls for heavy disk writing, consider writing data to a hard drive or SSD.

All things considered, I chose option 1. I don't expect extremely heavy disk writing, but later on in my project I do reconfigure RetroArch to write to the memory card for Playstation emulators at 2 second intervals to alleviate another problem (see Playstation Saving).

Display

Disassembly

The BW 3.5 Inch TFT LCD Monitor is a cheap product, so before you disassemble it, give it a test run to look for dead pixels or any other problems. If you have some extra cash, I would recommend buying two of them in case one of them is crap. Why not buy a more expensive one instead of two cheap ones? Even expensive ones can arrive broken. Buying two can give you some flexibility. The second one can be a backup in case you break the first one, and if they both end up working fine you now have another screen that you can use for another project.

Lcd.jpg

The display is a bit difficult to disassemble. After unscrewing the backside, you still have a screen cover that is stuck on with adhesive. Sometimes using a heat gun is a good way to loosen up adhesives, but in this case I didn't want to cause any warping of the screen itself, so I very carefully separated the cover by cutting around the edges with an X-Acto knife. I made sure to cut all the way around the screen, lifting as much as I could with the knife before pulling it off by hand.

Once I had freed the screen from its bezel, I cleaned off the adhesive with Zippo lighter fluid (or Ronsonol). You could also use Goo Gone.

Setup

The screen is attached to a display driver through a ribbon cable. The display driver then has four input wires:

Color     Function    
white unused
yellow video in
black ground
red 5V+ in

 DSC00142 EDIT.JPG

I don't remember what the white wire is for, but I didn't use it. In addition, there is a 3 button PCB attached using a small white connector (left side). These are display adjustments, such as brightness and contrast. I never needed to use them, but I included them in the final product anyway. They were long post-style tactile buttons, and I cut them shorter to make them fit in the crowded interior of the Game Boy Zero.

DSC00205 CROP.JPG
Brightness, contrast, and hue controls for the display.

Wiring diagram for display:

Rb-schematic-display.png
Note: The 5V and GND go directly to the Powerboost, not the Raspberry Pi.

Power Modification

The display driver requires about 5.5V to 6V to run, but we can only provide 5V, so we need to make a modification suggested by Wermy. Take a small insulated wire and solder it between the 5V IN (red wire) and pin 2 of the the 8-pin IC (which I believe is a DC-to-DC step-down converter). The chip has a notch indicating pin 1, so pin 2 is the next pin down (on the same side).

DSC00142.JPG

For software configurations, go to Display Config.

Audio

Audio Module

I had a lot of trouble finding the best audio solution for this project. At first I tried pulse width modulation (PWM) by re-assigning the GPIO pins on the Raspberry Pi to generate two channels of PWM output then using a low-pass filter to get the audio signal. I used a software utility suite called WiringPi, but I never got it to work with Emulationstation. It seemed to cause Alsa to crash. There are a few good tutorials out there describing how to set up WiringPi on a fresh Raspbian install (which worked fine when I tried it), but my efforts to resolve the compatibility issues with Emulationstation began to outweigh the benefit. I then tried Pigpio, but it was much the same story. I was done with PWM. Besides, it is supposedly not the best quality audio you can get from a Raspberry Pi.

20170427 225434 CROP.jpg
Failed attempt to use PWM audio with a low-pass filter.

DSC00333.JPG
The messy test bench.

After rethinking my approach, I decided to go with an entirely different technology: I2S (Inter-IC Sound Bus), which is a serial audio protocol. I purchased the Adafruit I2S 3W Class D Amplifier MAX98357A (source), which has a Digital-to-Analog Converter (DAC) with an amplifier built in. It produces high quality audio and it can be very energy efficient in low watt modes. For clarification, I2S does use PWM, but it's not the same as using just PWM (source). I wired it as follows:

I2S Module Input GPIO Pin Powerboost 500C 8 Ohm Speaker Wire Color
LRC GPIO 19     yellow
BCLK GPIO 18     blue
DIN GPIO 21     green
Vin   5V+   red
GND   GND   black
Out (+)     (either pin) red
Out (-)     (either pin) black

It's important that this module doesn't require a Master Clock (MCLK) input, as there are apparently no DAC drivers for Raspberry Pi Zero that support it (indicating that the hardware simply doesn't support it).

DSC00619 2.JPG DSC00374 CROP.JPG

Notice that I powered it directly from the Adafruit Powerboost 500C instead of through the Pi. I did this because I decided to run it on 5V and there was no other reason to power it through the Pi. If I wanted to save overall power and run the I2S module on 3.3V, I would have drawn the power from the Pi, but that might put the Pi at risk of having insufficient power to run some CPU-intensive games and audio at the same time. I didn't test this, I just went with that reasoning.

I tried out the gain setting on the I2S module, but I was satisfied with the default gain level. If you want to change it, wire a resistor as follows:

  • 15dB if a 100K resistor is connected between GAIN and GND
  • 12dB if GAIN is connected directly to GND
  • 9dB if GAIN is not connected to anything (this is the default)
  • 6dB if GAIN is conneted directly to Vin
  • 3dB if a 100K resistor is connected between GAIN and Vin

Wiring diagram for audio:

Rb-schematic-audio.png
Note: The 5V and GND go directly to the Powerboost, not the Raspberry Pi.

What if I wanted stereo? This module is for a single audio channel. If you want stereo sound, you will either need two modules, a different module that supports stereo, or you could set up something clever with the left/right channel select and rapidly switch back and forth between channels (I'm speculating). For my application, mono was sufficient and I wanted to minimize power consumption.

Another good tutorial: https://learn.adafruit.com/adafruit-max98357-i2s-class-d-mono-amp

Other Audio Hardware

The audio system also includes a 3.5mm audio socket, an 8 ohm speaker (28.5mm diameter), and a B103 10k ohm wheel potentiometer. The audio socket has a switch that allows it to change audio channel when a jack is inserted. I used this to disable the speaker when headphones are being used. The left and right channels on the audio socket are bridged to make it mono. Also, the speaker and the potentiometer don't care which wire is which. In other words, as long as you follow my diagram the two wires can be switched and the result will be the same. Be sure that the speaker is rated for the wattage that is put out by the DAC/amp. My configuration demands that the speaker handle at least 1.4W. The potentiometer was wired so that the resistance increases as the wheel is turned clockwise (with the "B103" label facing you).

DSC00338.JPG DSC00339.JPG

DSC00337.JPG DSC00335.JPG
Note: Some of these pictures show different speakers, but they all have the same specs.

For software configurations, go to I2S Audio Config.

Controls

The controls are very simple: each button on the control PCB maps to a single GPIO pin on the Raspberry Pi. They all share a common ground. I added two tactile buttons for the left and right triggers that also map to GPIO pins.

DSC00149 RBOY.JPG DSC00363B.JPG

For very basic (lazy) protection of the GPIO pins, I added 330ohm resistors to each of the button inputs. This means that the path of least resistance will usually be through the ground pin, but this really doesn't protect against most over-volt situations. If you want proper protection, look into Zener Clamping. I don't seem to have any floating pin problems, so I don't think I needs any pull down resistors (even though I really should use them). Also, the rubber buttons don't have much bounce, so I don't need to worry too much about repeated inputs. The message here is: I'm lazy.

DSC00186.JPG DSC00209.JPG

Control-to-GPIO mapping:

Control PCB RPi GPIO
X GPIO 16
Y GPIO 13
A GPIO 6
B GPIO 5
START GPIO 11
SELECT GPIO 9
RIGHT GPIO 10
DOWN GPIO 22
UP GPIO 27
LEFT GPIO 17
GND GND
 
Tactile Button RPi GPIO
LEFT TRIG GPIO 26
RIGHT TRIG GPIO 20
LEFT GND GND
RIGHT GND GND

DSC00159 EDIT.JPG

DSC00173.JPG

Note: I changed the pinout since I took the photos above. The tables to the left are correct.

Wiring diagram for the controls:

Rb-schematic-controls.png

USB Port:

To setup the USB port I simply re-routed the USB data pins on the Raspberry Pi to a type-A USB port. It's important to twist the two data wires as tightly as possible. If you don't, the wires might cause interference (called "crosstalk") and the signal will be poor. The 5V and GND power pins go the the PowerBoost module, not the Raspberry Pi. See the Power Section for more info.

Wiring diagram for USB:

Rb-schematic-usb.png
Note: The 5V and GND go directly to the Powerboost, not the Raspberry Pi.

A tip for USB adapters:

One of the best things I did for testing on the Raspberry Pi Zero is buy these cheap little USB to micro USB adapters. The USB ports on the Raspberry Pi Zero are really close together, so finding adapters that can plug in adjacent to another device is difficult (or more expensive). These things are super cheap; I got these for $0.30 a piece on aliexpress.com. All you have to do is cut the colored plastic shell off of them with some wire snips. Try searching "mini otg usb to micro usb adapter".

DSC00667.JPG

Power

Everything in the Game Boy Zero is powered by a 3.7v 2500mAh LiPo battery (51mm x 65mm x 8mm). Power distribution and charging are controlled by the Adafruit Powerboost 500C. It provides 5.2V of power to all of the components, and it can charge on any 5V micro USB charger. It can handle up to 1A of current.

DSC00208.JPG DSC00207.JPG

Unfortunately, I discovered the Powerboost 500C can't run and charge the battery at the same time. Even if you have it plugged into a 5V power source the battery will still drain and eventually die. So you do have to turn it off every once in a while to charge. I read that this will happen when you draw more than 500mA, but I don't think the Game Boy Zero is drawing that much so I'm not sure what's happening. Next time I will go with the Adafruit Powerboost 1000C which has load-sharing.

You can see that I also re-routed the low-battery LED to a red LED near the USB ports. This is just to make it more visible when the case is fully assembled. Note that there is a pin labelled "LB" for low-battery but it is actually turned on when the battery is NOT low. That's not what I want. I could have set up a small circuit to create the proper behavior, but why? There is already an LED that does what I want.

Also, a note about spacing: notice that I have PCBs on each of the two shells of the casing that, when assembled, will be sandwiched together. It's very important to ensure that nothing is touching. They actually fit together nicely in this case, but I still covered the Powerboost in kapton tape when I was done. Hot glue can hold pretty well, but I always imagine what might happen if this thing was dropped. I would much rather my friend tell me "something is loose inside" instead of "something is loose inside and it won't turn on."

DSC00205.JPG DSC00375.JPG
Note: I added a wire extension for the battery to make it possible to unplug the battery without disassembling the case.

I want to address the gray ribbon cable with the two white connectors in the second photo above, because it may cause some confusion. This cable passes power and data between the two shells of the case. The small connector on the left is power. It seemed a bit flimsy with only two wires so I doubled up the wires. That's why you see four wires coming out of it, even though it's only a 2-pin connector. The wide connector on the right also has four wires and it is for control inputs. It has left trigger, right trigger, the "safe power off" button, and ground. See the Controls Section for more info on that.

Wiring diagram for power distribution:

Rb-schematic-power sm.png

For power configurations, go to Power Config.

Software

RetroPie

RetroPie is a suite of software that brings together different gaming platforms into one clean, organized game library and menu system. It also lets you centrally manage configurations across different emulators. I used the pre-made Raspbian image. In my Game Boy Zero project, I installed version 4.1.

Retropie02.png Retropie03.png

This version of RetroPie comes with emulators for the following platforms:

  • Amstrad CPC
  • Arcade (mame-libretro, mame-mame4all)
  • Atari 2600
  • Atari 7800
  • Atari Lynx
  • FinalBurn Alpha
  • Famicom Disk System
  • Neo Geo
  • Neo Geo Pocket
  • Neo Geo Pocket Color
  • Nintendo (NES)
  • Super Nintendo (SNES)
  • Nintendo 64
  • Game Boy
  • Game Boy Advance
  • Game Boy Color
  • Sega Master System
  • Sega Genesis (Mega Drive)
  • Sega Game Gear
  • Sega 32x
  • Sega CD
  • Sega SG-1000
  • PC Engine (TurboGrafx-16)
  • Playstation (PSX)
  • Microsoft MSX
  • Vectrex
  • ZX Spectrum

See all supported systems as of RetroPie version 4.3 here.

RetroPie is a combination of:

Raspbian A Linux distribution that is a port of Debian for the Raspberry Pi. This is my preferred operating system for this project, but there are others available for running RetroPie.
Emulationstation Graphical interface for managing your game library. It lets you easily configuring controllers, audio, and more.
RetroArch Unified frontend for emulators that lets you manage audio, video, control, and other configurations across all your emulators. It uses the Libretro API. In RetroPie, RetroArch is integrated with Emulationstation.

Much of this information can be easily found on other sites, but since I refer to these different things in this page, I figured I should briefly explain the differences.

Display Config

These are the software configurations for all things related to display. For display hardware setup click here.

Screen Resolution

I changed the screen resolution to that of the display device, which is 640x480. You can change this in the /opt/retropie/config/all/retroarch.cfg file. The important values are:

video_fullscreen_x = "640"
video_fullscreen_y = "480"

Contents of my /opt/retropie/config/all/retroarch.cfg file. I've removed all commented lines here. In other words, make sure the file has only these lines uncommented (if you are setting it up exactly like mine):

cache_directory = "/tmp/retroarch"
core_options_path = "/opt/retropie/configs/all/retroarch-core-options.cfg"
system_directory = "/home/pi/RetroPie/BIOS"
config_save_on_exit = "false"

video_fullscreen_x = "640"
video_fullscreen_y = "480"

video_threaded = "true"
video_smooth = "false"
video_aspect_ratio_auto = "true"
video_font_size = "12"

input_joypad_driver = "udev"
input_autodetect_enable = "true"

input_player1_a = "z"
input_player1_b = "x"
input_player1_y = "s"
input_player1_x = "a"
input_player1_start = "enter"
input_player1_select = "ctrl"
input_player1_l = "w"
input_player1_r = "q"
input_player1_left = "left"
input_player1_right = "right"
input_player1_up = "up"
input_player1_down = "down"
input_player1_l2 = "e"
input_player1_r2 = "r"

input_state_slot_increase = "right"
input_state_slot_decrease = "left"
input_exit_emulator = "enter"
input_shader_next = "m"
input_shader_prev = "n"
input_rewind = "r"
input_reset = "x"
input_menu_toggle = "a"

all_users_control_menu = "true"
menu_driver = "rgui"

rewind_enable = "false"
rewind_buffer_size = "10"
rewind_granularity = "2"

video_gpu_screenshot = "true"

input_enable_hotkey = "ctrl"
auto_remaps_enable = "true"

Font Size

The default font size in Emulationstation was a bit too small for the tiny screen, so I increased it.

Edit the file /etc/emulationstation/themes/carbon/carbon.xml and look for a section that starts with the tag <textlist name="gamelist">. It should look like this (although it looks slightly different in updated versions):

<textlist name="gamelist">
		<selectorColor>1c1c1c</selectorColor>
		<selectedColor>8b0000</selectedColor>
		<primaryColor>969696</primaryColor>
		<secondaryColor>7a6161</secondaryColor>
		<fontPath>./art/Cabin-Bold.ttf</fontPath>
		<forceUppercase>1</forceUppercase>
		<scrollSound>./art/select.wav</scrollSound>
	</textlist>

</view>

<view name="basic">
	<textlist name="gamelist">
		<fontSize>0.0380</fontSize>
	</textlist>
</view>

<view name="detailed">
	<textlist name="gamelist">
		<fontSize>0.03</fontSize>
	</textlist>
</view>

You can see, in this case, there are two smaller sections within <view name="basic"> and <view name="detailed">. Edit one of the fontSize tags to a value that better suits your display (the fontSize tag may also be in the larger section). For my 640x480 display, I found that 0.06 was ideal.

RetroGame (Controller Driver)

RetroGame is a Raspberry Pi GPIO-to-virtual-keyboard utility for classic game emulators. It's very simple: it maps GPIO pins to keyboard keys. When you configure your controller, it will act like a keyboard, but you don't need to think about that. After installing and configuring RetroGame, you can just go into Emulationstation and configure the controller as you usually do. For controller hardware setup click here.

Installing RetroGame

To install RetroGame I followed these instructions, but I will repeat them here.

Download the RetroGame script:

curl -O https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/retrogame.sh

If you don't trust it, read the script first to see what it does. Now run it:

sudo bash retrogame.sh

Note: In case the link no longer exists, I've provided the script in my Downloads Section.

You will get a prompt asking to select from a set of preset configurations. I chose #3 PiGRRL Zero, but it doesn't matter what you choose. These are just presets. It will then prompt you to continue. Type "y" for yes. After it installs, it will ask you to reboot the system. Type "y" to continue. Once it finishes rebooting you can edit the RetroGame config.

RetroGame Configuration

Contents of my /boot/retrogame.cfg file. I've removed most commented lines here. In other words, make sure the file has only these lines uncommented (if you are setting it up exactly like mine):

#keyboard key  GPIO
#============  ====
LEFT           17  # Joypad left
RIGHT          10  # Joypad right
DOWN           22  # Joypad down
UP             27  # Joypad up
Z               6  # 'A' button
X               5  # 'B' button
A              16  # 'X' button
S              13  # 'Y' button
Q              26  # Left shoulder button
W              20  # Right shoulder button
LEFTCTRL        9  # 'Select' button; PiTFT Button 2
ENTER          11  # 'Start' button; PiTFT Button 3

Reboot after making changes.

I2S Audio Config

These are the software configurations for all things related to audio. For audio hardware setup click here.

DTOverlay Configuration

Device Tree Overlay (DTOverlay) is a system that many Pi-based operating systems use to load modules for devices. The drivers are already on the system, you just have to enable them. You can find all the overlays in /boot/overlays (which also contains a README file). For more information on DTOverlay read this.

Contents of my /boot/config.txt file. I've removed all commented lines here. In other words, make sure the file has only these lines uncommented (if you are setting it up exactly like mine):

dtparam=i2s=on

gpu_mem_256=128
gpu_mem_512=256
gpu_mem_1024=256
overscan_scale=1

dtoverlay=rpi-dac
dtoverlay=i2s-mmap

Reboot after making changes.

Alsa Configuration

Advanced Linux Sound Architecture (ALSA) provides audio functionality. The configurations below may not be entirely necessary, but this is ultimately how I left it.

Contents of my /etc/asound.conf file:

pcm.!default {
    type            plug
    slave.pcm       "softvol"   #make use of softvol
}

pcm.softvol {
    type            softvol
    slave {
        pcm         "dmix"      #redirect the output to dmix
    }
    control {
        name        "PCM"       #override the PCM slider to set the softvol
        card        0
    }
    min_dB -5.0
    max_dB 10.0
    resolution 6
}

The min_dB, max_dB, and resolution were some things I was playing around with. You can omit them or adjust them.

You can get a list of playback hardware devices in Alsa:

aplay -l

You will see output that looks like this:

**** List of PLAYBACK Hardware Devices ****
card 0: sndrpirpidac [snd_rpi_rpi_dac], device 0: RPi-DAC HiFi pcm1794a-hifi-0 []
  Subdevices: 0/1
  Subdevice #0: subdevice #0

Notice that I only have one card, which is card 0, device 0. My /etc/asound.conf file refers to card 0.

You can test the device by playing a sound file:

aplay -D hw:0,0 sound.wav

The -D option specifies the audio device, in the form hw:X,Y where X is the card # and Y is the device #.

You can also use a tool called speaker-test but I won't get into details. Read more.

Adjust volume levels:

alsamixer

Power Config

These are the software configurations for all things related to power. For power hardware setup click here.

Manual Power Button

I wrote a short and simple Python script for shutting the system down safely using a GPIO button press. It also allows you to specify a duration that the button must be held. It wasn't entirely necessary for this project, but it's a nice touch and I've been meaning to write something like this to be used in later projects.

Here is the code:

#!/bin/python
#
# Script to shutdown Raspberry Pi when GPIO input is held.
# Connect a button between ground (GND) and the GPIO pin
# that you specify below.
#
# If you run this script from your /etc/rc.local file, it
# will be running as root, which eliminates the need to 
# enter a password to elevate privileges. Otherwise, the
# sudo command will ask for a password before it will
# execute shutdown.

import RPi.GPIO as GPIO
import sys,os,signal,time

# GPIO pin number
btn = 4

# Button must be held for this many seconds
delay = 3.0

def sense_input(btn,delay):

  try:
    # Wait for button press
    GPIO.wait_for_edge(btn, GPIO.FALLING)

    count = 0
    while True:
      if GPIO.input(btn) == False:
        if count < delay:
          count = count + 1
          time.sleep(0.1)
          continue
        else:
         # Shutdown system
         os.system("sudo shutdown -h now")
         os._exit(-1)
      else:
          try:
            GPIO.cleanup()
          except:
            pass
          time.sleep(0.1)
          break

  except KeyboardInterrupt:
    try:
      GPIO.cleanup()
    except:
      pass
    os._exit(-1)

  except:
    pass          
        
delay = delay*10
while True:
  GPIO.setmode(GPIO.BCM)
  GPIO.setup(btn, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  sense_input(btn,delay)

Assuming you save this to /off-button.py go ahead and make it executable:

chmod a+x /off-button.py

Then add it to /etc/rc.local so it runs on startup. Enter the command above the exit 0 line so that it looks like this:

# ... existing rc.local stuff ...

python /off-button.py &
exit 0

Power Saving

Disable Wi-Fi: If you are using the Raspberry Pi Zero W and you don't plan to use the Wi-Fi, disable it so that it doesn't consume power.

To disable Wi-Fi, add this line to your /boot/config.txt file and reboot:

dtoverlay=pi3-disable-wifi

Disable Bluetooth: If you are using the Raspberry Pi Zero W disabling bluetooth will also help to save power.

To disable bluetooth, add this line to your /boot/config.txt file and reboot:

dtoverlay=pi3-disable-bt

Disable HDMI: Even when you're not using HDMI, the interface is enabled and consuming a small amount of power. If you don't plan to use HDMI, you can disable it.

To disable HDMI on startup, edit your /etc/rc.local file and add this line somewhere above the exit 0 line:

# ... existing rc.local stuff ...

/usr/bin/tvservice -o
exit 0

At any time, you can run this command to enable HDMI again:

/usr/bin/tvservice -p

Disable LEDs: LEDs only consume a tiny amount of power, but if you want to be really diligent with power saving you may want to consider disabling them.

To disable LEDs on the Raspberry Pi Zero, add these lines to your /boot/config.txt file and reboot:

dtparam=act_led_trigger=none
dtparam=act_led_activelow=on

Note: Disabling the LEDs on the Raspberry Pi Zero is different than on the other Raspberry Pi models. Read more about it here.

Configuration Improvements

Note: Some of these are no longer needed with newer versions of RetroPie.

Playstation Saving

Despite saving your game using the in-game save menu, you might find that your game wasn't saved because Retroarch saves the memory card data to the .srm file at certain time intervals. It's possible to turn your game off before it has a chance to truly save it. Learn how to fix this: Auto_Saving_to_Memory_Card

Game Lists in Emulationstation

For improvements in the listing of game files in Emulationstation (may not be relevant in newer versions of RetroPie): ROM_Files

Font Size in Emulationstation

For better visibility on smaller screens: Appearance

Faster Booting

Because the system doesn't need to wait for DHCP: Faster_Boot_Time

Keybindings

To change or remove RetroArch keybindings: Change/Remove_Keybindings

Optimizing for Performance

Because performance: Optimization

Lessons Learned

Modularity

I have this habit of making everything "pluggable" and socketed so that it can be removed. This often over-complicates the build and takes up more space. I sometimes do this to my detriment. My main concern is repeatedly soldering and de-soldering from a valuable component, like the Raspberry Pi, and damaging the contacts. Maybe in the future I will consider using perfboard, or something else that I don't mind damaging, and just soldering to that instead. The device probably won't need enough servicing to justify using connectors.

Functionality

I really wish I had done more research on the Powerboost 500C. When I discovered that I couldn't power the device and charge the device simultaneously, I realized I should have gone with the Powerboost 1000C. I did start my project with a list of functional requirements, but this one slipped my mind. The truth is, I didn't know the implication of load-sharing, nor did I notice that the 500C didn't have it. My friend was happy with the end product either way, so it turned out fine.

Triple-Check Your Wiring

At one point, I had a lot of trouble with the I2S audio output, and it turned out to be a silly mistake. The audio module uses GPIO pin 19 for LRC (Left/Right Channel Select). I was previously using GPIO pin 19 for the "A" button in my RetroGame config. I knew I was going to have to change the pin number, but I was in such a hurry to test the audio that I didn't consider that the DAC driver and RetroGame were fighting over that pin. The result was terrible sound quality and excessive loudness. It even tore the cone on one of my speakers.

Backups

There were a few times when I needed to revert my SD image to a previous stage in my progress. I did a backup every day and I'm glad I did.

Links

3D Printed Parts (Free Download):

Components:

  • Aftermarket DMG-01 case (source)
  • BW 3.5 Inch TFT LCD Monitor for Car (source)
  • Adafruit I2S 3W Class D Amplifier MAX98357A (source)
  • 8 ohm speaker (28.5mm diameter; from junk laptop)
  • B103 10k ohm wheel potentiometer (source)
  • 3.5mm headphone socket (source)
  • 3.7v 2500mAh LiPo battery (51mm x 65mm x 8mm) (source)
  • Adafruit Powerboost 500C (source)
  • USB 2.0 port (came with the PowerBoost) and micro USB breakout board (source)
  • Raspberry Pi Zero 1.3 (source)
  • 4-button PCB and button kit (source)
  • tactile buttons, diodes, resistors, LEDs (from miscellaneous parts)
  • 128GB Sandisk Extreme PRO micro SD card (source)

Raspberry Pi

I2S Audio

PWM Audio

Audio General

Controls

Sudomod's Blog

Custom Parts

Other Tech Links