我正在尝试通过一些书籍和 Terasic 的 Altera DE1 开发套件来学习 VHDL 编程。
这里的问题是我正在尝试对 VGA 控制器进行编程,使其能够以 640x480 的分辨率工作(尽管我的屏幕是 1280x1024 的 TFT LCD)。
我的代码有一些问题。
我正在使用 FSM 来制作垂直和水平信号,另一个块来驱动 RGB 输入以及来自 DE1 的 27 MHz 时钟。
我认为代码一定有问题,因为我在屏幕上打印的图像尺寸不正确(640x480)而是更大(大约1174x980)。
到现在为止,我正试图在屏幕上只放一种颜色来简化它,直到我发现错误为止。
我的项目有 3 个文件,1 个用于块 RGB,1 个用于 FSM,另一个用于实例化它们。
我将不胜感激解决此问题的某种帮助,因为我已经努力解决了这个问题,但我看不出错误在哪里。
非常感谢!
奥马尔
VGA 控制器文件
library ieee;
use ieee.std_logic_1164.all;
entity VGA_controller is
port(clk, reset : in std_logic;
Hsync,Vsync : out std_logic;
R,G,B : out std_logic_vector(3 downto 0));
end entity;
architecture arch of VGA_controller is
component FSM_sync is
port(clk,reset : in std_logic;
Hsync,Vsync,VIDON : out std_logic;
Vcount,Hcount : out integer range 0 to 799);
end component;
component VGA_display is
port(hcount,vcount : in integer range 0 to 799;
r,g,b : out std_logic_vector(3 downto 0);
video_on : in std_logic);
end component;
signal video : std_logic;
signal signal1 : integer range 0 to 799;
signal signal2 : integer range 0 to 799;
begin
maquinaestado_sync : FSM_sync port map (clk=>clk, reset=>reset, Hsync=>Hsync, Vsync=>Vsync, Vcount=>signal1, Hcount=>signal2, VIDON=>video);
salida_pantalla : VGA_display port map (r=>R, g=>G, b=>B, video_on=>video, vcount=>signal1, hcount=>signal2 );
end arch;
FSM 同步文件
library ieee;
use ieee.std_logic_1164.all;
entity FSM_sync is
port(clk,reset : in std_logic;
Hsync,Vsync,VIDON : out std_logic;
Vcount,Hcount : out integer range 0 to 799);
end entity;
architecture arch of FSM_sync is
--constantes para definir los ciclos de reloj de cada señal del HSYNC
constant counterMAX : integer := 640;
constant counterSP : integer := 96;
constant counterBP : integer := 48;
constant counterHV : integer := 640;
constant counterFP : integer := 16;
--constantes para definir los ciclos de reloj de cada señal del VSYNC
constant counterMAX_V : integer := 384000; -- calculamos estos valores multiplicando el numero de filas por los pixeles en cada fila horizontal (800)
constant counterSP_V : integer := 1600; -- de manera que cada estado de la sincronizacion vertical dure todo el recorrido de los pixeles de cada fila
constant counterBP_V : integer := 26400;
constant counterVV : integer := 384000;
constant counterFP_V : integer := 8000;
--constantes para el numero de pixeles maximo que debemos controlar en horizontal y en vertical
constant number_pixelsMAX_H : integer := 800;
constant number_pixelsMAX_V : integer := 525;
type state is (SP_1,BP,HV,FP,reseteo); --4 estados para cada maquina de estado de sincronizacion (vertical y horizontal)
signal present_state_H,next_state_H,present_state_V,next_state_V : state;
signal timer : integer range 0 to counterMAX ; -- señal para pasar el valor counterXX al proceso secuencial para compararlo con un contador y establecer el
-- tiempo de duracion de cada estado
signal timer2 : integer range 0 to counterMAX_V ; --lo mismo que la señal anterior pero para el sincronizacion vertical
signal video_1,video_2 : std_logic;
signal hcount_reg,vcount_reg : integer range 0 to 799;
begin
--==============================================
--FSM para la sincronizacion del barrido HORIZONTAL
--===============================================
lower_part_1 : process (clk,reset)
variable counter : integer range 0 to counterMAX - 1; --variable para crear un contador de pulsos del clk
variable counter2 : integer range 0 to number_pixelsMAX_H - 1; --contador para los pixeles horizontales
variable counter3 : integer range 0 to number_pixelsMAX_V - 1; --contador para los pixeles verticales
begin --se cargan con 800 por que 800 son los pixeles que hay que leer en horizontal
if (reset = '1') then --esto implica contadores de al menos 10 bits para llegar a ese numero.
--y para que los dos contadores sean del mismo numero de bits se cargan los dos igual
counter := 0; --realmente en vertical solo debemos contar hasta 521
counter2 := 0;
counter3 := 0;
present_state_H <= reseteo;
elsif (clk'event and clk = '1') then
counter := counter + 1;
if (counter2 < number_pixelsMAX_H-1) then
counter2 := counter2 + 1;
else
counter2 := 0;
if (counter3 < number_pixelsMAX_V-1) then
counter3 := counter3 + 1;
else
counter3 := 0;
end if;
end if;
hcount_reg <= counter2;
vcount_reg <= counter3;
if (counter = timer) then
present_state_H <= next_state_H;
counter := 0;
end if;
end if;
end process lower_part_1;
upper_part_1 : process (next_state_H)
begin
Hsync <= '1';
next_state_H <= HV;
case present_state_H is
when SP_1 =>
Hsync <= '0';
next_state_H <= BP;
timer <= counterSP;
video_1 <= '0';
when BP =>
Hsync <= '1';
next_state_H <= HV;
timer <= counterBP;
video_1 <= '0';
when HV =>
Hsync <= '1';
next_state_H <= FP;
timer <= counterHV;
video_1 <= '1';
when FP =>
Hsync <= '1';
next_state_H <= SP_1;
timer <= counterFP;
video_1 <= '0';
when reseteo =>
Hsync <= '1';
next_state_H <=HV;
end case;
end process upper_part_1;
--==============================================
--FSM para la sincronizacion del barrido VERTICAL
--===============================================
lower_part_2 : process (clk,reset)
variable counter2 : integer range 0 to counterMAX_V; --variable para crear un contador de pulsos del clk
begin
if (reset = '1') then
counter2 := 0;
present_state_V <= reseteo;
elsif (clk'event and clk = '1') then
counter2 := counter2 + 1;
if (counter2 = timer2) then
present_state_V <= next_state_V;
counter2 := 0;
end if;
end if;
end process lower_part_2;
upper_part_2 : process (next_state_V)
begin
Vsync <= '1';
next_state_V <= HV;
case present_state_V is
when SP_1 =>
Vsync <= '0';
next_state_V <= BP;
timer2 <= counterSP_V;
video_2 <= '0';
when BP =>
Vsync <= '1';
next_state_V <= HV;
timer2 <= counterBP_V;
video_2 <= '0';
when HV =>
Vsync <= '1';
next_state_V <= FP;
timer2 <= counterVV;
video_2 <= '1';
when FP =>
Vsync <= '1';
next_state_V <= SP_1;
timer2 <= counterFP_V;
video_2 <= '0';
when reseteo =>
Vsync <= '1';
next_state_V <=HV;
end case;
end process upper_part_2;
VIDON <= video_1 AND video_2;
Vcount <= vcount_reg;
Hcount <= hcount_reg;
end arch;
VGD 显示文件
library ieee;
use ieee.std_logic_1164.all;
entity VGA_display is
port(hcount,vcount : in integer range 0 to 799;
r,g,b : out std_logic_vector(3 downto 0);
video_on : in std_logic);
end entity;
architecture arch of VGA_display is
begin
process (video_on)
begin
if video_on = '1' then --solo activamos los pixeles cuando vidon esté a uno, es decir, esten en la fase HV y VV las sincronizaciones
r <= "1111";
g <= "0000";
b <= "0000";
else
r <= (others => '0');
g <= (others => '0');
b <= (others => '0');
end if;
end process;
end arch;