vhdlclockxilinxvgaspartan

Why my VHDL code for generating a VGA signal doesn't work


I have been going crazy trying to make it work but nothing been on this for the past 6 hours and still didn't solve it :/

so this the top module

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity Test is
  Port ( CLKI : in  STD_LOGIC;
         HSO : out  STD_LOGIC;
         VSO : out  STD_LOGIC;
         RO,GO,BO : out  STD_LOGIC);
end Test;

architecture Behavioral of Test is
  component CLK_25Mhz_Divider
    Port ( CLK : in  STD_LOGIC;
           CLK_OUT : out  STD_LOGIC);
  end component;

  component VGA_Sync
    Port ( CLK : in  STD_LOGIC;
           HS : out  STD_LOGIC;
           VS : out  STD_LOGIC;
           R,G,B : out  STD_LOGIC);
  end component;

  signal CLKBE: STD_LOGIC;

begin

  CLK_Divider_1: CLK_25Mhz_Divider port map ( CLK => CLKI,
                                              CLK_OUT => CLKBE);

  VGA_S1: VGA_Sync port map ( CLK => CLKBE,
           HS => HSO,
           VS => VSO,
           R  => RO,
              G  => GO,
              B  => BO );

end Behavioral;

the clock divider

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity CLK_25MHz_Divider is
    Port ( CLK : in  STD_LOGIC;
           CLK_OUT : out  STD_LOGIC);
end CLK_25MHz_Divider;

architecture Behavioral of CLK_25MHz_Divider is

 BEGIN
     PROCESS(CLK)
          VARIABLE COUNT : INTEGER:=0;
          VARIABLE TEMP : STD_LOGIC:='0';
          BEGIN
                IF RISING_EDGE(CLK)THEN
                     COUNT:=COUNT+1;
                     IF COUNT=2 THEN
                          TEMP:=NOT TEMP;
                          COUNT:=0;
                     END IF;
                END IF;
                CLK_OUT<=TEMP;
                END PROCESS;
end Behavioral;

The VGA signal generation module

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity VGA_Sync is
    Port ( CLK : in  STD_LOGIC;
           HS : out  STD_LOGIC;
           VS : out  STD_LOGIC;
           R,G,B : out STD_LOGIC);
end VGA_Sync;

architecture Behavioral of VGA_Sync is

begin 

  process(CLK)

  Variable countH : Integer := 0;
  Variable countV : Integer := 0;

    begin
     if (CLK'EVENT and CLK = '1') then

        if countH < 800 then 
            countH := countH + 1;
        else 
            countH := 0;
           if countV < 500 then
                countV := countV + 1;
        else 
               countV := 0;
           end if;
        end if;

        if countH >= 16 and countH < 112 then
           HS <= '0';
       else 
           HS <= '1';
        end if;

        if countV >= 10 and countV < 12 then
           VS <= '0';
       else 
           VS <= '1';
        end if;

        if (countH < 160) or (countV < 45) then 
           R <= '0';
            G <= '0';
            B <= '0';
        else 
           R <= '1';
            G <= '0';
            B <= '1';
      end if;
   end if;
 end process;       
end Behavioral;

so tell me your thoughts on what is wrong with the code


Solution

  • Because you haven't actually describe the problem and because I had a testbench for a 25 MHz clocked vga generator that only required changing the type for r, g and b, I ran you sync_vga against the testbench:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity vga_sync_tb is
    end entity;
    
    architecture foo of vga_sync_tb is
        signal clk:    std_logic := '0';
        signal hs:     std_logic;
        signal vs:     std_logic;
        signal r,g,b:  std_logic;
    begin
    DUT:
        entity work.vga_sync 
            port map (
                clk => clk,
                hs => hs,
                vs => vs,
                r => r,
                g => g,
                b => b
            );
    CLOCK:
        process
        begin
            wait for 20 ns;  -- clock period 25 MHz = 40 ns;
            clk <= not clk;
            if now > 20 ms then  -- one frame time plus a bit
                wait;
            end if;
        end process;
    end architecture;
    

    It gave a vertical sync rate around 60 Hz:

    sync_vga_tb_full.png

    Zooming in and measuring between two HS edges shows a horizontal rate of around 31.17 KHz.

    You have horizontal and vertical blanking intervals and your R, G, and B does what your code says.

    That sort of leaves the clock divider or something platform related.

    Because a testbench for the clock is simple:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity clock_tb is
    end entity;
    
    architecture foo of clock_tb is
        signal clk:     std_logic := '0';
        signal clk25:   std_logic;
    begin
    DUT:
        entity work.clk_25mhz_divider
            port map (
                clk => clk,
                clk_out => clk25
            );
    CLOCK:
        process
        begin
            wait for 10 ns; -- half the period of 50 MHz
            clk <= not clk;
            if now > 130 ns then
                wait;
            end if;
        end process;
    end architecture;
    

    It demonstrates Martin Zabel's answer:

    clock_tb.png

    That your divide by two actually divides by four. giving a period of 80 ns (12.5 MHz).

    This demonstrates the usefulness of simulation and in simulation it can also be helpful to use signals instead of variables which have no history. Variables don't have a projected output waveform and he simulator has to attach extra code to display them in a waveform.

    The simulation performance increase using variables instead of signals is traded for the ability to display them and there is no interesting distinction in synthesis.