为什么我用于生成 VGA 信号的 VHDL 代码不起作用

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

我一直在疯狂地尝试让它工作,但在过去的 6 个小时里什么也没做,仍然没有解决它:/

所以这是顶级模块

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;

时钟分频器

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;

VGA信号产生模块

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;

请告诉我您对代码错误的看法

来自以下问题的评论:

at that resolution i should use 25Mhz so i using the onboard clock that's 50 Mhz and dividing it using the Clock divider module. – Mostafa

您的时钟分频器将输入频率除以 4 而不是 2。您每两个周期切换 TEMP CLK,即顶部模块的 CLKI。所以 CLK_OUT 的一个完整周期需要输入时钟的 4 个周期。

要除以二,必须在输入时钟的每个时钟周期切换TEMP

architecture Behavioral of CLK_25MHz_Divider is
BEGIN
     PROCESS(CLK)
          VARIABLE TEMP : STD_LOGIC:='0';
     BEGIN
         IF RISING_EDGE(CLK)THEN
             TEMP:=NOT TEMP;
         END IF;
         CLK_OUT<=TEMP;
     END PROCESS;

end Behavioral;

TEMP = '0' 开始,它在 CLK 的第一个上升沿切换到“1”。在第二个上升沿,TEMP 切换为“0”,在第三个上升沿切换回“1”。 50 MHz 输入时钟的第一个和第三个上升沿之间的持续时间为 40 ns,这使得输出时钟的频率为 25 MHz。

因为你实际上没有描述问题,而且因为我有一个 25 MHz 时钟 vga 发生器的测试台,它只需要更改 r、g 和 b 的类型,我 运行 你 sync_vga 针对测试平台:

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;

它给出了大约 60 Hz 的垂直同步率:

放大并在两个 HS 边缘之间进行测量显示水平速率约为 31.17 KHz。

您有水平和垂直消隐间隔,并且您的 R、G 和 B 按照您的代码说明执行。

这样就留下了时钟分频器或与平台相关的东西。

因为时钟的测试平台很简单:

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;

它证明了 Martin Zabel 的回答:

你除以二实际上除以四。给出 80 ns (12.5 MHz) 的周期。

这证明了模拟的有用性,并且在模拟中使用信号代替没有历史的变量也很有帮助。变量没有预计的输出波形,他的模拟器必须附加额外的代码才能在波形中显示它们。

使用变量而不是信号来提高模拟性能是为了显示它们的能力而进行的交易,并且在综合中没有有趣的区别。