Programming pattern to generate VGA signal with micro-controller?

I want to generate VGA signal with micro-controller (like TI Tiva ARM which runs at 90/120Mhz speed).

I'm not sure how to make accurate timings with micro-controller. Which programming pattern I need to use?

Do I need any inline assembler code? How to wisely use interrupts?

Would be great if anybody show some pseudo code how to generate VGA signal.

I successfully generated VGA signal with FPGA. But I just can't figure out how to do it with MCU.

• There are VGA libraries for AVR. Different microcontroller, but you might get some inspiration from it. You might be able to utilize the DMA controller to offload the main CPU, because generating a video signal is pretty CPU intensive without these sort of tricks. Apr 17, 2016 at 6:04

This answer is all based on standard VGA screens, which are 640 x 480 since that was what you referenced in your answer. Timing for SVGA (super VGA, 800 x 600), XGA (1024 x 768) and so on is going to be different. This page has a good list of virtually all the resolutions in use. But the pixel timing for these bigger screens is going to be so fast I doubt you could generate it using a micro.

VGA Timing

So the standard VGA screen is 640 pixels horizontally and 480 lines vertically. To generate the timing, a 25.175 MHz pixel clock is used. (Theoretically, this means the micro would need to be able generate pulses that are exactly 39.72 ns long, which would be rather difficult, but it seems you can get by with 25 MHz and 40 ns clocks.

The format of VGA timing for each line dates back to CRT computer screens days and before that television sets. It looks like this for a 640x480 picture (just the horizontal shown here):

There are two synchronization pulses -- one per line (horizontal sync) and one per frame (vertical sync). The horizontal sync pulse is preceded by a "back porch interval, and followed by a "front porch" interval. In between these two is the active video (640 pixels). The total line though is 800 pixels wide.

Likewise, the vertical lines have a sync pulse at the bottom, surrounded by a vertical back porch and front porch and is 524 pixels high.

Back when video was done using CRT's instead of LCD screens, there was an electron beam that scanned across the screen for each line, which then moved down a bit, scanned the next line etc. At the bottom of the screen, it had to zip back to the top.

At the end of each line, the beam has to move back to the beginning of the next line -- this takes a little time. During this time the video was blanked. This is known as the horizontal refresh time, and is the sum of the back porch+sync+front porch timing. Likewise for the vertical refresh period. That's why there is a total of 800 pixels across the screen, and 524 lines vertically, even though you only see 640x480.

The timing then can be specified in terms of clock pulses:

where HPX are the 640 pixels, HFP is the horizontal back porch interval, HSP is the horizontal sync pulse, HBP is the horizontal back porch interval. Likewise for the vertical. This what you need to use for your timing in the microcontroller (assuming you have a 40 ns clock).

So each full line is 800 clocks, or 800 x 40 ns = 32 µs.

Note that the critical timing only occurs when writing pixels to the screen (12 bits every 40 ns). While writing out the pixels you're not going to have much time to do anything else. But during the front porch, sync pulse, and back porch you've got 635 ns, 3.81 µs, and 1.9 µs respectively for doing other stuff.

Note that if you don't have a processor fast enough to generate 40 ns pixels, you can divide everything in half (essentially running at 12.5 MHz, or a 80 ns clock) and you will have 320 x 240 resolution. So each pixel is repeated twice as far as the monitor is concerned. It still thinks you're sending VGA.

VGA Output

To generate the video signals for each pixel, you can make your own DAC (digital to analog converter) using resistors. If you allocate 4 bits per color (RGB) you will need 12 resistors in total, arranged so:

You could get by with less bits, for example 3 bits per color, or even 2, but the picture quality won't be as good.

Firmware

Assume we have a 100 MHz 32-bit processor (10 ns per instruction). Also assume we are using 12 bit pixels, stored two pixels to a 32-bit word (so we waste 8 bits unfortunately).

Before starting, assume r0 is loaded with the address of the starting 32-bit word containing pixels for this line, and r1 is loaded with address of a memory mapped I/O port, of which the lower 12 bits D0-D11 are brought out, and r2 is a temporary holding two pixels.

I'm using a made-up RISC-like instruction set, but it should be pretty obvious what is going on. Assume each instruction takes one cycle, or 10 ns.

ld r2,[r0]      ; load indirect through register r0, 32 bits (2 pixels)
andi r2,0xFFF   ; and immediate, get lower 12 bits
st r2,[r1]      ; store pixel to I/O port
ld r2,[r0]      ; get pixel again
rsh r2,16       ; right shift 16 bits to get upper pixel
andi r2,0xFFF   ; and immediate, get lower 12 bits
st r2,[r1]      ; store pixel to I/O port


If the processor is faster than 100 MHz, you will need to add nops so the entire sequence still takes 80 ns for two pixels.

You repeat this sequence of eight instructions 320 times inline. At the end, set up an interrupt for 635 ns in the future (end of back porch) and return from the interrupt level (entered when you started sending you pixels) In the meantime you've got 63 instructions free for the base level.

At the interrupt (end of back porch), generate the beginning of the horizontal sync pulse (goes low) and set another interrupt this time 3.81 µs in the future (end of horizontal sync) and exit from the interrupt. You can execute about 380 instructions this time.

At the interrupt (end of horizontal sync), complete the horizontal sync (goes back high), set an interrupt for 1.9 µs in the future (end of front porch) and return from the interrupt. 190 or so more instructions available.

At the final interrupt (end of front porch), start outputting pixel data again (all in the interrupt routine).

Similar code to handle the end of the frame (vertical sync etc.).

Except for the horizontal retrace time, all of this is just to copy the pixels from the RAM to the screen. There would be an additional 32 µs * 44 lines or 1.408 ms during the vertical retrace available, or 140,800 instructions for other stuff. But this, added with the extra instructions available during the horizontal retrace (304,000) would still not be fast enough to generate a full frame of video for the next time at the full 640x480 resolution. You would really need at least a 200 MHz processor to both generate video and copy it to the VGA output.

It's no wonder PCs come with specialized graphics hardware from the very beginning that writes the contents of a video RAM out to a video port (VGA or whatever) without the assistance of the main processor..

• Actually very helpful information. But can give more details about software side. I need timer with 25 Mhz frequency ? Thanks Apr 17, 2016 at 7:12
• @kesrut Yes. You're going to need a very fast processor. A 200 MHz processor would be 5 ns per instruction (assuming one cycle/instruction), or 8 instructions per pixel clock. Not a lot of time. Note the multi-core Parallax Propeller has special timers so it can generate VGA output in one core, while you have 7 more cores for other stuff. You might want to consider that as a co-processor. Here's a demo and another. Apr 17, 2016 at 7:47
• @kesrut Actually a 100 MHz (or even 76 MHz) processor will do; see the update to my answer. Apr 17, 2016 at 10:04
• People have done it with overclocked atmel microcontrollers: tinyvga.com/avr-vga Apr 17, 2016 at 10:41
• @PeterGreen Agree, I explain this pretty well in my answer in the Firmware section. Updating the active video requires code of 3 or 4 instructions per pixel, so a total of 1920 - 2560 in-line lines of assembly code depending on the processor clock (76 or 100 MHz). Other activity can take place during the front porch, sync period, and back porch periods -- a total of 5.71 µs per line. If you had a 200 MHz processor (8 instructions per pixel) you'd be able to use a loop and wouldn't need two thousand lines of in-line code. But no interrupts allowed (actually this is taking place inside an ISR). Apr 17, 2016 at 14:35

Some projects are using an i2s or spi port to drive each color. The tiva C has a parallel port with dma/fifo to stream the pixel data.

• Welcome to EE.SE. Proper capitalisation would help make your post more readable. It's rather short on detail. Sep 2, 2020 at 14:38
• Using on-chip peripherals to do the precise timing is indeed far better than using the CPU core! Questions on an SE site aren't allowed to ask for the actual code to implement something, anyway - rather the point is to provide the method based on which someone can go and write code, and this does indeed point in a promising direction. Sep 2, 2020 at 15:10