Quantcast
Channel: Altera Forums
Viewing all articles
Browse latest Browse all 19390

VHDL How to Design a Screen (Frame) Buffer

$
0
0
Hello,

I am trying to use a screen buffer to store, change and output the bits of a video data to the DVI transmit interface.

  • I am using Altera Cyclone III development kit.
  • I will be using 1440x900@60Hz for my resolution so my pixel clock rate is 106.7 MHz. The DVI interface is written and is tested within another project that was not using a screen buffer, but I think it is not a source to any problem.



I can not decide what kind of a RAM to use as the screen buffer. With some reading, I came to the conclusion that dual port inferred RAM would be the best choice. However, I am not sure how to use its read and write ports. I already managed to infer a ram block and instantiated it with using a function that generates a .mif file.

My current progress is as follows:

  • Words will be 16 bits long. This means that RAM will have 81K addresses.
  • The READ port will always have its write enable signal LOW (0).
  • The WRITE port will always have its write enable signal HIGH (1).
  • So I am trying to write and read SIMULTANEOUSLY. The clock for both is the same.


Code:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity FrameBuffer is
    port
    ( 
        data_a  : in std_logic_vector(15 downto 0);
        data_b  : in std_logic_vector(15 downto 0);
        addr_a  : in natural range 0 to 80999;
        addr_b  : in natural range 0 to 80999;
        we_a        : in std_logic ;
        we_b        : in std_logic ;
        clk_106    : in std_logic;
        q_a    : out std_logic_vector(15 downto 0);
        q_b    : out std_logic_vector(15 downto 0)
    );


end FrameBuffer;


architecture rtl of FrameBuffer is


    -- Build a 2-D array type for the RAM
    subtype word_t is std_logic_vector(15 downto 0);
    type memory_t is array(0 to 80999) of word_t;


    FUNCTION initialize_ram
        return memory_t is
        variable result : memory_t;
        BEGIN
            FOR i IN 0 to 80999 LOOP
                result(i) := "1111111111111111";
            END LOOP;
        RETURN result;
    END initialize_ram;




    -- Declare the RAM
    shared variable ram : memory_t :=initialize_ram ;


begin




    -- Port A
    process(clk_106)
    begin
        if(rising_edge(clk_106)) then -- Port A
            if(we_a = '1') then
                ram(addr_a) := data_a;
            -- Read-during-write on the same port returns NEW data
                q_a <= data_a;
            else
            -- Read-during-write on the mixed port returns OLD data
                q_a <= ram(addr_a);
            end if;
        end if;
    end process;


    -- Port B
    process(clk_106)
    begin
        if(rising_edge(clk_106)) then -- Port B
            if(we_b = '1') then
                ram(addr_b) := data_b;
            -- Read-during-write on the same port returns NEW data
                q_b <= data_b;
            else
            -- Read-during-write on the mixed port returns OLD data
                q_b <= ram(addr_b);
            end if;
        end if;
    end process;
end rtl;

I think I managed to write data inside the RAM, but now I am stuck with feeding my data to DVI. For the time being I hold 1 bit per pixel inside the ram, and conclude the 24bit color inside the DVI block I designed. The color depends on the coordinate of the hcounter and vcounter. So, reading 16 bits from the RAM is not enough to pass it on to DVI, I need to pass it bit by bit at each clock edge.

Currently I do it as follows:

Code:

process(clk106M, locked_sgnl)
begin
  if locked_sgnl = '0' then
                address_counter <= (others => '0');
                counter <= "10000";
                pixel_in_register <= (others => '0');
  elsif rising_edge(clk106M) and (locked_sgnl = '1') then
    if (address_counter < "10011110001101000") then
                        if counter >= 16 then
                                pixel_in_register <= pixel_in;
                                address_counter <= address_counter + '1';
                                counter <= "00000";
                        else
                                pixel_in_sgnl <= pixel_in_register(0);
                                pixel_in_register <= '0' & pixel_in_register(15 downto 1);
                                counter <= counter + '1';
                        end if;
          else
                        address_counter <= (others => '0');
          end if;


 end if;
end process;


 buffer_address_dvi <= address_counter;


I use a register and hold the buffer output inside. Then at each clock cycle for 16 cycles, I output the LSB of the contents of the register and shift the data to right. What stucks in my head is that if I need to generate the read address earlier or not.


Currently if there is a 0 in buffer, that pixel corresponds to green. If 1, it corresponds to blue. What I do is that I instantiate the RAM full of '1's. Then I write '0' to a portion of it, and try to observe a thick horizontal line on the screen. Fortunately enough, I see that horizontal line, but it is not stationary. Its sweeping the screen from top to bottom or bottom to top, I can not differentiate. What might the cause of that particular issue?

Viewing all articles
Browse latest Browse all 19390

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>