为什么我用于生成 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) 的周期。
这证明了模拟的有用性,并且在模拟中使用信号代替没有历史的变量也很有帮助。变量没有预计的输出波形,他的模拟器必须附加额外的代码才能在波形中显示它们。
使用变量而不是信号来提高模拟性能是为了显示它们的能力而进行的交易,并且在综合中没有有趣的区别。
我一直在疯狂地尝试让它工作,但在过去的 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) 的周期。
这证明了模拟的有用性,并且在模拟中使用信号代替没有历史的变量也很有帮助。变量没有预计的输出波形,他的模拟器必须附加额外的代码才能在波形中显示它们。
使用变量而不是信号来提高模拟性能是为了显示它们的能力而进行的交易,并且在综合中没有有趣的区别。