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. |
VHDL
[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’);
[/vhdl]