【问题标题】:How do you displayed on HDMI screen with FPGA board?FPGA板如何在HDMI屏幕上显示?
【发布时间】:2019-12-11 12:22:24
【问题描述】:

我正在做一个项目。 该项目的目标是使用 FPGA 板将 USB 键盘和 HDMI 显示器相互连接。这意味着当我们按下按键时,我们希望在显示屏上显示键盘的每个字母和字符。

对于该项目,我选择了由 Digilent 基于 FPGA Xilinx Spartan6 构建的 Altys 板。

目前我已经将键盘与 FPGA 板连接起来,并且可以从键盘接收数据。这意味着当我按下字母时,板的 LED 会亮起。 我还为每个字母实现了一个 LED 序列。

现在我尝试将字母从键盘发送到带有 HDMI 输出端口的显示器,但我遇到了一些问题。

有没有人有任何想法或代码来显示 FPGA 板的 HDMI 端口?

感谢您的帮助

键盘连接代码

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

entity main is
    port(
        k_clk: in std_logic;
        k_d: inout std_logic;
        Led: out std_logic_vector(7 downto 0);
        clk: in std_logic;
        char: out std_logic_vector(7 downto 0)
    );
end main;


architecture Behavioral of main is

signal s_k_clk: std_logic :='0';
signal ch: std_logic_vector(7 downto 0) :=(others=>'0');
signal k_clk1: std_logic;

--signal pulseInternal : std_logic;
signal makeCodeTemp : std_logic_vector(7 downto 0);
signal makeCode : std_logic_vector(7 downto 0);
signal data : std_logic_vector(21 downto 0);
signal charTemp :std_logic_vector(7 downto 0);
--signal char :std_logic_vector(7 downto 0);
begin
--------------------------------------------------------------
makeCodeTemp <= data(9 downto 2); -- Scan code window
makeCode(7) <= makeCodeTemp(0);
makeCode(6) <= makeCodeTemp(1);
makeCode(5) <= makeCodeTemp(2);
makeCode(4) <= makeCodeTemp(3);
makeCode(3) <= makeCodeTemp(4);
makeCode(2) <= makeCodeTemp(5);
makeCode(1) <= makeCodeTemp(6);
makeCode(0) <= makeCodeTemp(7);
--------------------------------------------------------------
    Led(7 downto 0) <= ch(7 downto 0);
    k_clk1<=k_clk xor s_k_clk;
    p0:process(clk)
        begin
        if rising_edge(clk)then
            s_k_clk<=k_clk;
        end if;
    end process;

    p1:process(clk)
        begin
        if rising_edge(clk)then 
            if (k_clk1='1') then 
                data(21 downto 1) <= data(20 downto 0);
                data(0) <= k_d;
                --ch<=ch+1;
            end if;
        end if;
        end process;


    p2:process(clk)
    begin
         if rising_edge(clk) then
              if data(20 downto 13) = x"0F" then                                         char <= charTemp;
                  end if;
         end if;
    end process;

    p3:process(clk)
    begin
         if rising_edge(clk) then
              if charTemp=x"41" then
                ch(0)<='1';
                elsif charTemp=x"42" then
                ch(1)<='1';
                elsif charTemp=x"43" then
                ch(2)<='1';
                elsif charTemp=x"44" then
                ch(3)<='1';
elsif charTemp=x"45" then
                ch(4)<='1';
                end if;
         end if;
    end process;


