Intercepting the Gameboy LCD
October 26, 2010 23 Comments
A peculiar aspect of the original Gameboy is how well it did given how absolutely dreadful the display hardware was. The screen is not backlit, the colour palette is a meager 4 shades of gray and the resolution is only 160×144 . Before you object that that’s just how the technology was back then, note that it launched at about the same time as the Lynx and the Game Gear, both of which had beautiful backlit, 4096 colour screens.
(This site has moved to http://www.flashingleds.net, go there if you have comments or questions)
However the upshot of such a dismal screen is that the battery life is phenomenal, and this was instrumental in the Gameboy being such a spectacular success. And when lots of big developers get involved, you get graphics that are actually pretty nice.
Brilliant pixel art in 4 shades
Twenty years later the hobby electronics scene is thriving and there is a wide variety of powerful, cheap hardware. You now have an army of people like me who are not embedded engineers, but have 20+MHz microcontrollers and a passionate desire to build stupid, pointless crap with them.
And those people may be interested to learn that because it’s so low-spec, it’s quite straightforward to hijack the gameboy display for whatever nefarious purposes you please.
[EDIT: Based on some of the feedback I might not have made the point of this project perfectly clear. I’m not interested in re-using the screen (because the screen is terrible as discussed above). I want to access the video data from the gameboy so I can display it on something more interesting. You may of course do whatever you please with this information]
Let’s discuss how to go about this. A good source of information about the gameboy hardware is devrs.com. Particularly handy is the schematic by Jeff Frohwein:
Direct your attention to the “LCD Display” block on the left
The signals we are interested in are VERTSYN,HORSYNC, DATAOUT0, DATAOUT1 and CLOCK. These are the control lines for the LCD coming from the central processor (which is not shown in this schematic). I’ll explain how these control lines work in a moment. First we’ll discuss how to tap into them, which should enable us to reconstruct the images being sent to the LCD.
Just opening a Gameboy turns out to be one of the most difficult steps, thanks to stupid Nintendo and their stupid tri-wing screws. After several attempts with flathead screwdrivers I gave up and bought a triwing driver from ebay for a few bucks. Unless you’re happy to smash up the case, I suggest you do the same.
Once you do have it open, it’s not hard to find the signals we’re after with an oscilloscope or logic analyzer:
The LCD connector
Handily they’re 5V logic levels, but if your instrument does not have robust input protection then be careful of the -30V DC contrast signal! (I forget exactly which one, but it’s one of the lower 10 pins – use a multimeter to find it if you’re worried). The pitch is not particularly tight, so I simply soldered some ribbon cable to the LCD connector. It’s possible (but tight) to then feed this through the cart slot and still have access to the pins with the Gameboy closed up again.
With the gameboy on, this is the kind of data you’ll see:
Logic capture of one display line. This is too zoomed in to see any VSYNC pulses
Let’s discuss how these signal lines operate. The controller scans through each frame line by line, setting each pixel in sequence to whatever colour value is required. We start at the upper left of the screen, and start belting out pixel values.
The pixel clock pulses once for each pixel. At the falling edge of the CLOCK signal, , DATA1 and DATA0 give you the 2-bit colour value corresponding to that pixel. You can see in the capture above that there is a large section of one colour in the middle of this line, where the colour value is 0b11.
Once all 160 pixels in the first horizontal line are done, we wait for a signal to move down and start the next line underneath. This is the role of the HSYNC line, and the signal is a rising edge.
Once 144 lines have been drawn, we wait for a signal to go back and start all over again with a new frame. This is the role of the VSYNC line, and the signal is a rising edge.
From the logic capture you can see that when a line is finished, the controller does not immediately start the next one. In fact over half the time assigned to each line is not used; the pixel clock is not running. Specifically, we get 68.9us of deadtime after all 160 clock pulses before the next HSYNC pulse happens. After all 144 lines, we get 1.1ms before the next VSYNC pulse. This is not really an awful lot of time, so to do anything practical with this data you’ll probably be skipping some frames. Remember that 60Hz is the LCD refresh rate, but it’s not necessarily the speed at which the central processor is updating the screen.
As a proof of principle I exported a capture of the signal waveforms (with the excellent Saleae Logic) to my graphing software of choice (the excellent Igor Pro). After throwing together a very simple script to process the signals, we can indeed reconstruct the image!
Good grief, it worked!
If you’d like to play with this yourself, raw data from a frame (it’s not the same frame as the image above) and the Igor script are available below. Since WordPress apparently won’t let me post *.txt files, I have renamed them as doc files. I leave it “as an exercise for the reader” to change the file extension back if required.
Igor script (be warned that it’s really something quick and dirty I threw together)
I have plans for this, and in a future post I’ll discuss doing something with it in (semi) real-time.
P.S. Of course I understand that you could get the same result, possibly a lot easier, with an emulator. But there’s just something pure about working with original hardware.
P.P.S. Navy Seals is an absolutely dreadful game. The other game I have on hand is Hook, which is even worse
[EDIT: Followup post here]
[EDIT (30/12/2011): If you came looking for gameboy hardware info, another great resource is this report by John Ernberg]