# VGA driver not working

I am at the moment trying to make an vga driver for my FPGA, but something isn't going right, and I can't seem to find out what is going wrong...

The code is based on this code example: Example VGA controller

Here is my code: (I've only changed the resolution and some variable names, other than that it should be exactly the same.)

    ----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 03/07/2016 08:53:44 AM
-- Design Name:
-- Module Name: vga - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
--
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity vga is
GENERIC(
constant HR:integer:=640;--Horizontal Resolution
constant HFP:integer:=16;--Horizontal Front Porch
constant HBP:integer:=48;--Horizontal Back Porch
constant HRet:integer:=96;--Horizontal retrace
h_pol    :  STD_LOGIC := '0';   --horizontal sync pulse polarity (1 = positive, 0 = negative)

constant VR:integer:=480;--Vertical Resolution
constant VFP:integer:=10;--Vertical Front Porch
constant VBP:integer:=33;--Vertical Back Porch
constant VRet:integer:=2;--Vertical Retrace);
v_pol    :  STD_LOGIC := '0'  --vertical sync pulse polarity (1 = positive, 0 = negative)

);
Port ( clk : in STD_LOGIC;
LED0: out std_logic;
vga_r: out std_logic_vector(4 downto 0);
vga_g: out std_logic_vector(5 downto 0);
vga_b: out std_logic_vector(4 downto 0);
vga_vs: out std_logic;
vga_hs: out std_logic);
end vga;

architecture Behavioral of vga is
signal COUNT : integer range 0 to 100000000;
constant x_counter:  integer := HR + HFP + HBP + HRet;
constant y_counter:  integer := VR + VFP + VBP + VRet;
signal newCounter: integer range 0 to 4 := 0;
signal newClk: std_logic;
begin

alive: process(CLK)
begin
if rising_edge(CLK) then
COUNT  <= COUNT + 1;

if COUNT = 100000000 then
COUNT <= 0;
end if;

if COUNT < 100000000/2 then
--     LED0 <=  '1';
else
--     LED0 <= '0';
end if;
end if;
end process;

prescaler: process(clk)
begin
if rising_edge(clk) then
newCounter <= newCounter +1;
if newCounter = 4  then
newClk <= ‘1’;
newCounter <= 0;
else
newClk <= ‘0’;
end if;
end if;
end process;

screen:process(newClk)
VARIABLE h_count  :  INTEGER RANGE 0 TO x_counter - 1 := 0;  --horizontal counter (counts the columns)
VARIABLE v_count  :  INTEGER RANGE 0 TO y_counter - 1 := 0;  --vertical counter (counts the rows)
begin
-- Horizontal 640
-- Vertical 480
if rising_edge(newClk) then
-- Increase Horizontal counter
if (h_count < x_counter - 1 ) then
h_count := h_count + 1;
else
h_count := 0 ;
-- Increase Vertical counter
if (v_count < y_counter - 1 ) then
v_count := v_count + 1;
else
v_count := 0 ;
end if;
end if;

--horizontal sync signal
IF(h_count < HR + HFP OR h_count > HR + HFP + HRet) THEN
vga_hs <= NOT h_pol;    --deassert horiztonal sync pulse
LED0 <= NOT h_pol;
ELSE
vga_hs <= h_pol;        --assert horiztonal sync pulse
LED0 <= h_pol;
END IF;

--vertical sync signal
IF(v_count < VR + VFP OR v_count > VR + VFP + VRet) THEN
vga_vs <= NOT v_pol;    --deassert vertical sync pulse
ELSE
vga_vs <= v_pol;        --assert vertical sync pulse
END IF;
end if;
end process;

vga_r <= "11111";
vga_g <= "000000";
vga_b <= "00000";

end Behavioral;

