Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
10 years ago

VGA - output of a graphic not stable

Hello Community,

I got a problem with my current VGA project. Here a few informations about what I want to do:

- first ten 8-bit-rows are used to display some text like variables or sth similar. --> first 80 pixel rows are reserved for the text output

- on the other part of the screen I want to display a graphic (described in a 32x32 memory) which I can move with some pushbuttons up/down/left/right

My problem is that I don't get a stable state of my graphic. The splitting of the screen and the output of the text is no problem but I'm not able to get the graphic output correctly working.

My current graphic should be a simple square (just the borders) but I get rotating stripes in the size of 64x64 on my screen (the graphic should only be 32x32)

I think with my current code I just read some of the values from the middle of my memory. But I want to read a new 32-bit-std_logic_vector every new pixel line. These 32-bit vector I want to split up to the single pixels with a counter and my pixelclock.

Here is my code for the graphic (without my VGA-sync and all the files used to display the text)

library ieee;use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity graphic is
    generic( address_width : integer := 5;
             data_width    : integer := 32);
    port( clock                  : in  std_logic;
          --graphic_address      : in  std_logic_vector(address_width-1 downto 0);
          pixel_column, pixel_row     : in  unsigned(9 downto 0);
             move_up, move_down            : in std_logic;
             move_left, move_right        : in std_logic;
             horiz_sync                        : in std_logic;
          graphic_output                 : out std_logic);
end graphic;
architecture behavior of graphic is
    signal clock_counter            :    unsigned(24 downto 0) := (others => '0');
    signal clock_counter_37_9k    :    unsigned(24 downto 0) := (others => '0');
    signal clock_10hz                :     std_logic;
    signal clock_37_9k            :    std_logic;
    signal modified_clock        :    std_logic;
    signal graphic_read_address:    std_logic_vector(address_width-1 downto 0);
    signal horiz_position        :    unsigned(9 downto 0)    := "0000000000";
    signal vert_position            :    unsigned(9 downto 0)    := "0001010001";
    signal graphic_output_complete_row    :     std_logic_vector(data_width-1 downto 0);
    signal counter_horiz            :    unsigned(5 downto 0) := "000000";
    signal counter_vert            :    unsigned(4 downto 0) := "00000";
    signal pixel_column_prev    :    unsigned(9 downto 0)    := "0000000000";
    signal display_graphic_on    :    std_logic :='0';
    component Graphic_RAM
    port(    address    : IN STD_LOGIC_VECTOR (address_width-1 DOWNTO 0);
            clock        : IN STD_LOGIC  := '1';
            data        : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
            wren        : IN STD_LOGIC ;
            q            : OUT STD_LOGIC_VECTOR (31 DOWNTO 0));
    end component;
     
begin
    -- RAM wrapper
    Graphic_RAM_inst: Graphic_RAM port map(        
                data        =>     "00000000000000000000000000000000",
                clock         =>       horiz_sync,
                address      =>       std_logic_vector(graphic_read_address),
                wren        =>       '0',
                q           =>       graphic_output_complete_row
                );
                
-- create a 10 hz clock for changing position at this speed    
process(clock)
begin
    if rising_edge(clock) then
        if (clock_counter < 1999999) then
            clock_counter <= clock_counter +1;
        else
            clock_10hz <= not clock_10hz;
            clock_counter <= (others => '0');
        end if;
    end if;
end process;
        
-- process moves the object at a speed of 10 Hz
process(clock_10hz) 
begin
    if rising_edge(clock_10hz) then
        -- vertical movement
        if ((move_up = '0') and (move_down = '1')) then
            if (vert_position > "0001010001") then -- checks if we already reached the upper border of the graphic area
                vert_position <= vert_position - 1;
            end if;
        elsif (move_down = '0') then
            if (vert_position < "1001011000") then -- checks if we already reached the lower border of the graphic area
                vert_position <= vert_position + 1;
            end if;
        end if;
        -- horizontal movement
        if ((move_left = '0') and (move_right = '1')) then
            if (horiz_position > "0000000000") then -- checks if we already reached the left border of the graphic area
                horiz_position <= horiz_position - 1;
            end if;
        elsif (move_right = '0') then
            if (horiz_position < "1100100000") then -- checks if we already reached the right border of the graphic area
                horiz_position <= horiz_position + 1;
            end if;
        end if;
    end if;    
end process;
process(horiz_sync, clock, vert_position, pixel_row)
begin
    if (pixel_row = vert_position) then
        display_graphic_on <= '1';    -- Flag to recognize when to display the graphic for the next 32 rows
    elsif (pixel_row = (vert_position+32)) then
        display_graphic_on     <= '0';
    end if;
end process;
-- vertical positioning of the graphic
process(horiz_sync, clock, vert_position, pixel_row)
begin
    
    if rising_edge(horiz_sync) then
        if ((display_graphic_on = '1') and (counter_vert < "11110")) then
            graphic_read_address <= std_logic_vector(counter_vert);
            counter_vert <= counter_vert + 1;
            if (counter_vert > "11110") then
                counter_vert             <= "00000";
                
            end if;
        end if;
    end if;
end process;
process (pixel_column, pixel_row, clock)
begin
    if rising_edge(clock) then
        if (horiz_position <= unsigned(pixel_column) + 32) and (horiz_position + 32 >= unsigned(pixel_column)) and
            (vert_position <= unsigned(pixel_row)    + 32) and (vert_position + 32 >= unsigned(pixel_row)) then
            if (counter_horiz <= "011111") then
                graphic_output <= graphic_output_complete_row(to_integer(counter_horiz));
                counter_horiz <= counter_horiz +1;
            else
                counter_horiz <= "000000";
                graphic_output <= '0';
            end if;
        else
            graphic_output <= '0';
        end if;
    end if;
end process;
end behavior;

Hopefully somebody can help me with my problem. I tried to get this working for days now but I have no idea how to solve this...

Best,

orPoG

here a picture of what I get on my screen currently. (It looks like if I get one single line but thats just my camera... actually there are two very thin stripes next to each other. I think that are my borders of the square if I repeat them)

http://www.alteraforum.com/forum/attachment.php?attachmentid=12945&stc=1

2 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Dont generate a clock with logic - generate a clock enable instead. Logic clocks can cause all sorts of timing problems. Stick with the same system clock throughout with a 10Hz clock enable.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Thanks for your hint!

    Unfortunately I have never worked with a clock enable and I'm not sure if this causes the problem I got. Because I just use the 10Hz clock to move the graphic on the screen to the left/right/up/down and not for synchronization or something else on the screen. I also tried to use the pixelclock instead of the 10Hz clock. I had the same problem like before but also the problem that it was impossible to control the position of my square because it moved very fast to the corners of the screen.

    Thanks for your help,

    orPoG