VHDL VGA интерфейс

Я моделировал VGA-интерфейс на плате DE0. У меня есть следующая модель для дисплея 640x480, который обновляется с частотой 60 Гц:

Основная модель:

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;

Синхронизировать модель:

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

Другой прямой пример - для PLL, сгенерированного из Quartus II, он работает нормально... спасибо, мистер Зилмер:). Модель компилируется нормально. Я загружаю его в DE0. Затем подключите его к монитору и ничего не отобразите на дисплее. Он должен отображать крест в центре экрана. Я использую дисплей Samsung с разрешением 1920x1080. Остановит ли это мою модель от отображения чего-либо? Или я сделал очевидную ошибку в моей модели. Я изменил некоторые стандартные значения синхронизации, чтобы соответствовать частоте обновления 60 Гц с 25 МГц clk. Спасибо д

1 ответ

Решение

Ваш код VHDL для синхронизации сущностей не анализируется. Вам не хватает end if и ваши начальные значения для h_sync а также v_sync нарушать ограничение подтипа:

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

куда 0 находится за пределами 1 to 800 или же 1 to 520,

Это поднимает вопрос о том, есть ли у вас другая архитектура для синхронизации сущностей, или же синхронизация просто не связана. Любой из них может дать вам неправильное указание (и ошибка не продемонстрирована в вашем вопросе).

Мы можем использовать тестовый стенд, чтобы продемонстрировать, что делает синхронизация в симуляции с тактовой частотой 25 МГц:

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;

И теперь мы можем устранить неполадки:

sync_tb_1.png

Первое, что мы заметили, это то, что h_sync не так. Также обратите внимание, что значение v_sync составляет около 16.667 мс (1/60 секунды).

Мы можем добавить счетчики h_pos и v_pos, чтобы мы могли посмотреть на h_sync, мы знаем, что счетчик h_pos работает, чтобы получить v_sync, который мы можем видеть в правой окрестности 60 Гц.

Поэтому я выбрал не то место, чтобы добавить end if, Исправление, которое также отделяет работу счетчиков от работы на их выходах (h_sync, v_sync и 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; 

У нас сейчас h_sync:

sync_tb_2.png

Обратите внимание, что теперь мы можем видеть вертикальный интервал гашения.

При увеличении мы видим горизонтальную белую линию в v_pos 280:

sync_tb_3.png

Наряду с вертикальной линией на h_pos 480 (+1):

sync_tb_4.png

И похоже, что это может сработать.

Единственное изменение дизайна, которое я мог бы испытать, это начать видимую часть строки с h_pos = 0, а видимую часть кадра - с v_pos = 0. Это позволило бы что-то еще адресовать пикселям для записи в кадре. буфер без добавления дополнительных счетчиков пикселей или необходимости делать смещение арифметики. (Пиксельная адресация обычно начинается с 0 для осей x и y).

Другие вопросы по тегам