--------------------------------------------------------------------------- -- (c) 2016 Alexey Spirkov -- I am happy for anyone to use this for non-commercial use. -- If my verilog/vhdl/c files are used commercially or otherwise sold, -- please contact me for explicit permission at me _at_ alsp.net. -- This applies for source and binary form and derived works. --------------------------------------------------------------------------- -- Recommended params: -- N=0x1800 CTS=0x6FD1 (28.625MHz pixel clock -> 48KHz audio clock) -- N=0x1000 CTS=0x6FD1 (28.625MHz pixel clock -> 32KHz audio clock) -- N=0x1000 CTS=0x6978 (27MHz pixel clock -> 32KHz audio clock) -- N=0x1800 CTS=0x6978 (27MHz pixel clock -> 48KHz audio clock) --------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity hdmi is generic ( FREQ: integer := 27000000; -- pixel clock frequency FS: integer := 48000; -- audio sample rate - should be 32000, 41000 or 48000 CTS: integer := 27000; -- CTS = Freq(pixclk) * N / (128 * Fs) N: integer := 6144 -- N = 128 * Fs /1000, 128 * Fs /1500 <= N <= 128 * Fs /300 -- Check HDMI spec 7.2 for details ); port ( -- clocks I_CLK_PIXEL : in std_logic; I_RESET : in std_logic; -- components I_R : in std_logic_vector(7 downto 0); I_G : in std_logic_vector(7 downto 0); I_B : in std_logic_vector(7 downto 0); I_BLANK : in std_logic; I_HSYNC : in std_logic; I_VSYNC : in std_logic; -- PCM audio I_AUDIO_PCM_L : in std_logic_vector(15 downto 0); I_AUDIO_PCM_R : in std_logic_vector(15 downto 0); -- VIDEO mode I_VIDEO_ID_CODE : in std_logic_vector(7 downto 0); -- ENCODED output O_R : out std_logic_vector(9 downto 0); O_G : out std_logic_vector(9 downto 0); O_B : out std_logic_vector(9 downto 0)); end entity; architecture rtl of hdmi is component hdmidataencoder generic ( FREQ: integer := 27000000; FS: integer := 48000; CTS: integer := 27000; N: integer := 6144 ); port ( i_pixclk : in std_logic; i_reset : in std_logic; i_hSync : in std_logic; i_vSync : in std_logic; i_blank : in std_logic; i_audioL : in std_logic_vector(15 downto 0); i_audioR : in std_logic_vector(15 downto 0); i_video_id_code : in std_logic_vector(7 downto 0); o_d0 : out std_logic_vector(3 downto 0); o_d1 : out std_logic_vector(3 downto 0); o_d2 : out std_logic_vector(3 downto 0); o_data : out std_logic ); end component; signal enc0out : std_logic_vector(9 downto 0); signal enc1out : std_logic_vector(9 downto 0); signal enc2out : std_logic_vector(9 downto 0); signal tx_in : std_logic_vector(29 downto 0); signal tmds_d : std_logic_vector(2 downto 0); signal data : std_logic; signal dataPacket0 : std_logic_vector(3 downto 0); signal dataPacket1 : std_logic_vector(3 downto 0); signal dataPacket2 : std_logic_vector(3 downto 0); signal delayLineIn: std_logic_vector(39 downto 0); signal delayLineOut: std_logic_vector(39 downto 0); signal ROut: std_logic_vector(7 downto 0); signal GOut: std_logic_vector(7 downto 0); signal BOut: std_logic_vector(7 downto 0); signal hSyncOut: std_logic; signal vSyncOut: std_logic; signal vdeOut: std_logic; signal dataOut: std_logic; signal vhSyncOut: std_logic_vector(1 downto 0); signal prevBlank: std_logic; signal prevData: std_logic; signal dataPacket0Out : std_logic_vector(3 downto 0); signal dataPacket1Out : std_logic_vector(3 downto 0); signal dataPacket2Out : std_logic_vector(3 downto 0); signal ctl0: std_logic; signal ctl1: std_logic; signal ctl2: std_logic; signal ctl3: std_logic; signal ctl_10: std_logic_vector(1 downto 0); signal ctl_32: std_logic_vector(1 downto 0); -- states type count_state is ( videoData, videoDataPreamble, videoDataGuardBand, dataIslandPreamble, dataIslandPreGuard, dataIslandPostGuard, dataIsland, controlData ); signal state: count_state; signal clockCounter: integer range 0 to 2047; signal r : std_logic_vector(9 downto 0); signal g : std_logic_vector(9 downto 0); signal b : std_logic_vector(9 downto 0); begin -- data should be delayed for 11 clocks to allow preamble and guard band generation -- delay line inputs delayLineIn(39 downto 32) <= I_R; delayLineIn(31 downto 24) <= I_G; delayLineIn(23 downto 16) <= I_B; delayLineIn(15) <= I_HSYNC; delayLineIn(14) <= I_VSYNC; delayLineIn(13) <= not I_BLANK; delayLineIn(12) <= data; delayLineIn(11 downto 8) <= dataPacket0; delayLineIn(7 downto 4) <= dataPacket1; delayLineIn(3 downto 0) <= dataPacket2; -- delay line outputs ROut <= delayLineOut(39 downto 32); GOut <= delayLineOut(31 downto 24); BOut <= delayLineOut(23 downto 16); hSyncOut <= delayLineOut(15); vSyncOut <= delayLineOut(14); vdeOut <= delayLineOut(13); dataOut <= delayLineOut(12); dataPacket0Out <= delayLineOut(11 downto 8); dataPacket1Out <= delayLineOut(7 downto 4); dataPacket2Out <= delayLineOut(3 downto 0); vhSyncOut <= vSyncOut & hSyncOut; ctl_10 <= ctl1&ctl0; ctl_32 <= ctl3&ctl2; FSA: process(I_CLK_PIXEL) is begin if(rising_edge(I_CLK_PIXEL)) then if(prevBlank = '0' and i_BLANK = '1') then state <= controlData; clockCounter <= 0; else case state is when controlData => if prevData = '0' and data = '1' then -- ok - data stared - needs data preamble state <= dataIslandPreamble; ctl0 <= '1'; ctl1 <= '0'; ctl2 <= '1'; ctl3 <= '0'; clockCounter <= 0; elsif prevBlank = '1' and I_BLANK = '0' then -- ok blank os out - start generation video preamble state <= videoDataPreamble; ctl0 <= '1'; ctl1 <= '0'; ctl2 <= '0'; ctl3 <= '0'; clockCounter <= 0; end if; when dataIslandPreamble => -- data island preable needed for 8 clocks if clockCounter = 8 then state <= dataIslandPreGuard; ctl0 <= '0'; ctl1 <= '0'; ctl2 <= '0'; ctl3 <= '0'; clockCounter <= 0; else clockCounter <= clockCounter + 1; end if; when dataIslandPreGuard => -- data island preguard needed for 2 clocks if clockCounter = 1 then state <= dataIsland; clockCounter <= 0; else clockCounter <= clockCounter + 1; end if; when dataIsland => if clockCounter = 11 then -- ok we at the end of data island - post guard is needed state <= dataIslandPostGuard; clockCounter <= 0; elsif prevBlank = '1' and I_BLANK = '0' then -- something fails - no data were detected but blank os out state <= videoDataPreamble; ctl0 <= '1'; ctl1 <= '0'; ctl2 <= '0'; ctl3 <= '0'; clockCounter <= 0; elsif data = '0' then -- start count and count only when data is over clockCounter <= clockCounter + 1; end if; when dataIslandPostGuard => -- data island postguard needed for 2 clocks if clockCounter = 1 then state <= controlData; clockCounter <= 0; else clockCounter <= clockCounter + 1; end if; when videoDataPreamble => -- video data preable needed for 8 clocks if clockCounter = 8 then state <= videoDataGuardBand; ctl0 <= '0'; ctl1 <= '0'; ctl2 <= '0'; ctl3 <= '0'; clockCounter <= 0; else clockCounter <= clockCounter + 1; end if; when videoDataGuardBand => -- video data guard needed for 2 clocks if clockCounter = 1 then state <= videoData; clockCounter <= 0; else clockCounter <= clockCounter + 1; end if; when videoData => if clockCounter = 11 then -- ok we at the end of video data - just switch to control state <= controlData; clockCounter <= 0; elsif I_BLANK = '1' then -- start count and count only when video is over clockCounter <= clockCounter + 1; end if; end case; end if; prevBlank <= I_BLANK; prevData <= data; end if; end process; blueout: b <= "1010001110" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "00" else "1001110001" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "01" else "0101100011" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "10" else "1011000011" when (state = dataIslandPreGuard or state = dataIslandPostGuard) and vhSyncOut = "11" else "1011001100" when state = videoDataGuardBand else enc0out; greenout: g <= "0100110011" when state = videoDataGuardBand else "0100110011" when state = dataIslandPreGuard or state = dataIslandPostGuard else enc1out; redout: r <= "1011001100" when state = videoDataGuardBand else "0100110011" when state = dataIslandPreGuard or state = dataIslandPostGuard else enc2out; delay_line: entity work.hdmi_delay_line port map ( i_clk => I_CLK_PIXEL, i_d => delayLineIn, o_q => delayLineOut ); dataenc: hdmidataencoder generic map ( FREQ => FREQ, FS => FS, CTS => CTS, N => N ) port map( i_pixclk => I_CLK_PIXEL, i_reset => I_RESET, i_blank => I_BLANK, i_hSync => I_HSYNC, i_vSync => I_VSYNC, i_audioL => I_AUDIO_PCM_L, i_audioR => I_AUDIO_PCM_R, I_VIDEO_ID_CODE => I_VIDEO_ID_CODE, o_d0 => dataPacket0, o_d1 => dataPacket1, o_d2 => dataPacket2, o_data => data ); enc0: entity work.encoder port map ( CLK => I_CLK_PIXEL, DATA => BOut, C => vhSyncOut, VDE => vdeOut, ADE => dataOut, AUX => dataPacket0Out, ENCODED => enc0out); enc1: entity work.encoder port map ( CLK => I_CLK_PIXEL, DATA => GOut, C => ctl_10, VDE => vdeOut, ADE => dataOut, AUX => dataPacket1Out, ENCODED => enc1out); enc2: entity work.encoder port map ( CLK => I_CLK_PIXEL, DATA => ROut, C => ctl_32, VDE => vdeOut, ADE => dataOut, AUX => dataPacket2Out, ENCODED => enc2out); o_r <= r; o_g <= g; o_b <= b; end rtl;