• "- What happens?" "- It's not working." – pipe Mar 8 '16 at 19:35
• Well.. the screen goes black.. I would expect to display red since all those pins are high – Carlton Banks Mar 8 '16 at 19:41
• Assuming that you've verified that your H and V sync timing and polarity is correct, it's possible that your monitor is outsmarting you -- many modern monitors refuse to display a VGA signal that doesn't have any detectable horizontal and vertical blanking in the analog video channels. – Dave Tweed Mar 8 '16 at 20:12
• The monitor works with VGA - signal, I have tested it with an bit file which was working... The clk freq = 125 mhz The pre scaler scales the clock down to 25 mhz which is those setting (I intended to use) The resolution i am trying to recreate is 640 x 480 – Carlton Banks Mar 8 '16 at 20:21
• The signal used to provide blanking in the Example VGA controller is disp_ena which tells you when you're not blanked. When disp_ena is not '1' in hw_image_generator.vhd then r,g and b are '0' (black). In an analog display the color is sampled during the horizontal retrace interval to determine where set black. – user8352 Mar 9 '16 at 0:03

You assign constant values to your VGA color lines, which will not work.

An analog VGA monitor expects to see a reference "black" level during part of the off-screen duration of the trace. If you drive a substantially non-zero value there, it will adapt to the idea that this voltage means black, and you will not get the expected rectangle of color (on some monitors, you might get a brief flash of color upon connection, before going to all black).

You will need to toggle your color lines between the desired color and black during the periods of time when they should be signalling color in the active area or black reference outside of it.

Two very useful tools will be a timing diagram of what VGA should look like, and if possible an oscilloscope comparing your signal to that of a VGA card setup to output something similar (full color screensaver?)

• Soo.. I am not sure quite understand when you want me to toggle the color from one state to another. – Carlton Banks Mar 8 '16 at 23:07
• The simplest approach is to drive the lines to black anytime the trace is not within the rectangle of the screen that you are trying to paint red. It's quite a bit easier if you just paint a 640x480 rectangle and not try to color the overscan, though with more careful attention to a VGA timing diagram that may(?) be possible. – Chris Stratton Mar 9 '16 at 0:03

As already mentioned by Chris Stratton et.al., you have to set the color to black during the blanking intervals. This was achieved by the signal disp_ena in the example design linked in your question.

To add such behaviour to your design, you have to:

1) Add a new signal disp_ena in the architecture declaration part:

signal disp_ena : std_logic;


2) Set this signal clock-synchronous to '1' when the image is displayed, and to '0' otherwise (during blanking).

screen:process(newClk)
-- ... existing code
begin
if rising_edge(newClk) then
-- ... existing code

--set display-enable control signal
IF(h_count < HR and v_count < VR) THEN
disp_ena <= '1';
ELSE
disp_ena <= '0';
end IF;
end if;
end process;


3) Set color to red only when display is enabled (disp_ena = '1') otherwise black. Thus, change the existing lines to:

vga_r <= "11111" when disp_ena = '1' else (others => '0');
vga_g <= "000000" when disp_ena = '1' else (others => '0');
vga_b <= "00000" when disp_ena = '1' else (others => '0');


You are generating a new clock signal using a counter. This is not good design practice. You should use one of the PLLs on the FPGA instead. You can create a proper instantiation via the Xilinx IP Core Generator.

If you want to stick with the counter, then you have two options:

1) Use a BUFG component to minimize the skew on the clock network newclk. To use this component, you need to include:

library unisim;
use unisim.vcomponents.all;


Then instantiate the BUFG via:

newclk_bufg: BUFG (I => newclk, O => newclk2);


Then use newclk2 to drive the registers.

2) Use newclk as a clock-enable signal instead of a clock signal. The screen process will then trigger on CLK, but loading the new register values will happen only if newclk is high:

screen:process(CLK)
-- ... existing code
begin
if rising_edge(CLK) then
if newclk = '1' then   -- newclk used as clock-enable here
-- ... existing code
end if;
end if;
end process;


Also check if you have specified the correct timing constraints for the clock CLK in the UCF file (ISE) or XDC file (Vivado).

• still not working.. – Carlton Banks Mar 14 '16 at 11:59
• @dfh the generation of newclk might be a problem as now discussed in my extended answer. – Martin Zabel Mar 14 '16 at 16:08
• Well.. code posted above doesn't show anything properly. The screen says that the input is not supported. – Carlton Banks Mar 14 '16 at 18:32
• Which solution for newclk have you tried? Does the screen says anything about a wrong frequency? Are you sure, that the input frequency for your FPGA is 125 MHz? – Martin Zabel Mar 14 '16 at 20:35