User Tools

Site Tools


info:atmega_vga_control

Using an Atmega 168 or FPGA for VGA

Introduction

This is my first FPGA project. I got this Xilinx Spartan3 FGPA starter kit which came with 5 pins hooked up to a VGA port. Basically all it does is takes the 50MHz clock crystal and halves it to 25MHz. This creates a VGA clock where each pixel is 1 clock cycle. It uses a 10 bit counter for doing the horizontal timing and a 10 bit counter for the vertical timing. Using these counters it calculates when to apply voltage to the horizontal and vertical sync pins and data on the red, green, and blue pins. Coding was all done in VHDL (source code is below).

I have a video of vga2.vhd working on youtube.com: http://www.youtube.com/watch?v=YcRCNr78GuQ.

Also, if you're interested in seeing how I implemented VGA in an SX microcontroller or an Atmel ATmega168 microcontroller, take a look at my SX microcontroller VGA and Atmel VGA projects.

Atmega 168 VGA

First I did VGA with an FPGA, then with the SX Microcontroller, and now with an Atmel ATmega168. This differs from the SX version in that I used interrupts to control the timing. Also, since this chip is 20MHz instead of 50MHz, some of the timings are not quite accurate. Seems to work fine although there is some jitter starting halfway down the screen. Could be fixable. 20MHz is pretty much a bad clock rate for VGA 640×480@60Hz since each pixel clock should be 1 tick of a 25MHz clock. A single scan line now is 800pixels*(20MHz/25MHz) which comes out at an even 640, which is good, but the hsync which should start after 8 25MHz clocks and stop after completing 96 25MHz clocks, come out to non-round numbers (6.4 and 76.8 respectively). Still seemed to work, although like I said, there is some jitter which since this is just a useless proof of concept, I don't feel like working on it any more to fix it :).

Explanation

So how it works: Basically I took all the timings of the FPGA project I did and multipied them by (20/25) to get the timings for a 20MHz clock. I set up 2 interrupts. The first is using the timer compare A, I set it for 640 clocks (equal to 800 25MHz pixel clocks). This gives me pretty nice timing of when a scan line is finished. At this point the timer also resets to 0 again. I then set up interrupts an interrupt at 7 cycles using the timer's compare B. At this point I turn on the hsync pin and do some calculations on my vertical scan since I have about 76 cycles here to play with. I also tell it that compare B is now 84 clocks and change the 16 bit Z register (r30 and r31 combined) so the next ijmp instruction will jump to a different routine. The next routine is the hsync off routine which turns off the hsync, does some more vertical scan calculations and gets ready to draw the playfield. I set the Z register to point to the playfield routine and set compare B to something higher than 122 (playfield starts at 122, but I start drawing a little later to center stuff). The playfield routine draws one scan line. The scan line information is pulled out of flash which is inserted into the source code from an include file that is generated from the Python script included in the zipfile below. When the scan line is done it changes the interrupt information for timer compare B back to 7 cycles and points again to hsync on. Kinda looks like a linked list of interrupt handlers.

info/atmega_vga_control.txt · Last modified: 2009/04/23 14:48 by tomgee