Tôi đang cố gắng học lập trình VHDL với một số sách và bộ phát triển Altera DE1 từ Terasic.Bộ điều khiển VGA với VHDL
Vấn đề ở đây là tôi đang cố gắng lập trình bộ điều khiển VGA để làm việc với độ phân giải 640x480 (mặc dù màn hình của tôi là màn hình LCD TFT có 1280x1024).
Tôi gặp một số sự cố với mã.
Tôi đang sử dụng FSM để tạo tín hiệu dọc và ngang, một khối khác để điều khiển đầu vào RGB và đồng hồ 27 MHz từ DE1.
Tôi nghĩ rằng phải có điều gì đó sai với mã vì hình ảnh tôi in trên màn hình không đúng kích thước (640x480) nhưng lớn hơn (khoảng 1174x980).
Hiện tại, tôi đang cố gắng đặt một màu duy nhất trên màn hình để đơn giản hóa màu cho đến khi tôi có thể phát hiện ra lỗi.
Dự án của tôi có 3 tệp, 1 cho khối RGB, 1 cho FSM và một tệp khác để khởi tạo cả hai tệp.
Tôi sẽ đánh giá cao một số loại trợ giúp để giải quyết vấn đề này bởi vì tôi đã cố gắng hết sức để tìm ra nhưng tôi không thể nhìn thấy đâu là những sai lầm.
Cảm ơn rất nhiều!
Omar
tập tin điều khiển 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;
tập tin FSM sync
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 tập tin hiển thị
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;
Bạn có chắc chắn màn hình của bạn không thu nhỏ kích thước 640x480 đến 1280x960 (tức là 2x2 pixel) để lấp đầy bảng điều khiển không? – NPE
Một trong những vấn đề lớn với máy xử lý 2 trạng thái là khó khăn trong việc lấy danh sách độ nhạy chính xác. Tôi đã không xem xét mã của bạn một cách chi tiết (tôi không làm 2 quy trình SM) nhưng có vẻ sai khi đặt 'next_state_ *' trong danh sách độ nhạy và sau đó kiểm tra 'present_state_ *' trong trường hợp câu lệnh. Cũng có thể có các vấn đề về danh sách nhạy cảm khác. –
Hai quy trình thể hiện mối quan tâm của danh sách độ nhạy của Brian là 'upper_part_1'and' upper_part_2'. Tôi không tin rằng họ là một vấn đề tổng hợp, danh sách nhạy cảm có xu hướng bị bỏ qua. Bạn nên sửa chữa tất cả như nhau. – user1155120