FPGA VGA

From Hamsterworks Wiki!

Jump to: navigation, search

Generating a VGA display is one of the first things most people who start playing with FPGAs try.

Usually this is limited to the standard 640x480 or maybe 800x600 modes, due to the nice pixel clocks of 25MHz or 50MHz.

I've been using a 19" Widscreen, and had a go at 1440x900 too - which needs a pixel clock of 106MHz.

Here is the Code.

 ----------------------------------------------------------------------------------
 -- Module Name:    vga1440x900 - Behavioral 
 -- Version:        1.0
 -- Author:         Mike Field (hamster@snap.net.nz)
 -- 
 -- Generate 1440 x 900 x 256 colour VGA signals.
 --
 -- Horizontal timing (frame)
 -- Scanline part	Pixels	Time [┬Ás]
 -- Visible area	1440	13.52493660186
 -- Front porch		80		0.75138536676998
 -- Sync pulse		152	1.427632196863
 -- Back porch		232	2.1790175636329
 -- Whole line		1904	17.882971729126
 --
 -- Vertical timing (frame)
 -- Polarity of vertical sync pulse is positive.
 -- Frame part		Lines	Time [ms]
 -- Visible area	900	16.094674556213
 -- Front porch		1		0.017882971729126
 -- Sync pulse		3		0.053648915187377
 -- Back porch		28		0.50072320841552
 -- Whole frame		932	16.666929651545
 ----------------------------------------------------------------------------------
 library IEEE;
 use IEEE.STD_LOGIC_1164.ALL;

 use IEEE.NUMERIC_STD.ALL;
 use IEEE.STD_LOGIC_UNSIGNED.ALL;

 entity vga1440x900 is
  port ( Clk      : in    std_logic; 
         Hsync    : out   std_logic; 
         vgaBlue  : out   std_logic_vector (2 downto 1); 
         vgaGreen : out   std_logic_vector (2 downto 0); 
         vgaRed   : out   std_logic_vector (2 downto 0); 
         Vsync    : out   std_logic
        );
 end vga1440x900;

 architecture Behavioral of vga1440x900 is
   COMPONENT ClockGen
   PORT(
     CLKIN_IN : IN std_logic;          
     CLKFX_OUT : OUT std_logic;
     CLKIN_IBUFG_OUT : OUT std_logic;
     CLK0_OUT : OUT std_logic
   );
   END COMPONENT;

   signal clk106M	 : std_logic;
   signal hcounter : std_logic_vector(10 downto 0) := (others => '0');
   signal vcounter : std_logic_vector(9 downto 0)	:= (others => '0');
   signal sx		 : std_logic_vector(10 downto 0) := "00000100000";
   signal sy 		 : std_logic_vector(9 downto 0)  := "0000100000";
 begin
   -- Generated IP core to convert the clock up to 106MHz using two DCMs 
   Inst_ClockGen: ClockGen PORT MAP(
     CLKIN_IN => clk,
     CLKFX_OUT => clk106M,
     CLKIN_IBUFG_OUT => open,
     CLK0_OUT => open
   );

   process(hcounter, vcounter)
   begin
     vgaRed 	<= "000";
     vgaBlue	<= "00";
     vgaGreen <= "000";
     hSync 	<= '1';
     vSync 	<= '0';

     if vcounter < 900 then
       if hcounter < 1440 then
         if vcounter < 10 or vcounter > 889 or hcounter < 10 or hcounter > 1429 then
           vgaRed  <= "000";
           vgaBlue <= "11";
           vgaGreen <= "000";
         end if;
       end if;
     end if;

     if hcounter > 1519 and hcounter < 1672 then
       hsync <= '0';
     end if;

     if vcounter > 900 and vcounter < 904 then
       vSync <= '1';
     end if; 		
   end process;
	
   process(clk106M)
   begin
     if clk106M'event and clk106M = '1' then
       if hcounter = 1903 then
         hcounter <= (others => '0');
         if vcounter = 931 then
           vcounter <= (others => '0');
         else
           vcounter <= vcounter+1;
         end if;
       else
         hcounter <= hcounter+1;
       end if;
     end if;
   end process;
 end behavioral;

This has a few flaws - as the DAC is generated by combinatorial logic it can suffer from 'hazards' and other timing issues if it gets too complex. Buffering all outputs would solve this.

Personal tools