153 lines
4.8 KiB
VHDL
153 lines
4.8 KiB
VHDL
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;
|