0

I've been modelling a VGA interface on the DE0 board. I have the following model for a 640x480 display which refreshes at 60Hz:

Main model:

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;

Sync model:

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----------

The other direct instantiation is for PLL generated from Quartus II it seems to work fine.. thank you Mr Zilmer :). The model compiles fine. I load it into the DE0. Then connect this to a monitor and get nothing on the display. It should display a cross in the centre of the screen. The display I am using is a Samsung with 1920x1080. Would this stop my model from displaying anything? Or have I made a obvious mistake in my model. I have changed some of the standard timing values to fit a 60Hz refresh with 25Mz clk. Thanks D

hoboBob
  • 832
  • 1
  • 17
  • 37
  • Please provide a testbench for the `SYNC` entity, so that, one can easily check the timing! I think this question should be asked on Electrical Engineering. – Martin Zabel Feb 06 '16 at 20:23
  • Hi Martin, I have updated the model with a few changes to the integer values for h_pos and v_pos. These are seen reflected through the model. Also and most importantly a change to an IF statement (I never knew you could nest an IF statement appending a ELSE statement!) Well the model compiles and this time I get my samsung 1920x1080 to tell me this is not optimal mode!.... When I try to simulate the model in ModSim, the option to simulate my VGA file is not their, in that, the file is there but extension icon is not. Hope this makes sense, and thanks for the reply – hoboBob Feb 06 '16 at 21:01
  • Please check your monitor datasheet to check wether your intended video mode is supported. – Martin Zabel Feb 06 '16 at 22:07
  • There's a problem with your code (see the answer below). The question of whether or not your monitor can do 60 Hz VGA requires examining it's documentation (but it probably does). –  Feb 07 '16 at 01:18
  • You stated that your code compiles, but it does not as user1155120 pointed out. (I couldn't check this on my mobile.) So, please give the right code! Maybe, you broke it while editing the question. – Martin Zabel Feb 07 '16 at 08:18

1 Answers1

4

Your VHDL code for entity sync doesn't analyze. You are missing an end if and your initial values for h_sync and v_sync violate the subtype constraint:

    signal h_pos: integer range 1 to 800 := 0;
    signal v_pos: integer range 1 to 520 := 0;

Where 0 is outside the bounds of 1 to 800 or 1 to 520.

This raises the question of whether or not you have another architecture for entity sync, or whether sync is simply unbound. Either of which might give you an incorrect indication (and the error isn't demonstrated in your question).

We can use a testbench to demonstrate what sync does in simulation with a 25 MHz clock:

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;

And now we get to troubleshoot:

sync_tb_1.png

The first thing we notice is h_sync is wrong. Also note that v_sync appears to be around 16.667 ms (1/60th of a second).

We can add the h_pos and v_pos counters so we can look at h_sync, we do know the h_pos counter is running to get a v_sync we can see in the right neighborhood of 60 Hz.

So I picked the wrong place to add the end if. Correcting that also separates operating the counters from operating on their outputs (h_sync, v_sync and 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; 

We have h_sync now:

sync_tb_2.png

Notice we can see the vertical blanking interval now too.

Zooming in we can see there a horizontal white line at v_pos 280:

sync_tb_3.png

Along with a vertical line at h_pos 480 (+1):

sync_tb_4.png

And this looks like it just might work.

The only design change I might be tempted to make would be to start the visible portion of the line at h_pos = 0 and the the visible portion of the frame at v_pos = 0. This would allow something else to address pixels for writing in a frame buffer without adding additional pixel counters or having to do offset arithmetic. (Pixel addressing usually starts at 0 for x and y axis).

  • Hi, Thank you for pointing out where I have made errors in the code. I've updated these on the original question. – hoboBob Feb 09 '16 at 13:46
  • The question didn't need updating to fix the code. If you update the code in your question the error can no longer easily be discerned, making the question and answer less useful as a resource to other stackoverflow users. –  Feb 09 '16 at 19:51