The Game Boy Advance has been with us since mid-2001 and its portable nature, combined with a plethora of games, led it to become a very popular gaming device. However, many retro gaming enthusiasts, including Rodrigo Alfonso, wanted the ability to play anything they wanted, regardless if the title was released for the GBA specifically or not, which is why he came up with an add-on that does exactly this.
The GBA's link cable was intended for use with other Game Boy Advances for local multiplayer, or as a way to connect the handheld with a Nintendo Gamecube/Wii where it can act as a supplemental screen in a game. Therefore, by reverse engineering the protocol for writing information to the screen and getting button presses, Alfonso could send data from practically any system he wanted.
The cable contains six total pins, which are meant to carry a serial signal of either UART or serial peripheral interface (SPI). In this case, SPI mode 3 was chosen since its transfer rate can support 2Mbps with 32-bit transfers- plenty for sending pixel data.
In order for the host device (in this case a Raspberry Pi 3) to send data, Alfonso first had to figure out the required pins. The Pi acts as the controlling device, which means it is responsible for clocking its SPI0 CLK pin and toggling the MOSI pin as needed. To achieve a faster refresh rate, the GBA was modified with a 12MHz oscillator instead of the default 4.194MHz one for a hefty overclock. Now the Pi could send pixel data one-way at 4.8Mbps.
Owing to the Raspberry Pi 3's massive speed difference compared to the GBA's relatively slow CPU, the Game Boy is able to toggle its MISO pin HIGH and keep it there until it has finished processing the remaining data. The GBA is able to draw images to the screen at around 60 frames per second, but getting to this level of speed was not easy, since sending
120x80 pixels of uncompressed pixels 60 times per second would be far too much for the system to handle. So to compress data, the Pi first quantizes each frame from a full RGBA palette to a mere 256 total colors and then downscales the original 240x160px frame to several 120x80px frames that can be shifted slightly to create a mosaic effect and increase the framerate. Finally, raw pixel data is run-length encoded in order to save space and clocked out over the SPI bus.
You can read about this process in more detail here.
As mentioned before, the GBA is not only capable of receiving image data, but it can also send back data about which buttons are currently being pressed. On each frame a single 16-bit packet is generated and sent over the MISO pin to the Raspberry Pi where it is then translated as a VirtualGamepad so the inputs can be read with an API.
The last piece of this GBA game streaming project was to get audio playing out of the Game Boy's built-in speakers. The modded GBA runs s port of the GSM Full Rate audio codec and expects audio frames that are 33 bytes in size and grouped within chunks to prevent stuttering. After the Raspberry Pi's virtual soundcard has read whatever audio is currently playing, ffmpeg takes the data and converts it into the GSM encoding scheme at 18.157KHz, where it is finally sent to the Game Boy's buffer and eventually played.
Mounting the Pi onto the back of the GBA was accomplished by taking an old cartridge PCB, placing tape over it contacts, and attaching an enclosure containing a battery, power conversion circuit, and the Pi itself. Once configured, the Pi was then able to stream RetroPi games to the display as well as play audio. For more information, you can watch Alfonso's video below, or explore the code and other files here on GitHub.