-- Tool to check if VGA signals are good -- To use: -- Connect 25MHz clock -> clk_good should blink off and on -- Connect HSYNC -> hsync_good should turn on (solid) -- Connect VSYNC -> vsync_good should turn on (solid) -- Connect any RGB data pin, which is 1 when the region is valid and 0 otherwise (the `valid` signal itself will work) -- -> h_front_porch_good should turn on (solid to the naked eye, with a flicker during vsync) -- -> h_blanking_good should turn on (solid to the naked eye, with a flicker during vsync) -- TODO: check vertical porches library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity vga_check is port( clk : in std_logic; -- 25.1 MHz clock hsync : in std_logic; -- Horizontal sync vsync : in std_logic; -- Vertical sync data : in std_logic; -- Any data pin, which is 0 during blanking and 1 otherwise clk_good : out std_logic; -- Whether there is a clock signal at all hsync_duration_good : out std_logic; -- Whether the HSYNC duration is correct h_front_porch_good : out std_logic; -- Whether front porch is correct h_blanking_good : out std_logic; -- Whether horizontal blanking is correct vsync_duration_good : out std_logic -- Whether the VSYNC duration is correct ); end; architecture synth of vga_check is -- The column count is broken down below: -- 0-639 (640) Image data -- 640-655 (16) Front porch -- 656-751 (96) Sync pulse (sync goes low) -- 752-799 (48) Back porch -- Row count is similar: -- 0-479 (480) Image data -- 480-489 (10) -- 490-491 (2) -- 492-524 (33) constant H_FRONT_PORCH : integer := 16; constant HSYNC_PULSE_CYCLES : integer := 96; constant H_BACK_PORCH : integer := 48; constant V_FRONT_PORCH : integer := 10*800; constant VSYNC_PULSE_CYCLES : integer := 2*800; constant V_BACK_PORCH : integer := 33*800; constant CLK_GOOD_BITS : integer := 24; signal clk_counter : unsigned(CLK_GOOD_BITS-1 downto 0); signal hsync_last : std_logic; signal vsync_last : std_logic; signal data_last : std_logic; -- Count of clock cycles that data signal has been low (H or V blanking) -- During vertical blanking, this can be 45 lines * 800 pixels = 36000 cycles (+ H blanking) signal blanking_counter : unsigned(16 downto 0); -- Count of clock cycles that the HSYNC pin has been low -- This should be 96 cycles -> 7 bits signal hsync_counter : unsigned(6 downto 0); -- Count of clock cycles that the VSYNC pin has been low -- This should be 2 rows * 800 cycles/row = 1600 cycles -> 11 bits signal vsync_counter : unsigned(10 downto 0); begin process(clk) begin if rising_edge(clk) then clk_counter <= clk_counter + 1; end if; end process; clk_good <= clk_counter(CLK_GOOD_BITS-1); process(clk) begin if rising_edge(clk) then end if; end process; -- Check that the hsync is low for exactly the right number of clock cycles process(clk) begin if rising_edge(clk) then -- Keep the previous values of the signals; when we detect an edge, we can look at the -- appropriate counter and make sure that it was the right number of cycles. hsync_last <= hsync; vsync_last <= vsync; data_last <= data; -- Update the counters while the respective signals are low -- TODO: Make them saturate so they don't roll over and accidentally give the right value (although this would be *really* unlikely) if data = '0' then blanking_counter <= blanking_counter + 1; else blanking_counter <= 17d"0"; end if; if hsync = '0' then hsync_counter <= hsync_counter + 1; else hsync_counter <= 7d"0"; end if; if vsync = '0' then vsync_counter <= vsync_counter + 1; else vsync_counter <= 11d"0"; end if; -- Finally, update the outputs if the counts were right at the appropriate times -- HSYNC is falling, this is the end of the front porch if hsync_last = '1' and hsync = '0' then if blanking_counter = H_FRONT_PORCH then h_front_porch_good <= '1'; else h_front_porch_good <= '0'; end if; end if; -- Otherwise, leave h_front_porch_good at its previous value -- HSYNC is rising, this is the end of the HSYNC pulse if hsync_last = '0' and hsync = '1' then if hsync_counter = HSYNC_PULSE_CYCLES then hsync_duration_good <= '1'; else hsync_duration_good <= '0'; end if; end if; -- data is rising, this is the end of the back porch if data_last = '0' and data = '1' then if blanking_counter = H_FRONT_PORCH + HSYNC_PULSE_CYCLES + H_BACK_PORCH then h_blanking_good <= '1'; else h_blanking_good <= '0'; end if; end if; -- VSYNC is rising, this is the end of the VSYNC pulse if vsync_last = '0' and vsync = '1' then if vsync_counter = VSYNC_PULSE_CYCLES then vsync_duration_good <= '1'; else vsync_duration_good <= '0'; end if; end if; end if; end process; end;