En este momento estoy tratando de hacer un controlador vga para mi FPGA, pero algo no va bien, y parece que no puedo encontrar qué es lo que va mal...
El código se basa en este ejemplo de código: Ejemplo de controlador VGA
Aquí está mi código: (solo cambié la resolución y algunos nombres de variables, aparte de eso, debería ser exactamente igual).
----------------------------------------------------------------------------------
-- Company:
-- Engineer:
--
-- Create Date: 03/07/2016 08:53:44 AM
-- Design Name:
-- Module Name: vga - Behavioral
-- Project Name:
-- Target Devices:
-- Tool Versions:
-- Description:
--
-- Dependencies:
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
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 leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity vga is
GENERIC(
constant HR:integer:=640;--Horizontal Resolution
constant HFP:integer:=16;--Horizontal Front Porch
constant HBP:integer:=48;--Horizontal Back Porch
constant HRet:integer:=96;--Horizontal retrace
h_pol : STD_LOGIC := '0'; --horizontal sync pulse polarity (1 = positive, 0 = negative)
constant VR:integer:=480;--Vertical Resolution
constant VFP:integer:=10;--Vertical Front Porch
constant VBP:integer:=33;--Vertical Back Porch
constant VRet:integer:=2;--Vertical Retrace);
v_pol : STD_LOGIC := '0' --vertical sync pulse polarity (1 = positive, 0 = negative)
);
Port ( clk : in STD_LOGIC;
LED0: out std_logic;
vga_r: out std_logic_vector(4 downto 0);
vga_g: out std_logic_vector(5 downto 0);
vga_b: out std_logic_vector(4 downto 0);
vga_vs: out std_logic;
vga_hs: out std_logic);
end vga;
architecture Behavioral of vga is
signal COUNT : integer range 0 to 100000000;
constant x_counter: integer := HR + HFP + HBP + HRet;
constant y_counter: integer := VR + VFP + VBP + VRet;
signal newCounter: integer range 0 to 4 := 0;
signal newClk: std_logic;
begin
alive: process(CLK)
begin
if rising_edge(CLK) then
COUNT <= COUNT + 1;
if COUNT = 100000000 then
COUNT <= 0;
end if;
if COUNT < 100000000/2 then
-- LED0 <= '1';
else
-- LED0 <= '0';
end if;
end if;
end process;
prescaler: process(clk)
begin
if rising_edge(clk) then
newCounter <= newCounter +1;
if newCounter = 4 then
newClk <= ‘1’;
newCounter <= 0;
else
newClk <= ‘0’;
end if;
end if;
end process;
screen:process(newClk)
VARIABLE h_count : INTEGER RANGE 0 TO x_counter - 1 := 0; --horizontal counter (counts the columns)
VARIABLE v_count : INTEGER RANGE 0 TO y_counter - 1 := 0; --vertical counter (counts the rows)
begin
-- Horizontal 640
-- Vertical 480
if rising_edge(newClk) then
-- Increase Horizontal counter
if (h_count < x_counter - 1 ) then
h_count := h_count + 1;
else
h_count := 0 ;
-- Increase Vertical counter
if (v_count < y_counter - 1 ) then
v_count := v_count + 1;
else
v_count := 0 ;
end if;
end if;
--horizontal sync signal
IF(h_count < HR + HFP OR h_count > HR + HFP + HRet) THEN
vga_hs <= NOT h_pol; --deassert horiztonal sync pulse
LED0 <= NOT h_pol;
ELSE
vga_hs <= h_pol; --assert horiztonal sync pulse
LED0 <= h_pol;
END IF;
--vertical sync signal
IF(v_count < VR + VFP OR v_count > VR + VFP + VRet) THEN
vga_vs <= NOT v_pol; --deassert vertical sync pulse
ELSE
vga_vs <= v_pol; --assert vertical sync pulse
END IF;
end if;
end process;
vga_r <= "11111";
vga_g <= "000000";
vga_b <= "00000";
end Behavioral;
Asigna valores constantes a sus líneas de color VGA, lo que no funcionará.
Un monitor VGA analógico espera ver un nivel de "negro" de referencia durante parte de la duración del seguimiento fuera de la pantalla. Si maneja un valor sustancialmente distinto de cero allí, se adaptará a la idea de que este voltaje significa negro, y no obtendrá el rectángulo de color esperado (en algunos monitores, es posible que obtenga un breve destello de color al conectarse, antes yendo a todo negro).
Deberá alternar sus líneas de color entre el color deseado y el negro durante los períodos de tiempo en los que deberían señalar el color en el área activa o la referencia negra fuera de ella.
Dos herramientas muy útiles serán un diagrama de tiempo de cómo debería verse VGA y, si es posible, un osciloscopio que compare su señal con la de una configuración de tarjeta VGA para generar algo similar (¿salvapantallas a todo color?)
Como ya mencionaron Chris Stratton et.al., debe establecer el color en negro durante los intervalos de supresión. Esto se logró mediante la señal disp_ena
en el diseño de ejemplo vinculado en su pregunta.
Para agregar dicho comportamiento a su diseño, debe:
1) Agregue una nueva señal disp_ena
en la parte de declaración de arquitectura:
signal disp_ena : std_logic;
2) Establezca esta señal sincronizada con el reloj en '1' cuando se muestra la imagen y en '0' en caso contrario (durante el borrado).
screen:process(newClk)
-- ... existing code
begin
if rising_edge(newClk) then
-- ... existing code
--set display-enable control signal
IF(h_count < HR and v_count < VR) THEN
disp_ena <= '1';
ELSE
disp_ena <= '0';
end IF;
end if;
end process;
3) Establezca el color en rojo solo cuando la visualización esté habilitada ( disp_ena = '1'
), de lo contrario, en negro. Por lo tanto, cambie las líneas existentes a:
vga_r <= "11111" when disp_ena = '1' else (others => '0');
vga_g <= "000000" when disp_ena = '1' else (others => '0');
vga_b <= "00000" when disp_ena = '1' else (others => '0');
Estás generando una nueva señal de reloj usando un contador. Esta no es una buena práctica de diseño. Debería usar uno de los PLL en el FPGA en su lugar. Puede crear una instanciación adecuada a través de Xilinx IP Core Generator.
Si quieres quedarte con el contador, entonces tienes dos opciones:
1) Use un BUFG
componente para minimizar el sesgo en la red del reloj newclk
. Para usar este componente, debe incluir:
library unisim;
use unisim.vcomponents.all;
Luego crea una instancia de la BUFG
vía:
newclk_bufg: BUFG (I => newclk, O => newclk2);
Luego use newclk2
para manejar los registros.
2) Utilizar newclk
como señal de activación de reloj en lugar de señal de reloj. Luego, el screen
proceso se activará CLK
, pero la carga de los nuevos valores de registro ocurrirá solo si newclk
es alto:
screen:process(CLK)
-- ... existing code
begin
if rising_edge(CLK) then
if newclk = '1' then -- newclk used as clock-enable here
-- ... existing code
end if;
end if;
end process;
Compruebe también si ha especificado las restricciones de tiempo correctas para el reloj CLK
en el archivo UCF (ISE) o el archivo XDC (Vivado).
newclk
podría ser un problema como se discute ahora en mi respuesta extendida.newclk
has probado? ¿La pantalla dice algo sobre una frecuencia incorrecta? ¿Está seguro de que la frecuencia de entrada de su FPGA es de 125 MHz?
tubo
Bancos Carlton
david tweed
Bancos Carlton
usuario8352
disp_ena
la que le indica cuándo no está en supresión. Cuando disp_ena no es '1' en hw_image_generator.vhd, r,g yb son '0' (negro). En una pantalla analógica, el color se muestrea durante el intervalo de retroceso horizontal para determinar dónde se establece el negro.pjc50