charTemp <= x"41" when makeCode = x"1C" else --A        
            x"42" when makeCode = x"32" else --B        
            x"43" when makeCode = x"21" else --C        
            x"44" when makeCode = x"23" else --D        
            x"45" when makeCode = x"24" else --E        
            x"46" when makeCode = x"2B" else --F        
            x"47" when makeCode = x"34" else --G        
            x"48" when makeCode = x"33" else --H        
            x"49" when makeCode = x"43" else --I        
            x"4A" when makeCode = x"3B" else --J        
            x"4B" when makeCode = x"42" else --K        
            x"4C" when makeCode = x"4B" else --L        
            x"4D" when makeCode = x"3A" else --M        
            x"4E" when makeCode = x"31" else --N        
            x"4F" when makeCode = x"44" else --O        
            x"50" when makeCode = x"4D" else --P        
            x"51" when makeCode = x"15" else --Q        
            x"52" when makeCode = x"2D" else --R        
            x"53" when makeCode = x"1B" else --S        
            x"54" when makeCode = x"2C" else --T        
            x"55" when makeCode = x"3C" else --U        
            x"56" when makeCode = x"2A" else --V        
            x"57" when makeCode = x"1D" else --W        
            x"58" when makeCode = x"22" else --X        
            x"59" when makeCode = x"35" else --Y        
            x"5A" when makeCode = x"1A" else --Z        
            x"30" when makeCode = x"45" else --0        
            x"31" when makeCode = x"16" else --1        
            x"32" when makeCode = x"1E" else --2        
            x"33" when makeCode = x"26" else --3        
            x"34" when makeCode = x"25" else --4        
            x"35" when makeCode = x"2E" else --5        
            x"36" when makeCode = x"36" else --6        
            x"37" when makeCode = x"3D" else --7        
            x"38" when makeCode = x"3E" else --8        
            x"39" when makeCode = x"46" else --9        
            x"2F" when makeCode = x"5A" else --ENTER    
            x"5C" when makeCode = x"66" else --Backspace
            x"00";                           --Null
end Behavioral;

**HDMI显示代码:**

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;

entity dvid is
    Port ( clk_tmds0  : in  STD_LOGIC;
           clk_tmds90 : in  STD_LOGIC;
           clk_pixel  : in  STD_LOGIC;
           red_p      : in  STD_LOGIC_VECTOR (7 downto 0);
           green_p    : in  STD_LOGIC_VECTOR (7 downto 0);
           blue_p     : in  STD_LOGIC_VECTOR (7 downto 0);
           blank      : in  STD_LOGIC;
           hsync      : in  STD_LOGIC;
           vsync      : in  STD_LOGIC;
           red_s      : out STD_LOGIC;
           green_s    : out STD_LOGIC;
           blue_s     : out STD_LOGIC;
           clock_s    : out STD_LOGIC);
end dvid;

architecture Behavioral of dvid is
   COMPONENT TDMS_encoder
   PORT(
      clk     : IN  std_logic;
      data    : IN  std_logic_vector(7 downto 0);
      c       : IN  std_logic_vector(1 downto 0);
      blank   : IN  std_logic;          
      encoded : OUT std_logic_vector(9 downto 0)
      );
   END COMPONENT;

    COMPONENT qdr
    PORT(
        clk0  : IN std_logic;
        clk90 : IN std_logic;
        data  : IN std_logic_vector(3 downto 0);          
        qdr   : OUT std_logic
        );
    END COMPONENT;

   signal encoded_r, encoded_g, encoded_b : std_logic_vector(9 downto 0);

   -- for the control frames (blanking)
   constant c_red     : std_logic_vector(1 downto 0) := (others => '0');
   constant c_green   : std_logic_vector(1 downto 0) := (others => '0');
   signal   c_blue    : std_logic_vector(1 downto 0);

    signal   latched_r : std_logic_vector(9 downto 0) := (others => '0');
    signal   latched_g : std_logic_vector(9 downto 0) := (others => '0');
    signal   latched_b : std_logic_vector(9 downto 0) := (others => '0');

    signal   buffer_r : std_logic_vector(9 downto 0) := (others => '0');
    signal   buffer_g : std_logic_vector(9 downto 0) := (others => '0');
    signal   buffer_b : std_logic_vector(9 downto 0) := (others => '0');

    -- one hot encoded. Initial Value is important to sync with pixel chantges!
    signal   state     : std_logic_vector(4 downto 0) := "10000"; 

    signal   bits_r    : std_logic_vector(3 downto 0) := (others => '0');
    signal   bits_g    : std_logic_vector(3 downto 0) := (others => '0');
    signal   bits_b    : std_logic_vector(3 downto 0) := (others => '0');
    signal   bits_c    : std_logic_vector(3 downto 0) := (others => '0');

    -- output shift registers
    signal   sr_r      : std_logic_vector(11 downto 0):= (others => '0');
    signal   sr_g      : std_logic_vector(11 downto 0):= (others => '0');
    signal   sr_b      : std_logic_vector(11 downto 0):= (others => '0');
   signal   sr_c      : std_logic_vector(9 downto 0) := "0111110000";

    -- Gives a startup delay to allow the fifo to fill
    signal delay_ctr    : std_logic_vector(3 downto 0) := (others => '0');
