5
\$\begingroup\$

I want to generate VGA signal with microcontroller. But I have hard time finding solution online how to generate them in software. For e.g. Usually all online VGA signal generation just explains timing requirement for HSYNC and VSYNC along with back and front porch timing with for some fixed values like 640x480@60Hz or 1024x786@70Hz etc. But what is not given is how to calculate them and pixel clock and other things. So, how to calculate timing for VSYNC and HSYNC along with front and back porch for any random resolution at some random refresh rate for e.g. 480x240@60Hz?

Thanks for answers. Ashutosh

\$\endgroup\$

3 Answers 3

4
\$\begingroup\$

It is easy enough to calculate all you need from just the basic provided information.

For instance, the site I use most for a reference is this one: http://tinyvga.com/vga-timing/640x480@60Hz and it has all you need for 640x480 @ 60Hz (it specifies most common resolutions, but that's the simplest to work with).

It specifies everything in pixels and lines, and it provides a pixel clock frequency, as well as refresh frequencies. All you need though is the pixel clock and the number of pixels for each thing.

For instance, it gives a pixel clock of 25.175 MHz. That is not easy for most microcontrollers to generate, since it's both high frequency and high resolution - in general you can have one of those two - high frequency or high resolution. However, 25MHz is usually easy enough to generate, and is "close enough" for most monitors to cope with.

So we have a 25MHz pixel clock. We also have a "whole line" size of 800 pixels. That size includes the porches, sync and visible area. So a line of 800 pixels, at 25MHz clock, would be running at (25,000,000/800) 31250 Hz, or one line every 32µS.

The horizontal sync pulse - 96 pixels - would be (96/25,000,000) = 3.84µS long.

We know that a line takes 32µS, and there are 525 lines in a "whole frame", so 0.000032×525 = 0.0168s for a frame, or 59.524Hz. That's pretty close to the 60Hz for the specification.

So given a pixel clock, and a set of pixel periods, you can calculate anything. Of course, you can also go backwards. Given a frame rate and a resolution you can work out:

$$ 60Hz × 525 = 31500Hz $$

$$ 31500Hz × 800px = 25.2MHz $$ So that shows that even the given specifications aren't 100% exact, but there is a bit of flexibility in the VGA timings so you can bend your clock to suit you within certain bounds.

And while we're at it, generating VGA purely with software takes a lot of processing and often leaves you starved of CPU cycles to do anything. One of the most common "tricks" for making a VGA signal on a CPU is to use SPI to generate the pixel data stream. Even better if you have DMA in your microcontroller to output an entire line of data without the CPU having to do anything. The CPU is then just responsible for generating the sync pulses and loading the DMA system with the right addresses - the rest is done in the background. Of course, that leaves you with just a 1-bit monochrome display. If you happen to have an SQI interface, and enough RAM, you could make a 4-bit display (16 colours) easy enough.

\$\endgroup\$
3
  • \$\begingroup\$ That's helpful!!! SO, taking example of 640x480 in the link u shared, so the front porch should be 1/40th of horizontal pixels and so on. So, can i use 12 pixels for width of 480 horizontal pixels since there is no perticular formula? \$\endgroup\$
    – Ashutosh
    Nov 2, 2014 at 19:14
  • 1
    \$\begingroup\$ 480 is not a proper width for a recognized resolution. The trick here is to change the pixel size. Keep (say) 640x480 as your real resolution, but don't output the pixels at the same speed in your visible area. So although the visible area takes the same time as 640 pixels, you're actually outputting 480 pixels that are a bit slower in the same amount of time (if that makes sense) \$\endgroup\$
    – Majenko
    Nov 2, 2014 at 19:18
  • \$\begingroup\$ ok, that is logical. Thanks for the info Majenko! :) \$\endgroup\$
    – Ashutosh
    Nov 2, 2014 at 20:16
1
\$\begingroup\$

Although it doesn't provide the formulas, this page has a calculator that allows you to select from a list of either VGA or SVGA (up to 1920 x 1080), and it displays and a dozen or so different parameters. You can then modify any of these paramters manually, and it will re-calculate items like sync frequencies, pulse lengths, etc.

This page is another one that just has tables of parameters for various resolutions, in four tables with over a hundred different entries total.

\$\endgroup\$
0
\$\begingroup\$

This is a tricky question because it's so tightly coupled with whatever MCU architecture and picture generating circuitry you are using. I've done it by starting to define macros that allow me to calculate various useful things, such as clock cycles per line etc, and then adapt those to the hardware I'm using.

Here's a snipped of code I've written for the purpose. In all likelihood it's not going to be useful to you as such, but it might show a possible approach to the problem.

/// Crystal frequency in MHZ (float, observe accuracy)
#define XTAL_MHZ 3.579545
/// Line length in microseconds (float, observe accuracy)
#define LINE_LENGTH_US 31.777557 
/// Frame length in lines (visible lines + nonvisible lines)
#define TOTAL_LINES 525
/// Number of visible lines in frame (excluding any border areas)
#define VISIBLE_LINES 480
/// Number of lines used for VSYNC
#define SYNC_LINES 2
/// Number of lines used after the VSYNC but before visible area
#define FRONT_PORCH_LINES 10

#define HSYNC_WIDTH_XTALCLKS 14
#define BACKPORCH_BORDER_XTALCLKS 14

#define FRONTPORCH_BORDER_XTALCLKS 12
/// Number of visible pixels (excluding any border areas)
#define VISIBLE_PIXELS 100
/// Width, in PLL clocks, of each pixel
#define PLLCLKS_PER_PIXEL 8
/// How many bits per pixel - this must match with the pattern generator microcode
#define BITS_PER_PIXEL 16

#define WORDS_PER_LINE ((VISIBLE_PIXELS * BITS_PER_PIXEL + 15) / 16)
#define FIRST_LINE (SYNC_LINES + FRONT_PORCH_LINES)
#define PLL_MHZ (XTAL_MHZ * 8.0)
#define PLLCLKS_PER_LINE ((u_int16)((LINE_LENGTH_US * PLL_MHZ)+0.5))
#define COLORCLKS_PER_LINE ((u_int16)((LINE_LENGTH_US * XTAL_MHZ)+0.5))
...and so on...
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.