Difference between revisions of "Gameboy VGA adapter"

From Hackerspace ACKspace
Jump to: navigation, search
m (set project picture)
 
(18 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
{{Project
 
{{Project
|State=Active
+
|State=Completed
|Members=Prodigity
+
|Members=Prodigity, Danny Witberg
 
|Description=Adding VGA output to a gameboy classic
 
|Description=Adding VGA output to a gameboy classic
}}  
+
|Picture=FPGAscreen.jpg
 +
}}
 +
[[Image:VGA.png|center|300x150px|Temporary VGAmeboy logo]]
  
 
= Introduction<br>  =
 
= Introduction<br>  =
Line 13: Line 15:
 
Nowadays the gameboy has been replaced by far more advanced (read: battery-slurping) handheld devices and as such, many people have one lying around collecting dust.<br>  
 
Nowadays the gameboy has been replaced by far more advanced (read: battery-slurping) handheld devices and as such, many people have one lying around collecting dust.<br>  
  
As some of you might remember, the biggest problem with the gameboy classic was the unlit screen which caused any form of sunlight to render the screen into a useless plastic mirror.<br>  
+
As some of you might remember, the biggest problem with the gameboy classic was the lack of backlighting which caused any form of unwanted lighting to render the screen into a useless plastic mirror.<br>  
  
REJOICE! For I have decided to add VGA output to the gameboy so you can play on 21" screens! (TAKE&nbsp;THAT&nbsp;SUN!) No more visibility problems! (Yes you can add LEDs to the back of the screen, stop being so boring&nbsp;:P)<br>
+
REJOICE! For I have decided to add VGA output to the gameboy so you can play on 21" screens! (TAKE&nbsp;THAT&nbsp;SUN!) No more visibility problems! (Yes you can add LEDs to the back of the screen, stop being so boring&nbsp;:P).
  
<br>
+
Before we get down and dirty, you'll need to be sure that you understand the terms used on this page; [[VGA terminology]].<br>  
 
 
= Important VGA terms<br>  =
 
 
 
Before we get down and dirty, you'll need to be sure that you understand the following terms:<br>
 
 
 
<br>
 
 
 
<u>Resolution</u><br>
 
 
 
The resolution of a screen is the amount of distinct pixels that can be shown horizontally and vertically.<br>
 
 
 
A resolution of 160x144 means that the display is 160 pixels wide and 144 pixels high (which results in a total of 23040 pixels).<br>
 
 
 
<br>
 
 
 
<u>Pixel</u><br>
 
 
 
A pixel is a unit which can output light of a chosen wavelength with a chosen amplitude(intensity).<br>
 
 
 
In case of colour displays, the pixel is a collection of 3 subpixels each responsible for either Red, Green or Blue (RGB). (alternatives exist but won't be discussed)<br>
 
 
 
<br>
 
 
 
<u>Refresh Rate</u><br>
 
 
 
The refresh rate of a display tells us how often the entire display gets updated per second (Hertz).<br>
 
 
 
It is necessary to update the display periodically as displays expect this. (60Hz - 100Hz is typical nowadays)<br>
 
 
 
A clocked signal is responsible for letting the display know it's time to refresh, this signal is referred to as vertical sync or VSYNC.<br>
 
 
 
<br>
 
 
 
<u>Horizontal Sync</u><br>
 
 
 
Horizontal Sync or HSYNC is a clocked signal which tells the display that we want to start sending pixel data at the start of the next line.<br>
 
 
 
To show what I mean, here is an example: (Resolution: 3x3)<br>
 
 
 
[1][2][3] HSYNC!<br>
 
 
 
[4][5][6] HSYNC!<br>
 
 
 
[7][8][9] VSYNC &amp;&nbsp;HSYNC! (simultaneously)<br>
 
 
 
The numbers display the order in which the pixels get updated.<br>
 
 
 
<br>
 
 
 
<u>Bits per pixel</u><br>
 
 
 
The bits per pixel or BPP tells us how many different (colour) shades a single pixel can display.<br>
 
 
 
The gameboy for example has 2 BPP which tells us that every pixel can have 4 different shades. (00, 01, 10, 11 -&gt; white, light grey, dark grey, black)<br>
 
 
 
To calculate the amount of shades (/colours), we simply calculate 2^BPP.<br>  
 
  
 
<br>  
 
<br>  
  
<u>Pixel clock</u><br>
+
= The gameboy<br>  =
 
 
This clock is responsible for sending the pixels to the display in a timely fashion so that the display will position the pixels correctly.<br>
 
 
 
<br>
 
 
 
= F*** TERMS GIVE&nbsp;ME&nbsp;TEH&nbsp;NASTY&nbsp;STUFF<br>  =
 
 
 
Err yeah.<br>
 
  
 
<u>Gameboy specs:</u><br>  
 
<u>Gameboy specs:</u><br>  
Line 97: Line 35:
 
<br>  
 
<br>  
  
As you can see we are presented with a refresh rate of 59.7Hz which is awesome as it matches standard VGA signal timing! (Nearly, but it's good enough&nbsp;:D)<br>  
+
As you can see we are presented with a refresh rate of 59.7Hz which nearly matches the standard VGA refresh rate. (Most likely close enough, only testing will tell)<br>  
  
 
The resolution of 160x144 however poses a problem, no such VGA resolution exists and as such we will be forced to pick a different resolution and do some pixel juggling.<br>  
 
The resolution of 160x144 however poses a problem, no such VGA resolution exists and as such we will be forced to pick a different resolution and do some pixel juggling.<br>  
  
The solution? DOUBLE&nbsp;BUFFER&nbsp;YEAAHHHH.<br>  
+
The solution? We will use <strike>double</strike> buffering and a different resolution.<br>  
  
 
<br>  
 
<br>  
  
<u>Double buffer</u><br>
+
= Calculations  =
  
Stole...borrowed from wikipedia:<br>  
+
<strike><u>Double</u></strike><u>buffer</u><br>  
  
''The easiest way to explain how multiple buffering works is to take a real world example. It is a nice sunny day and you have decided to get the paddling pool out, only you can not find your garden hose. You'll have to fill the pool with buckets. So you fill one bucket (or buffer) from the tap (or faucet), turn the tap off, walk over to the pool, pour the water in, walk back to the tap to repeat the exercise. This is analogous to single buffering. The tap has to be turned off while you "process" the bucket of water.''
+
To determine the size of our buffer<strike>s</strike> we simply take the resolution of the gameboy screen and multiply the amount of horizontal pixels with the vertical pixels and the bpp (160x144x2 = 46080).<br>
  
''Now consider how you would do it if you had two buckets. You would fill the first bucket and then swap the second in under the running tap. You then have the length of time it takes for the second bucket to fill in order to empty the first into the paddling pool. When you return you can simply swap the buckets so that the first is now filling again, during which time you can empty the second into the pool. This can be repeated until the pool is full. It is clear to see that this technique will fill the pool far faster as there is much less time spent waiting, doing nothing, while buckets fill. This is analogous to double buffering. The tap can be on all the time and does not have to wait while the processing is done.''<br>
+
The 46080 bits translate roughly to 6 kilobyte.<br>  
 
 
So yeah, we're gonna fill us some buckets. (woops, I described a term under the header 'F***&nbsp;TERMS&nbsp;GIVE&nbsp;ME&nbsp;TEH&nbsp;NASTY&nbsp;STUFF' oh well, suck it up&nbsp;;P)<br>  
 
  
 
<br>  
 
<br>  
  
<u>Our buffer demands</u><br>  
+
<u>Resolution</u><br>  
  
To determine the size of our buffers we simply take the resolution of the gameboy screen and multiply the amount of horizontal pixels with the vertical pixels (160x144 = 23040).<br>  
+
Multiplying horizontal pixels by a float is only a matter of altering the pixel clock.<br>  
  
The 23040 bits translate roughly to 3 kilobyte.<br>  
+
Multiplying vertical pixels by a float however is difficult as this has to be done with a digital solution.<br>  
  
What we mustn't forget is that we are dealing with 2 BPP and as such we need 2 buffers per frame, resulting in DUAL&nbsp;DOUBLE&nbsp;BUFFERS FTW! (dual double = 4)<br>  
+
As such we prefer to use a resolution whose vertical pixels are a multiple of 144. (Any integer)<br>  
  
(You can also put the 2 bits per pixel in the same buffer, but this makes the project a tad more difficult and I can't be bothered atm)<br>  
+
There so happens to be a resolution which adheres to this: 768x576<br>  
  
 
<br>  
 
<br>  
  
<u>Choosing VGA output format</u><br>  
+
<u>VESA&nbsp;signal 768x576</u> [http://tinyvga.com/vga-timing/768x576@60Hz source]<br>  
  
First and foremost, the refresh rate HAS to be 60Hz or else shit gets too complicated.<br>
+
'''General timing'''
  
Secondly, because of the display ratio of the gameboy lcd we are forced to either leave black bars around the screen or we need to display certain pixels more often than others.<br>
+
{| class="wikitable"
 +
|-
 +
! Screen refresh rate
 +
| 60 Hz
 +
|-
 +
! Vertical refresh
 +
| 35.819672131148 kHz
 +
|-
 +
! Pixel freq.
 +
| 34.96 MHz
 +
|}
  
Thirdly, the higher the resolution -&gt; the higher we need our pixel clock to be -&gt; more ex$pensive electronics required to handle such high clock speeds. (Graphics won't look (alot) better anyway)<br>  
+
<strike>To 'convert' 160 pixels to 768 we simply adjust the pixel clock: 34.96 MHz / 768 pixels = x MHz / 160 pixels x = 160 pixels * (34.96 MHz / 768 pixels) = 7.283 MHz So if we use a pixel clock of 7.283 MHz, the 160 pixels will stretch themselves over a width of 768 pixels.</strike>
 
 
Fourthly, we don't need a high resolution. We need a resolution whose display ratio lies closest to that of the gameboys display ratio. This happens to be 4:3. (to reduce the black bars as much as possible)<br>
 
 
 
Thus the best choice is using the smallest universally supported resolution available for the 4:3 aspect ratio -&gt; 640x480<br>
 
 
 
<br>
 
 
 
<u>VGA Signal Timing for 640x480</u><br>
 
 
 
Source: [http://tinyvga.com/vga-timing/640x480@60Hz tinyvga.com/vga-timing/640x480@60Hz]
 
 
 
General timing<br>
 
 
 
*Screen refresh rate 60 Hz
 
*Vertical refresh 31.46875 kHz
 
*Pixel freq. 25.175 MHz
 
 
 
Horizontal timing (line)<br>Polarity of horizontal sync pulse is negative.  
 
 
 
Scanline part Pixels Time [µs]<br>
 
 
 
*Visible area 640 25.422045680238
 
*Front porch 16 0.63555114200596
 
*Sync pulse 96 3.8133068520357
 
*Back porch 48 1.9066534260179
 
*Whole line 800 31.777557100298
 
 
 
Vertical timing (frame)<br>Polarity of vertical sync pulse is negative.  
 
 
 
Frame part Lines Time [ms]<br>
 
 
 
*Visible area 480 15.253227408143
 
*Front porch 10 0.31777557100298
 
*Sync pulse 2 0.063555114200596
 
*Back porch 33 1.0486593843098
 
*Whole frame 525 16.683217477656<br>
 
 
 
<br>  
 
  
= Quick Summary aka SHIIII- too many details&nbsp;:O<br>  =
+
I've cheated, I stole some pixels from the back &amp; front porch and made the horizontal resolution 160*5 and the vertical resolution 144*4 (800x576)
  
The gameboy screen has a resolution of 160x144 and a refresh rate of 60Hz.<br>
+
= Implementation  =
  
To output this to a VGA display, we first need to use a double buffer for correct pixel placement and so we can time the HSYNC.<br>  
+
All of this converting takes place inside an Altera Cyclone II FPGA. This is a fairly cheap FPGA with integrated free configurable memory, and embedded multipliers. <strike>Also, a PLL which we can use to convert the 4MHz pixelclock to a more VGA-like frequency</strike>. The design of the VGA adapter is made using VHDL.
  
Seeing as the gameboy has a unique display ratio we wish to use a resolution for VGA which has a similar display ratio(4:3) to avoid black bars as much as possible.<br>
+
The VGA interface is made using a 3 bit R-2R DAC ladder, for each one of the R, G and B values. Hsync and Vsync are connected directly to the VGA out of the FPGA.<strike>Not having the gameboy connected yet</strike>, we are using a static picture (from an actual Gameboy) which resides in the framebuffer of our design. Some results so far:
  
High resolutions don't add to quality and only make our hardware more complicated.<br>
+
[[Image:FPGAVGA.jpg|300px|FPGAVGA.jpg]]
  
Therefore I've chosen to use 640x480 as it is a universally accepted display resolution.<br>
+
= Results =
  
 +
GREAT&nbsp;SUCCES!
  
 +
[[Image:VGAbeamer.jpg|400x300px|Awesome.]]
  
= Plan of attack! =
+
to be updated..

Latest revision as of 21:58, 3 November 2015

Project: Gameboy VGA adapter
Featured:
State Completed
Members Prodigity, Danny Witberg
GitHub No GitHub project defined. Add your project here.
Description Adding VGA output to a gameboy classic
Picture
FPGAscreen.jpg
Temporary VGAmeboy logo

Introduction

The gameboy classic is a handheld video game device which invokes a feeling of nostalgia into the hearts of many gamers (and non-gamers!).

In total nearly 120 million of these devices have been sold around the world and have delivered uncountable hours of fun (and frustration.. "DAMN YOU MARIO!" heh anyone? :P).

Nowadays the gameboy has been replaced by far more advanced (read: battery-slurping) handheld devices and as such, many people have one lying around collecting dust.

As some of you might remember, the biggest problem with the gameboy classic was the lack of backlighting which caused any form of unwanted lighting to render the screen into a useless plastic mirror.

REJOICE! For I have decided to add VGA output to the gameboy so you can play on 21" screens! (TAKE THAT SUN!) No more visibility problems! (Yes you can add LEDs to the back of the screen, stop being so boring :P).

Before we get down and dirty, you'll need to be sure that you understand the terms used on this page; VGA terminology.


The gameboy

Gameboy specs:

  • Resolution: 160 x 144
  • Refresh rate: 59.7Hz
  • Horizontal Sync: 9.2KHz
  • Bits per pixel: 2 (Black, Dark grey, Light grey or White)
  • Pixel Clock: 4MHz


As you can see we are presented with a refresh rate of 59.7Hz which nearly matches the standard VGA refresh rate. (Most likely close enough, only testing will tell)

The resolution of 160x144 however poses a problem, no such VGA resolution exists and as such we will be forced to pick a different resolution and do some pixel juggling.

The solution? We will use double buffering and a different resolution.


Calculations

Doublebuffer

To determine the size of our buffers we simply take the resolution of the gameboy screen and multiply the amount of horizontal pixels with the vertical pixels and the bpp (160x144x2 = 46080).

The 46080 bits translate roughly to 6 kilobyte.


Resolution

Multiplying horizontal pixels by a float is only a matter of altering the pixel clock.

Multiplying vertical pixels by a float however is difficult as this has to be done with a digital solution.

As such we prefer to use a resolution whose vertical pixels are a multiple of 144. (Any integer)

There so happens to be a resolution which adheres to this: 768x576


VESA signal 768x576 source

General timing

Screen refresh rate 60 Hz
Vertical refresh 35.819672131148 kHz
Pixel freq. 34.96 MHz

To 'convert' 160 pixels to 768 we simply adjust the pixel clock: 34.96 MHz / 768 pixels = x MHz / 160 pixels x = 160 pixels * (34.96 MHz / 768 pixels) = 7.283 MHz So if we use a pixel clock of 7.283 MHz, the 160 pixels will stretch themselves over a width of 768 pixels.

I've cheated, I stole some pixels from the back & front porch and made the horizontal resolution 160*5 and the vertical resolution 144*4 (800x576)

Implementation

All of this converting takes place inside an Altera Cyclone II FPGA. This is a fairly cheap FPGA with integrated free configurable memory, and embedded multipliers. Also, a PLL which we can use to convert the 4MHz pixelclock to a more VGA-like frequency. The design of the VGA adapter is made using VHDL.

The VGA interface is made using a 3 bit R-2R DAC ladder, for each one of the R, G and B values. Hsync and Vsync are connected directly to the VGA out of the FPGA.Not having the gameboy connected yet, we are using a static picture (from an actual Gameboy) which resides in the framebuffer of our design. Some results so far:

FPGAVGA.jpg

Results

GREAT SUCCES!

Awesome.

to be updated..