Monday, 2 February 2015

VGA Output from an FPGA

So after the simple 8 bit counter on the fpga I decided to get started with generating VGA output from my FPGA. Because that seemed to be a reasonably simple yet really cool looking project. Initially I thought I'd go the cheap way and solder up my own VGA circuit. But I just ended up wasting a lot of time and effort to get a really substandard circuit that would die on me all the time. So I got myself one of these VGA modules from the Numato Labs website.

First a bit about VGA signals. VGA was originally intended to work with CRT monitors. So the standard was built around the working of a CRT monitor. These type of monitors use a Cathode Ray Tube(CRT). Inside every CRT is an electron gun that produces a beam of really fast electrons. Electric fields are used to deflect this beam so that it can fall on different positions on a screen. The screen has dots(pixels) with phosphors that glow when hit by electrons and when all of these dots glow.

CRT monitors build up an image by scanning this electron beam horizontally across the screen in one line, then moving the beam a short distance downward and scanning again and again. The image is built up line by line.

So a VGA signal has two clocks called Vertical Sync (VS) and Horizontal Sync (HS). The HS pulses every time the screen starts scanning a new line. And the VS pulses every time the whole screen is scanned once. For more details on VGA signals, visit this page.

The R, G and B, signals have nominal values of 0.7 volts. So 0 volts on the R line means no Red component and 0.7 volts means maximum red component. The inputs have impedances of 75 ohms.

I took a look at the schematic of the VGA module.

You'll notice that there are three pins connecting to the red and green input signal and 2 connecting to the blue input signal. The pins are connected through resistors whose values rise exponentially. This is a simple way to perform DAC. I decided to work through the equations to see what input voltage levels were available to me.

For the Red and Green channels, I took the value of the smallest resistor as $R$ and the input voltage as V and went from there.

$\frac{V-V_1}{4R} + \frac{V-V_2}{2R} + \frac{V-V_3}{R} + \frac{V}{R_L} = 0$ (Using KCL)

Rearranging in terms of $V$ we get:

$V = \frac{V_{cc}}{14 + \frac{4R}{R_L}} (2b_0 + 4b_1 + 8b_3)$ where I set $V_i = V_{CC} b_i$

So after substituting all the numerical values. $(V_{CC} = 3.3V, R_L = 75 \varOmega R = 500 \varOmega)$ I get:

$V = 0.09802(b_0 + 2b_1 + 4b_2)$ where $b_2 b_1 b_0$ is a 3 digit binary number. This allows me to have 8 different shades of red! Following a similar procedure I can get expressions for the other colors. And in total I need 8 bits (3 for red, 3 for green, 2 for blue (poor blue :( (I like using nested parantheses. (I should probably stop now.)))) to represent the color of one pixel. So I have a palette of 256 colors to work with.

Now it's time to get started with generating the VGA sync signals.

I'm learning from this textbook called FPGA Prototyping by Verilog Examples by P. Chu. It has a brilliant section on generating VGA output. However, I couldn't just copy the code in there and check if the circuit was working. I have a small external monitor which I use for testing purposes. It turns out that this monitor (because it's a very cheap monitor) only supports one video mode. 1368 x 768 @ 60 Hz refresh rate. Nothing else works. Following the signal timing information about this resolution from the tinyVGA website, I modified the code (actually I typed it out line by line on my own so I could understand what was going on in each line. I highly recommend this technique when you're learning a new language.)

It took quite a while for me to get the output working properly. First I tried using the ipcore wizard to generate a pixel clock that was exactly the same as the recommended one. But when I tried to get the ISE to compile the code, it complained about timing issues. So I used the ipcore wizard to generate a clock that was exactly twice that of the pixel clock and divided this clock by 2 inside the VGA synchronization module.

Here's a video of the working VGA output:

Now I think I'll get started on generating something interesting on the fpga. Maybe some fractals?