VGA Synchronization Driver for FPGA

Description

In order to use the VGA connection on an FPGA there needs to be a vga timer that can change the pixels as it goes across the screen. I won’t go into detail here about VGA standards, or how the horizontal and vertical refreshes work, but rather just give some example VHDL code that will refresh a screen that is 640 X 480 pixels in size. This can then be declared as an entity in other VHDL code that can generate blocks and other movements on the screen.


Ports

Port Name Direction Width Purpose
clk Input 1 Input clock (50 MHz)
rst Input 1 Asynchronous reset
HS Output 1 Low asserted horizontal sync VGA signal
VS Output 1 Low asserted vertical sync VGA signal
pixel_x Output 10 Indicates the column of the current VGA pixel
pixel_y Output 10 Indicates the row of the current VGA pixel
last_column Output 1 Indicates that the current pixel_x correspond to the last visible column
last_row Output 1 Indicates that the current pixel_y corresponds to the last visible row
blank Output 1 Indicates that the current pixel is part of a horizontal or vertical retrace and that the output color must be blanked. The VGA pixel must be set to “Black” during blanking.

Screen Shot 2013-12-24 at 10.56.10 PM

VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

entity vga_timing is
    Port ( clk : in  STD_LOGIC;
           rst : in  STD_LOGIC;
           HS : out  STD_LOGIC;
           VS : out  STD_LOGIC;
           pixel_x : out  STD_LOGIC_VECTOR (9 downto 0);
           pixel_y : out  STD_LOGIC_VECTOR (9 downto 0);
           last_column : out  STD_LOGIC;
           last_row : out  STD_LOGIC;
           blank : out  STD_LOGIC);
end vga_timing;

architecture vga_timer of vga_timing is

signal pixel_en, row_en, visible, column_intermed: STD_LOGIC;
signal horiz_counter, vertical_counter, nexthcount, nextvcount : unsigned (9 downto 0) := (others=>'0');

begin

--toggle register for pixel en, giving 25MHz clk
process(clk,rst)
begin
if (rst = '1') then 
pixel_en <= '0';
elsif (clk'event and clk = '1') then
pixel_en <= not pixel_en;
end if;
end process;

--horizontal pixel counter register based off of pixel_en
process(clk,pixel_en,rst)
begin
if (rst = '1') then
horiz_counter <= (others => '0');
elsif (clk'event and clk = '1') then
        if (pixel_en = '1') then
        horiz_counter <= nexthcount;
        end if;
end if;
end process;

nexthcount <= (horiz_counter + 1) when (horiz_counter < 799) else
                                        (others => '0');
                                        
pixel_x <= std_logic_vector(horiz_counter);
column_intermed <= '1' when (horiz_counter = 639)
                                        else '0';
row_en <= '1' when (horiz_counter = 799) else 
                         '0';
last_column <= column_intermed;
                                        
HS <= '0' when ((horiz_counter > 655) and (horiz_counter < 752))
                else '1';
                
--vertical pixel counter increments only with last_column
process(clk,rst,row_en)
begin
if (rst = '1') then
vertical_counter <= (others => '0');

Comments are closed.