VGA Controller - red-bote/VHDL_Demos GitHub Wiki

This demo uses the VGA Controller tutorial from the DigiKey TechForum presented by Scott_1767 DigiKey Employee. Please checkout that tutorial but any questions about the information on this wiki page should be directed to me.

The following files are used:

The circuit drives 5 signals to the monitor:

  • Red
  • Green
  • Blue
  • Vsync
  • Hsync

The VGA output port consists of 4-bits for each of red, green and blue color components.

In a new Vivado project the following external ports are defined.

Port Name Direction Bus MSB LSB
clk in
reset in 0
sw in Checked 15 0
Hsync out Checked 15 0
Vsync out Checked 15 0
vgaRed out Checked 3 0
vgaGreen out Checked 3 0
vgaBlue out Checked 3 0

In the Basys 3 constraints (.xdc) file the center button btnC is mapped to the top-level reset port and the VGA output port must be enabled:

##Buttons
set_property -dict { PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports reset]
#set_property -dict { PACKAGE_PIN U18   IOSTANDARD LVCMOS33 } [get_ports btnC]

#VGA Connector
set_property -dict { PACKAGE_PIN G19   IOSTANDARD LVCMOS33 } [get_ports {vgaRed[0]}]
set_property -dict { PACKAGE_PIN H19   IOSTANDARD LVCMOS33 } [get_ports {vgaRed[1]}]
set_property -dict { PACKAGE_PIN J19   IOSTANDARD LVCMOS33 } [get_ports {vgaRed[2]}]
.
.
.
set_property -dict { PACKAGE_PIN D17   IOSTANDARD LVCMOS33 } [get_ports {vgaGreen[3]}]
set_property -dict { PACKAGE_PIN P19   IOSTANDARD LVCMOS33 } [get_ports Hsync]
set_property -dict { PACKAGE_PIN R19   IOSTANDARD LVCMOS33 } [get_ports Vsync]

The VGA demo is setup to drive a display screen of size 640x480, requiring a pixel clock of just over 25 Mhz. The VGA clock is derived with a counter dividing the 100 Mhz clock by 4.

Clock Divider

Instantiate clock divider from counters_1.vhd. New signals are added for the counter output, VGA clock, inverted reset, and video on.

architecture Behavioral of vga_top is
    signal clk_count : std_logic_vector(3 downto 0);
    signal clk_vga : std_logic;
    signal reset_l : std_logic;
    signal video_on : std_logic;
    signal RGB : std_logic_vector(23 downto 0);
    signal vga_col : integer;
    signal vga_row : integer;
begin
    u_clkdiv : entity work.counters_1
    port map(
        C => clk,
        CLR => reset,
        Q => clk_count
        );
    clk_vga <= clk_count(1); -- pixel clock set to 25Mhz

VGA Controller

The default timings the VGA controller are for an HDMI screen but is instantiated with generic values set for 640x480 VGA mode. An active low reset_n is generated to match the reset_n input to the controller. The 12-bits of color signals are connected directly to switches allowing the screen to be filled with any combination of 4-bit red green and blue.

    reset_l <= not reset;
    u_vga_control : entity work.vga_controller
        GENERIC map (
            h_pulse  => 96,
            h_bp     => 46, -- verify
            h_pixels => 640,
            h_fp     => 16,
            h_pol    => '0',
            v_pulse  => 2,
            v_bp     => 33,
            v_pixels => 480,
            v_fp     => 10,
            v_pol    => '0')
        port map(
            pixel_clk => clk_vga, -- 25 Mhz
            reset_n => reset_l,
            h_sync => Hsync,
            v_sync => Vsync,
            disp_ena => video_on,
            column => vga_col,
            row => vga_row,
            n_blank => open,
            n_sync => open
        );
    vgaRed    <= sw(11 downto 8) when video_on = '1' else (others => '0');
    vgaGreen  <= sw(7 downto 4) when video_on = '1' else (others => '0');
    vgaBlue   <= sw(3 downto 0) when video_on = '1' else (others => '0');

pixel_x and pixel_y provide the current location of the raster scan, but are not required for this simple demonstration and may be wired to open.

The video_on signal is active only while the raster scan location is within the viewable area of the display.

Test Image

Import hw_image_generator.vhd.

Instantiate the image generator in the top-level.

    -- output of image generator is 24-bit RGB
    signal RGB : std_logic_vector(23 downto 0);
    -- raster-scan location is used to locate the image on screen
    signal vga_col : integer;
    signal vga_row : integer;
.
.
.
    -- instantiate the image generator block
    u_image_gen : entity work.hw_image_generator
    generic map(
        pixels_y => 240,
        pixels_x => 320)
    port map(
        disp_ena => video_on,
        row => vga_row,
        column => vga_col,
        red => RGB(23 downto 16),
        green => RGB(15 downto 8),
        blue => RGB(7 downto 0)
    );
    -- connect upper 4-bits of each color to output ports
    vgaRed <= RGB(23 downto 20);
    vgaGreen <= RGB(15 downto 12);
    vgaBlue <= RGB(7 downto 4);

The image generator was written for a system that used 8-bits for each color. For the Basys 3, the upper 4-bits of each color are connected to the external RGB output ports.

The complete demo project can be found in the VHDL Demos repo.

Next