VHDL Cómo diseñar un búfer de pantalla (marco)

2

Estoy tratando de usar un búfer de pantalla para almacenar, cambiar y enviar los bits de un video a la interfaz de transmisión DVI.

  • Estoy usando el kit de desarrollo Altera Cyclone III.
  • Estaré usando 1440x900 @ 60Hz como resolución, por lo que mi velocidad de reloj de píxeles es de 106.7 MHz. La interfaz DVI está escrita y probada en otro proyecto que no estaba usando un búfer de pantalla, pero creo que no es la fuente de ningún problema.

No puedo decidir qué tipo de RAM usar como búfer de pantalla. Con algunas lecturas, llegué a la conclusión de que la RAM con doble puerto inferido sería la mejor opción. Sin embargo, no estoy seguro de cómo usar sus puertos de lectura y escritura. Ya logré inferir un bloque ram y lo instalé utilizando una función que genera un archivo .mif.

Mi progreso actual es el siguiente:

  • Las palabras tendrán una longitud de 16 bits. Esto significa que la RAM tendrá direcciones 81K.
  • El puerto READ siempre tendrá su señal de habilitación de escritura BAJA (0).
  • El puerto WRITE siempre tendrá su señal de habilitación de escritura HIGH (1).

Así que estoy tratando de escribir y leer SIMULTÁNEAMENTE. El reloj para ambos es el mismo.

No incrusté ningún código por simplicidad, y traté de ser lo más claro posible. Si es necesario o deseable, publicaré fragmentos de código.

Mi pregunta es la siguiente: ¿Existe una mejor manera de abordar este problema, porque hasta ahora mis intentos no han tenido éxito? Parece que no puedo escribir en la memoria RAM y no puedo encontrar la razón para ello. Algo me dice que tengo problemas con el tiempo, si alguien se puede relacionar con él, por favor, ayúdame.

¡Gracias!

Editar:

Sí, estoy almacenando 1 bit por píxel para fines de almacenamiento y estoy decidiendo el color en el bloque de transmisión DVI que viene después. La decisión se basa en las coordenadas de hcounter y vcounter del DVI. Instalo la RAM con '1' en cada celda. Lo verifico al leerlo y enviarlo a la pantalla con un color constante:

 if vcounter < 900 then
   if hcounter < 1440 then
        if pixel_in_sgnl = '0' then
         dviRed  <= "11111111";
         dviGreen<= "00000000";
         dviBlue <= "00000000";
         else
         dviRed   <= "00000000";
         dviBlue  <= "11111111";
         dviGreen <= "00000000";
        end if;

Sin embargo, cuando intento modificar el contenido de la RAM y luego leerlo y mostrarlo en la pantalla, todavía lo leo como 1, porque el color no cambia. Por ejemplo, en el siguiente código, quiero escribir "0000000000000000" en la ubicación 10000, y como resultado debo observar una línea de color diferente en un fondo constante. Espero poder ser lo suficientemente claro.

FB: FrameBuffer port map ( data_a => "0000000000000000",
                                data_b => "ZZZZZZZZZZZZZZZZ",   
                                addr_a => 10000, --address_write_sgnl,
                                addr_b => address_read_sgnl,
                                we_a  => '1',
                                we_b => '0',
                                clk_106 => DVI_clock,
                                q_a => open,
                                q_b => pixel_data_sgnl);

Esta es la RAM inferida que he encontrado en línea y modificada ligeramente:

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;

Editar2:

Creo que logré resolver el problema de escribir en la RAM, sin embargo, todavía puedo hablar sobre eso para mejorar mi diseño. Ahora estoy atascado con la alimentación de mi salida de búfer a DVI. Como mencioné anteriormente, tengo 1 bit por píxel en la RAM, pero el ancho de RAM es de 16 bits. Así que necesito almacenar estos 16 bits y enviarlos a DVI uno por uno en cada borde del reloj DVI. Lo hago de la siguiente manera:

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;

Utilizo un registro y mantengo dentro la salida del búfer. Luego, en cada ciclo de reloj durante 16 ciclos, saco el LSB del contenido del registro y cambio los datos a la derecha. Lo que me impresiona es que si necesito generar la dirección de lectura antes o no.

Actualmente, si hay un 0 en el búfer, ese píxel corresponde a verde. Si es 1, corresponde al azul. Lo que hago es que hago una instancia de la memoria RAM llena de '1's. Luego escribo '0' en una parte de él e intento observar una línea horizontal gruesa en la pantalla. Afortunadamente, veo esa línea horizontal, pero no es estacionaria. Su barrido de la pantalla de arriba a abajo o de abajo a arriba, no puedo diferenciar. ¿Cuál podría ser la causa de este problema en particular?

    
pregunta Toygun Başaklar

1 respuesta

0

Lo encontré hace un par de días:

Estaba aumentando la dirección del búfer de cuadros no solo durante la parte activa del DVI sino también en los períodos de supresión. Esto dio lugar a un cambio en la pantalla. Gracias a todos por sus respuestas.

    
respondido por el Toygun Başaklar

Lea otras preguntas en las etiquetas