Goal & Data I am trying to make a VGA driver on a Spartan 6 (Embedded Micro Mojo board) to display something simple like the french flag on an LCD monitor, in 640x480 8 colors. I live in Europe and the monitor is 16:10 if it's important.

Wiring I wired hsync&vsync to my monitor following this diagram, and wired the R G and B signals to a 0.7V power supply to start with. I assume that voltage is the maximum (many people say it is at least), giving white.

Symptoms Launching the following code gives a black screen. No "Out of range [31kHz 40Hz]" message appears (like it did when I had a timing error), and if I make a poor contact with the 0.7V on any color pin (meaning, shivering a bit), random stripes of the corresponding color very briefly appear - if the contact is good the screen becomes pitch black again.

Question I think I have an idea of why it doesn't work, in my opinion it's the fact the colors are never switched back to black at the end of the period as the protocol suggests. If I am right (if I am not then why?), why is that necessary to form an image? The way I see it, it's only about applying the colors at the right time and resetting the vertical/horizontal plates ramp at the right time...


library IEEE;

entity main is
    Port ( 
              clk : in  STD_LOGIC;
           hsync : out  STD_LOGIC;
           vsync : out  STD_LOGIC;
           r : out  STD_LOGIC_VECTOR (2 downto 0) := "000";
           g : out  STD_LOGIC_VECTOR (2 downto 0) := "000";
           b : out  STD_LOGIC_VECTOR (1 downto 0) := "000"
end main;

architecture Behavioral of main is
    signal hcounter : integer := 0;
    signal vcounter : integer := 0;
    signal tick : STD_LOGIC := '0';

    clk_process : process(clk)
        if(rising_edge(clk)) then
            tick <= not tick;
            if(tick = '1') then         -- Happens at 25MHz (50MHz / 2)

                -- Reset the counter if column/line finished or increment it
                if(hcounter = 799) then
                    hcounter <= 0;
                    if vcounter = 524 then
                        vcounter <= 0;
                        vcounter <= vcounter + 1;
                    end if;
                    hcounter <= hcounter + 1;
                end if;

                -- Send a pulse of vsync to start a new column
                if vcounter >= 490 and vcounter < 492 then
                    vsync <= '0';
                    vsync <= '1';
                end if;

                -- Send a pulse of hsync to start a new line
                if hcounter >= 656 and hcounter < 752 then
                    hsync <= '0';
                    hsync <= '1';
                end if;

                -- If pixel time, draw something
                if hcounter < 640 and vcounter < 480 then
                    --display a colour on the RGB signals once I have opamps to get them through
                    --if hcounter < 213 then
                        -- Blue line
                        --b <= "111";
                        --r <= "000";
                        --g <= "000";
                    --elsif hcounter < 426 then
                       -- White line
                        --r <= "111";
                        --g <= "111";
                        --b <= "111";
                        -- Red line
                        -- r <= "111";
                        -- g <= "000";
                        -- b <= "000";
                    --end if;
                    --display black colour on the RGB signals
                    -- b <= "000";
                    -- r <= "000";
                    -- g <= "000";
                end if;
            end if;
        end if;
    end process;

end Behavioral;

What I understand

And might be wrong, see the following picture. Based on this, the aspect ratio and the full resolution vertical refresh rate is not important now is it (since with a smaller picture the refresh rate is higher) ? enter image description here

  • 1
    \$\begingroup\$ There a 3 PLL's in LCD monitors/TV's. V, H and pixel edge min. interval. There may be dozens of ratios acceptable, but your rates were out of range. If pixel rate is 25 MHz and H is 31k so P/H=806 (800 actual) then it expects V rate to be 525 H clocks +\-10% but it wasn't. H/V was 775 \$\endgroup\$
    – user38637
    Commented Apr 20, 2014 at 19:14
  • \$\begingroup\$ So you are telling me the entire area of monitors has to be scanned otherwise the monitor rejects the signal? Therefore if I keep the same back/front porches and change my Vcounter to reset at 775 will it work (sorry I can't try now...)? In that case why doesn't my monitor say "Out of range", like it did when I had another error? Or why do the colors kind of display when the connection on R G B lines is not stable? \$\endgroup\$ Commented Apr 20, 2014 at 19:56
  • 1
    \$\begingroup\$ Sometimes displays use the off-screen signal levels to set the 'black level'. If the 'black level' corresponds to the color you want to display, then all you get is black. Now, I have no idea if this particular display sets the black level like that or not, but I would recommend following the protocol exactly. \$\endgroup\$ Commented Apr 20, 2014 at 21:01
  • \$\begingroup\$ LCD TV's like PC monitors can handle a wide variety of modes, ideal is the native mode using the same number of pixels in the same aspect ratio. But also older legacy rates and higher rates and will accept the analog inputs. The video level after sync is used for black level clamping called the back porch. There is no set rule but 800x600 is universal, in many cases so is 640x480 but this very low resolution 307.2 k pixels for a HDTV that supports 1920x1080 =2.07 Mpix, be it 1080p or 1080i, so there is no rule all TV's must support VGA. \$\endgroup\$
    – user38637
    Commented Apr 21, 2014 at 0:48
  • 1
    \$\begingroup\$ Also, I notice that the blue signal (b) is only two bits wide so your assignments to b should be adjusted accordingly. \$\endgroup\$
    – aja
    Commented Apr 21, 2014 at 7:12

2 Answers 2


The pixel clock rate needs to be adjusted to achieve Vsync rates and Hsync rates that are acceptable for your multisync monitor.

Since 40Hz is not a common Vsync rate, try 30, 50 or 60 or higher.

640*480 * 40Hz = 12.3MHz so it seems pixels are pushed out at 1/2 of 25MHz clock rate

The NTSC timing for V Sync , front porch (480~494) , Hsync, back porch(495~525) as follows using 25MHz enter image description here Hsync can be varied as long with before after periods as long as sum is same. Some monitors have a 10% tolerance depending design.

  • \$\begingroup\$ Thanks for your answer. That code is already set up to provide a 25MHz pixel clock, 60Hz vertical sync rate, which gives a 31.5kHz horizontal sync rate. I was surprised to see 40Hz on that screen, but I assume it has something to do with the aspect ratio (the monitor is not 4:3 but 16:10). The resulting picture should be smaller than the available real estate but still displayed, right? \$\endgroup\$ Commented Apr 20, 2014 at 17:05
  • \$\begingroup\$ The Sync rates are not what you expected, change TV mode to 4x3 or stretch. Verify sync freq. it appears pixel rate is only 12.3 MHz .. Yet H / V ratio is not 640 how many pixels are allocated for H sync and V sync \$\endgroup\$
    – user38637
    Commented Apr 20, 2014 at 17:19
  • 2
    \$\begingroup\$ Verify pixel rate with scope. Something wrong here \$\endgroup\$
    – user38637
    Commented Apr 20, 2014 at 17:30
  • \$\begingroup\$ Thanks for the diagram, they're always worth a thousand words. For this reason I uploaded a diagram of what I understand, because I still don't know why the 40Hz and the aspect ratio is an issue. I'll try with 4/3 on tuesday, I don't have the rig at hand (only the board). I simulated the design with ISim though and all the signals are correct (25MHz clock, and all timings to specs). \$\endgroup\$ Commented Apr 20, 2014 at 18:20

@alex.forencich gave the right answer in the comments: the black color is registered outside of the visible area, and since for my test setup I had wired every analog input to maximum luminance (0.7V) the black was registered as the same signal which was sent in the active region => black. I measured the input impedance of the monitor (apparently this 100ohm is standard), and added appropriate resistors (4R, 2R, R, where 7R makes a voltage divider with the input resistance) on the R(0 to 2) G(0 to 2) B(0 to 2) to get the appropriate voltage. Without changing anything about the counters, I managed to print my french flag. Thanks, if you post an answer I'll accept it.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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