begin   
   c_blue  <= vsync & hsync;

TDMS_encoder_red:   TDMS_encoder PORT MAP(clk => clk_pixel, data => red_p,   c => c_red,   blank => blank, encoded => encoded_r);
TDMS_encoder_green: TDMS_encoder PORT MAP(clk => clk_pixel, data => green_p, c => c_green, blank => blank, encoded => encoded_g);
TDMS_encoder_blue:  TDMS_encoder PORT MAP(clk => clk_pixel, data => blue_p,  c => c_blue,  blank => blank, encoded => encoded_b);

qdr_r: qdr PORT MAP(clk0 => clk_tmds0, clk90 => clk_tmds90, data => bits_r(3 downto 0), qdr => red_s);
qdr_g: qdr PORT MAP(clk0 => clk_tmds0, clk90 => clk_tmds90, data => bits_g(3 downto 0), qdr => green_s);
qdr_b: qdr PORT MAP(clk0 => clk_tmds0, clk90 => clk_tmds90, data => bits_b(3 downto 0), qdr => blue_s);
qdr_c: qdr PORT MAP(clk0 => clk_tmds0, clk90 => clk_tmds90, data => bits_c(3 downto 0), qdr => clock_s);

    process(clk_pixel)
    begin
        -- Just sample the encoded pixel data, to give a smooth transition to high speed domain
        if rising_edge(clk_pixel) then
            buffer_r <= encoded_r;
            buffer_g <= encoded_g;
            buffer_b <= encoded_b;
        end if;
    end process;

   process(clk_tmds0)
   begin
      if rising_edge(clk_tmds0) then 
            bits_r <= sr_r(3 downto 0);
            bits_g <= sr_g(3 downto 0);
            bits_b <= sr_b(3 downto 0);
            bits_c <= sr_c(3 downto 0);
            case state is 
                when "00001" =>
                    sr_r <= "00" & latched_r;
                    sr_g <= "00" & latched_g;
                    sr_b <= "00" & latched_b;
                when "00010" =>
                    sr_r <= "0000" & sr_r(sr_r'high downto 4);
                    sr_g <= "0000" & sr_g(sr_g'high downto 4);
                    sr_b <= "0000" & sr_b(sr_b'high downto 4);
                when "00100" =>
                    sr_r <= latched_r & sr_r(5 downto 4);
                    sr_g <= latched_g & sr_g(5 downto 4);
                    sr_b <= latched_b & sr_b(5 downto 4);
                when "01000" =>
                    sr_r <= "0000" & sr_r(sr_r'high downto 4);
                    sr_g <= "0000" & sr_g(sr_g'high downto 4);
                    sr_b <= "0000" & sr_b(sr_b'high downto 4);
                when others =>
                    sr_r <= "0000" & sr_r(sr_r'high downto 4);
                    sr_g <= "0000" & sr_g(sr_g'high downto 4);
                    sr_b <= "0000" & sr_b(sr_b'high downto 4);
            end case;

            -- Move on to the next state
            state       <= state(state'high-1 downto 0) & state(state'high);

            -- Move the TMDS clock signal shift register
            sr_c <= sr_c(3 downto 0) & sr_c(sr_c'high downto 4);
            if delay_ctr(delay_ctr'high) = '0' then 
                delay_ctr <= delay_ctr +1;
            end if;

            -- Move the encoded pixel data into the fast clock domain
            latched_r <= buffer_r;
            latched_g <= buffer_g;
            latched_b <= buffer_b;
      end if;
   end process;

end Behavioral;


【问题讨论】:

  • 您需要实现产生视频帧的逻辑。您必须将其输出连接到 HDMI 端口才能发送到显示器。您的逻辑应该能够以某种方式调整/更新生成的视频帧数据,以应对您在键盘上键入的字符。
  • 如果您想要额外的挑战(额外的功劳?),请尽量避免为整个帧分配缓冲区,并一次渲染一个字符行。
  • 用 VGA 热身可能是一个有用的垫脚石(较低的复杂性,相同的想法)。

标签: fpga


【解决方案1】:

查看此用户指南,其中介绍了在 atlys 板上实现 HDMI 作为参考设计。 https://www.xilinx.com/support/documentation/application_notes/xapp495_S6TMDS_Video_Interface.pdf

【讨论】:

    猜你喜欢
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-20
    相关资源
    最近更新 更多