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
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');