library ieee; library unisim; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; entity init_ch7301c is generic ( input_clk: integer := 27_000_000; address: std_logic_vector(6 downto 0) := "1110110" -- 0x76 ); port ( clk: in std_logic; reset: in std_logic; finished: buffer std_logic; error: buffer std_logic; i2c_scl: inout std_logic; i2c_sda: inout std_logic; -- tmp dvi_reset: out std_logic; led: out std_logic_vector(7 downto 0); led_n: out std_logic; led_s: out std_logic; led_c: out std_logic ); end init_ch7301c; architecture Behavioral of init_ch7301c is signal i2c_reset: std_logic := '1'; signal i2c_execute: std_logic := '0'; signal i2c_busy: std_logic; signal i2c_busy_old: std_logic; signal i2c_address: std_logic_vector(6 downto 0); signal i2c_write: std_logic; signal i2c_data_in: std_logic_vector(7 downto 0); signal i2c_data_out: std_logic_vector(7 downto 0); signal i2c_error: std_logic; begin i2c_master: entity work.i2c_master generic map ( input_clk => input_clk, bus_clk => 100_000 ) port map ( clk => clk, reset_n => i2c_reset, ena => i2c_execute, addr => i2c_address, rw => not i2c_write, data_wr => i2c_data_in, busy => i2c_busy, data_rd => i2c_data_out, ack_error => i2c_error, scl => i2c_scl, sda => i2c_sda ); led_n <= error; led_s <= finished; led_c <= reset; main: process(clk, reset) -- ch7301c needs some time (>2µs) to init its i2c port after reset constant max_delay: integer := input_clk / 200_000; -- 5µs variable delay: integer range 0 to max_delay := 0; variable busy_count: integer range 0 to 10 := 0; begin if reset = '1' then delay := 0; busy_count := 0; finished <= '0'; error <= '0'; -- reset components dvi_reset <= '0'; i2c_execute <= '0'; i2c_reset <= '0'; elsif rising_edge(clk) then if delay = 5 then -- init components dvi_reset <= '1'; i2c_reset <= '1'; delay := delay + 1; elsif delay = max_delay then i2c_busy_old <= i2c_busy; -- remember old value if i2c_busy_old = '0' and i2c_busy = '1' then -- count rising edges on i2c_busy: -- command was accepted, ready for new one busy_count := busy_count + 1; end if; if i2c_error = '1' then -- abort on error i2c_execute <= '0'; error <= '1'; busy_count := 3; end if; case busy_count is when 0 => -- start configure sequence i2c_execute <= '1'; i2c_write <= '1'; i2c_address <= address; -- select register PM (power management) i2c_data_in <= x"49"; when 1 => -- enable clock pll, dvi encoder and transmitter i2c_data_in <= x"C0"; when 2 => -- select register DC (DAC control) i2c_data_in <= x"21"; when 3 => -- enable dac bypass and h/vsync outputs i2c_data_in <= x"09"; when 4 => -- select register TPCP (PLL charge pump control) i2c_data_in <= x"33"; when 5 => -- enable <= 65 MHz mode (datasheet table 10) i2c_data_in <= x"08"; when 6 => -- select register TPD (PLL divider) i2c_data_in <= x"34"; when 7 => -- enable <= 65 MHz mode (datasheet table 10) i2c_data_in <= x"16"; when 8 => -- select register TPF (PLL filter) i2c_data_in <= x"36"; when 9 => -- enable <= 65 MHz mode (datasheet table 10) i2c_data_in <= x"60"; when 10 => -- no more commands i2c_execute <= '0'; finished <= '1'; end case; else delay := delay + 1; end if; end if; end process main; end Behavioral;