VHDL VGA接口
VHDL VGA interface
我一直在DE0板子上建模一个VGA接口。我有以下型号的 640x480 显示器,刷新频率为 60Hz:
主要型号:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY VGA is
PORT (clk : IN std_logic; -- demo had 2 bit vector
vga_hs, vga_vs : OUT std_logic;
vga_r, vga_g, vga_b : OUT std_logic_vector(3 DOWNTO 0));
END ENTITY VGA;
ARCHITECTURE A1 OF VGA IS
SIGNAL rst, clk25 : std_logic; -- rst only resets pixel clock
BEGIN
SYNC1 : ENTITY work.sync(A1)
PORT MAP (clk25, vga_hs, vga_vs, vga_r, vga_g, vga_b);
CLK_25 : ENTITY work.PLL(rtl)
PORT MAP (clk, rst, clk25);
END ARCHITECTURE A1;
同步模型:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY SYNC IS
PORT(
clk : IN std_logic;
h_sync, v_sync : OUT std_logic;
r, g, b : OUT std_logic_vector(3 DOWNTO 0)
);
END ENTITY SYNC;
ARCHITECTURE A1 OF SYNC IS
SIGNAL h_pos: integer RANGE 0 TO 800:=0;
SIGNAL v_pos : integer RANGE 0 TO 520:=0;
BEGIN
TIMING :PROCESS(clk) IS
BEGIN
IF rising_edge(clk) THEN
IF (h_pos = 480 or v_pos = 280) THEN -- middle of the screen is pic res/2 + (FP + sync + BP)
r <= (OTHERS => '1');
g <= (OTHERS => '1');
b <= (OTHERS => '1');
ELSE
r <= (OTHERS => '0');
g <= (OTHERS => '0');
b <= (OTHERS => '0');
END IF;
IF (h_pos < 800) THEN
h_pos <= h_pos + 1;
ELSE
h_pos <= 1;
IF (v_pos < 520) THEN
v_pos <= v_pos + 1;
ELSE
v_pos <= 1;
END IF;
END IF;
IF (h_pos > 16 and h_pos < 112 ) THEN -- H_POS between end of FP and the end of H_SYNC
h_sync <= '0'; -- H_SYNC needs to stay low during display
ELSE
h_sync <= '1';
END IF;
IF (v_pos > 8 and v_pos < 10 ) THEN --V_POS between end of FP and the end of V_SYNC
v_sync <= '0'; -- V_SYNC needs to stay low during display
ELSE
v_sync <= '1';
END IF;
IF ((h_pos > 0 and h_pos < 160) or (v_pos > 0 and v_pos < 40 )) THEN--During all of SYNC i.e FP + SYNC + BP colour signals stay low
r <= (OTHERS => '0');
g <= (OTHERS => '0');
b <= (OTHERS => '0');
END IF;
END IF;
END PROCESS TIMING;
END ARCHITECTURE A1;
----------Amendments made to model 09/02 13:42----------
另一个直接实例化是从 Quartus II 生成的 PLL,它似乎工作正常。谢谢 Zilmer 先生 :)。该模型编译得很好。我将它加载到 DE0 中。然后将其连接到显示器,显示器上什么也看不到。它应该在屏幕中央显示一个十字。我使用的显示器是 1920x1080 的三星显示器。这会阻止我的模型显示任何东西吗?或者我在我的模型中犯了一个明显的错误。我更改了一些标准时序值以适应 60Hz 刷新率和 25Mz clk。
谢谢
D
您的实体同步 VHDL 代码未分析。您缺少 end if
并且 h_sync
和 v_sync
的初始值违反了子类型约束:
signal h_pos: integer range 1 to 800 := 0;
signal v_pos: integer range 1 to 520 := 0;
其中 0
在 1 to 800
或 1 to 520
的范围之外。
这提出了一个问题,即您是否有另一个用于实体同步的架构,或者同步是否只是未绑定的。其中任何一个都可能给你一个错误的指示(并且你的问题中没有证明错误)。
我们可以使用测试台来演示同步在 25 MHz 时钟的模拟中的作用:
library ieee;
use ieee.std_logic_1164.all;
--use ieee.numeric_std.all;
entity sync is
port (
clk: in std_logic;
h_sync, v_sync: out std_logic;
r, g, b: out std_logic_vector(3 downto 0)
);
end entity sync;
architecture a1 of sync is
signal h_pos: integer range 1 to 800 := 1; -- was := 0;
signal v_pos: integer range 1 to 520 := 1; -- was := 0;
begin
timing:
process (clk) is
begin
if rising_edge(clk) then
if h_pos = 480 or v_pos = 280 then -- middle of the screen
r <= (others => '1');
g <= (others => '1');
b <= (others => '1');
else
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
if h_pos < 800 then
h_pos <= h_pos + 1;
else
h_pos <= 1;
if v_pos < 520 then
v_pos <= v_pos + 1;
else
v_pos <= 1;
end if;
if h_pos > 16 and h_pos < 112 then
h_sync <= '0'; -- h_sync low during display
else
h_sync <= '1';
end if;
if v_pos > 8 and v_pos < 10 then
v_sync <= '0'; -- v_sync low during display
else
v_sync <= '1';
end if;
if (h_pos > 1 and h_pos < 160) or
(v_pos > 1 and v_pos < 40 ) then -- black during blanking
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
end if;
end if; -- added misssing end if
end process timing;
end architecture a1;
library ieee;
use ieee.std_logic_1164.all;
entity sync_tb is
end entity;
architecture foo of sync_tb is
signal clk: std_logic := '0';
signal h_sync: std_logic;
signal v_sync: std_logic;
signal r, g, b: std_logic_vector (3 downto 0);
begin
DUT:
entity work.sync
port map (
clk => clk,
h_sync => h_sync,
v_sync => v_sync,
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;
现在我们来解决问题:
我们注意到的第一件事是 h_sync 是错误的。另请注意,v_sync 似乎约为 16.667 毫秒(1/60 秒)。
我们可以添加 h_pos 和 v_pos 计数器,这样我们就可以查看 h_sync,我们知道 h_pos 计数器是 运行 v_sync 我们可以在 60 Hz 的右邻域中看到。
所以我选择了错误的地方添加end if
。更正也将操作计数器与其输出操作分开(h_sync、v_sync 和 r、g、b)。
timing:
process (clk) is
begin
if rising_edge(clk) then
if h_pos = 480 or v_pos = 280 then -- middle of the screen
r <= (others => '1');
g <= (others => '1');
b <= (others => '1');
else
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
if h_pos < 800 then
h_pos <= h_pos + 1;
else
h_pos <= 1;
if v_pos < 520 then
v_pos <= v_pos + 1;
else
v_pos <= 1;
end if;
end if; -- separate the counters for what they produce
-- HSYNC
if h_pos > 16 and h_pos < 112 then
h_sync <= '0'; -- h_sync low during display
else
h_sync <= '1';
end if;
-- VSYNC
if v_pos > 8 and v_pos < 10 then
v_sync <= '0'; -- v_sync low during display
else
v_sync <= '1';
end if;
-- BLANKING
if (h_pos > 1 and h_pos < 160) or
(v_pos > 1 and v_pos < 40 ) then
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
end if;
end process timing;
我们现在 h_sync:
注意我们现在也可以看到垂直消隐间隔。
放大我们可以看到 v_pos 280:
处有一条水平白线
沿着 h_pos 480 (+1) 处的垂直线:
这看起来可能有用。
我可能想做的唯一设计更改是在 h_pos = 0 开始线条的可见部分,在 v_pos = 0 开始框架的可见部分。这将允许其他东西来寻址像素以写入帧缓冲区,而无需添加额外的像素计数器或不必进行偏移算术。 (对于 x 和 y 轴,像素寻址通常从 0 开始)。
我一直在DE0板子上建模一个VGA接口。我有以下型号的 640x480 显示器,刷新频率为 60Hz:
主要型号:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY VGA is
PORT (clk : IN std_logic; -- demo had 2 bit vector
vga_hs, vga_vs : OUT std_logic;
vga_r, vga_g, vga_b : OUT std_logic_vector(3 DOWNTO 0));
END ENTITY VGA;
ARCHITECTURE A1 OF VGA IS
SIGNAL rst, clk25 : std_logic; -- rst only resets pixel clock
BEGIN
SYNC1 : ENTITY work.sync(A1)
PORT MAP (clk25, vga_hs, vga_vs, vga_r, vga_g, vga_b);
CLK_25 : ENTITY work.PLL(rtl)
PORT MAP (clk, rst, clk25);
END ARCHITECTURE A1;
同步模型:
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
ENTITY SYNC IS
PORT(
clk : IN std_logic;
h_sync, v_sync : OUT std_logic;
r, g, b : OUT std_logic_vector(3 DOWNTO 0)
);
END ENTITY SYNC;
ARCHITECTURE A1 OF SYNC IS
SIGNAL h_pos: integer RANGE 0 TO 800:=0;
SIGNAL v_pos : integer RANGE 0 TO 520:=0;
BEGIN
TIMING :PROCESS(clk) IS
BEGIN
IF rising_edge(clk) THEN
IF (h_pos = 480 or v_pos = 280) THEN -- middle of the screen is pic res/2 + (FP + sync + BP)
r <= (OTHERS => '1');
g <= (OTHERS => '1');
b <= (OTHERS => '1');
ELSE
r <= (OTHERS => '0');
g <= (OTHERS => '0');
b <= (OTHERS => '0');
END IF;
IF (h_pos < 800) THEN
h_pos <= h_pos + 1;
ELSE
h_pos <= 1;
IF (v_pos < 520) THEN
v_pos <= v_pos + 1;
ELSE
v_pos <= 1;
END IF;
END IF;
IF (h_pos > 16 and h_pos < 112 ) THEN -- H_POS between end of FP and the end of H_SYNC
h_sync <= '0'; -- H_SYNC needs to stay low during display
ELSE
h_sync <= '1';
END IF;
IF (v_pos > 8 and v_pos < 10 ) THEN --V_POS between end of FP and the end of V_SYNC
v_sync <= '0'; -- V_SYNC needs to stay low during display
ELSE
v_sync <= '1';
END IF;
IF ((h_pos > 0 and h_pos < 160) or (v_pos > 0 and v_pos < 40 )) THEN--During all of SYNC i.e FP + SYNC + BP colour signals stay low
r <= (OTHERS => '0');
g <= (OTHERS => '0');
b <= (OTHERS => '0');
END IF;
END IF;
END PROCESS TIMING;
END ARCHITECTURE A1;
----------Amendments made to model 09/02 13:42----------
另一个直接实例化是从 Quartus II 生成的 PLL,它似乎工作正常。谢谢 Zilmer 先生 :)。该模型编译得很好。我将它加载到 DE0 中。然后将其连接到显示器,显示器上什么也看不到。它应该在屏幕中央显示一个十字。我使用的显示器是 1920x1080 的三星显示器。这会阻止我的模型显示任何东西吗?或者我在我的模型中犯了一个明显的错误。我更改了一些标准时序值以适应 60Hz 刷新率和 25Mz clk。 谢谢 D
您的实体同步 VHDL 代码未分析。您缺少 end if
并且 h_sync
和 v_sync
的初始值违反了子类型约束:
signal h_pos: integer range 1 to 800 := 0;
signal v_pos: integer range 1 to 520 := 0;
其中 0
在 1 to 800
或 1 to 520
的范围之外。
这提出了一个问题,即您是否有另一个用于实体同步的架构,或者同步是否只是未绑定的。其中任何一个都可能给你一个错误的指示(并且你的问题中没有证明错误)。
我们可以使用测试台来演示同步在 25 MHz 时钟的模拟中的作用:
library ieee;
use ieee.std_logic_1164.all;
--use ieee.numeric_std.all;
entity sync is
port (
clk: in std_logic;
h_sync, v_sync: out std_logic;
r, g, b: out std_logic_vector(3 downto 0)
);
end entity sync;
architecture a1 of sync is
signal h_pos: integer range 1 to 800 := 1; -- was := 0;
signal v_pos: integer range 1 to 520 := 1; -- was := 0;
begin
timing:
process (clk) is
begin
if rising_edge(clk) then
if h_pos = 480 or v_pos = 280 then -- middle of the screen
r <= (others => '1');
g <= (others => '1');
b <= (others => '1');
else
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
if h_pos < 800 then
h_pos <= h_pos + 1;
else
h_pos <= 1;
if v_pos < 520 then
v_pos <= v_pos + 1;
else
v_pos <= 1;
end if;
if h_pos > 16 and h_pos < 112 then
h_sync <= '0'; -- h_sync low during display
else
h_sync <= '1';
end if;
if v_pos > 8 and v_pos < 10 then
v_sync <= '0'; -- v_sync low during display
else
v_sync <= '1';
end if;
if (h_pos > 1 and h_pos < 160) or
(v_pos > 1 and v_pos < 40 ) then -- black during blanking
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
end if;
end if; -- added misssing end if
end process timing;
end architecture a1;
library ieee;
use ieee.std_logic_1164.all;
entity sync_tb is
end entity;
architecture foo of sync_tb is
signal clk: std_logic := '0';
signal h_sync: std_logic;
signal v_sync: std_logic;
signal r, g, b: std_logic_vector (3 downto 0);
begin
DUT:
entity work.sync
port map (
clk => clk,
h_sync => h_sync,
v_sync => v_sync,
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;
现在我们来解决问题:
我们注意到的第一件事是 h_sync 是错误的。另请注意,v_sync 似乎约为 16.667 毫秒(1/60 秒)。
我们可以添加 h_pos 和 v_pos 计数器,这样我们就可以查看 h_sync,我们知道 h_pos 计数器是 运行 v_sync 我们可以在 60 Hz 的右邻域中看到。
所以我选择了错误的地方添加end if
。更正也将操作计数器与其输出操作分开(h_sync、v_sync 和 r、g、b)。
timing:
process (clk) is
begin
if rising_edge(clk) then
if h_pos = 480 or v_pos = 280 then -- middle of the screen
r <= (others => '1');
g <= (others => '1');
b <= (others => '1');
else
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
if h_pos < 800 then
h_pos <= h_pos + 1;
else
h_pos <= 1;
if v_pos < 520 then
v_pos <= v_pos + 1;
else
v_pos <= 1;
end if;
end if; -- separate the counters for what they produce
-- HSYNC
if h_pos > 16 and h_pos < 112 then
h_sync <= '0'; -- h_sync low during display
else
h_sync <= '1';
end if;
-- VSYNC
if v_pos > 8 and v_pos < 10 then
v_sync <= '0'; -- v_sync low during display
else
v_sync <= '1';
end if;
-- BLANKING
if (h_pos > 1 and h_pos < 160) or
(v_pos > 1 and v_pos < 40 ) then
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
end if;
end process timing;
我们现在 h_sync:
注意我们现在也可以看到垂直消隐间隔。
放大我们可以看到 v_pos 280:
处有一条水平白线沿着 h_pos 480 (+1) 处的垂直线:
这看起来可能有用。
我可能想做的唯一设计更改是在 h_pos = 0 开始线条的可见部分,在 v_pos = 0 开始框架的可见部分。这将允许其他东西来寻址像素以写入帧缓冲区,而无需添加额外的像素计数器或不必进行偏移算术。 (对于 x 和 y 轴,像素寻址通常从 0 开始)。