Make init_ch7301c generic and prepare for embedding into main

This commit is contained in:
Klemens Schölhorn 2017-11-23 01:33:28 +01:00
parent a86cd90384
commit da4e8230c5
2 changed files with 63 additions and 77 deletions

View File

@ -25,7 +25,5 @@ NET "led(6)" LOC = AD24;
NET "led(7)" LOC = AE24; NET "led(7)" LOC = AE24;
NET "led_n" LOC = AF13; NET "led_n" LOC = AF13;
NET "led_e" LOC = AG23;
NET "led_s" LOC = AG12; NET "led_s" LOC = AG12;
NET "led_w" LOC = AF23;
NET "led_c" LOC = E8; NET "led_c" LOC = E8;

View File

@ -4,33 +4,33 @@ library unisim;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all; use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
-- Xilinx primitives (???)
use unisim.VComponents.all;
entity init_ch7301c is entity init_ch7301c is
generic (
input_clk: integer := 27_000_000;
address: std_logic_vector(6 downto 0) := "1110110" -- 0x76
);
port ( port (
clk: in std_logic; clk: in std_logic;
reset: in std_logic; reset: in std_logic;
finished: buffer std_logic;
error: buffer std_logic;
i2c_scl: inout std_logic; i2c_scl: inout std_logic;
i2c_sda: inout std_logic; i2c_sda: inout std_logic;
-- tmp
dvi_reset: out std_logic; dvi_reset: out std_logic;
dip: in std_logic_vector(7 downto 0);
led: out std_logic_vector(7 downto 0); led: out std_logic_vector(7 downto 0);
dip: in std_logic_vector(7 downto 0);
led_n: out std_logic; led_n: out std_logic;
led_e: out std_logic;
led_s: out std_logic; led_s: out std_logic;
led_w: out std_logic;
led_c: out std_logic led_c: out std_logic
); );
end init_ch7301c; end init_ch7301c;
architecture Behavioral of init_ch7301c is architecture Behavioral of init_ch7301c is
constant i2c_ch7301c: std_logic_vector(6 downto 0) := "1110110"; -- 0x76
signal i2c_reset: std_logic := '1'; signal i2c_reset: std_logic := '1';
signal i2c_execute: std_logic := '0'; signal i2c_execute: std_logic := '0';
signal i2c_busy: std_logic; signal i2c_busy: std_logic;
@ -40,13 +40,10 @@ architecture Behavioral of init_ch7301c is
signal i2c_data_in: std_logic_vector(7 downto 0); signal i2c_data_in: std_logic_vector(7 downto 0);
signal i2c_data_out: std_logic_vector(7 downto 0); signal i2c_data_out: std_logic_vector(7 downto 0);
signal i2c_error: std_logic; signal i2c_error: std_logic;
type states is (start, init, finished, error);
signal state: states := start;
begin begin
i2c_master: entity work.i2c_master generic map ( i2c_master: entity work.i2c_master generic map (
input_clk => 27_000_000, input_clk => input_clk,
bus_clk => 100_000 bus_clk => 100_000
) port map ( ) port map (
clk => clk, clk => clk,
@ -62,80 +59,71 @@ begin
sda => i2c_sda sda => i2c_sda
); );
led_n <= '1' when state = start else '0'; led_n <= error;
led_e <= '1' when state = init else '0'; led_s <= finished;
led_s <= '1' when state = finished else '0';
led_w <= '1' when state = error else '0';
led_c <= reset; led_c <= reset;
main: process(clk, reset) main: process(clk, reset)
variable delay_init: integer range 0 to 10_000 := 0; -- ch7301c needs some time (>2µs) to init its i2c port after reset
variable busy_count: integer range 0 to 2 := 0; 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 3 := 0;
begin begin
if reset = '1' then if reset = '1' then
delay := 0;
busy_count := 0; busy_count := 0;
delay_init := 0; finished <= '0';
state <= start; error <= '0';
-- reset components -- reset components
dvi_reset <= '0'; dvi_reset <= '0';
i2c_execute <= '0';
i2c_reset <= '0'; i2c_reset <= '0';
elsif rising_edge(clk) then elsif rising_edge(clk) then
case state is if delay = 5 then
when start => -- init components
delay_init := delay_init + 1; 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 delay_init = 5_000 then if i2c_error = '1' then
-- start components -- abort on error
dvi_reset <= '1'; i2c_execute <= '0';
i2c_reset <= '1'; error <= '1';
elsif delay_init = 10_000 then busy_count := 3;
delay_init := 0; end if;
-- start i2c init
state <= init;
busy_count := 0;
end if;
when init => case busy_count is
i2c_busy_old <= i2c_busy; -- remember old value when 0 =>
if i2c_busy_old = '0' and i2c_busy = '1' then -- no command accepted yet, insert first one
-- count rising edges on i2c_busy: i2c_execute <= '1';
-- command was accepted, ready for new one i2c_write <= '1';
busy_count := busy_count + 1; i2c_address <= address;
end if; i2c_data_in <= dip;
when 1 =>
if i2c_error = '1' then -- submit read command
-- abort on error i2c_write <= '0';
when 2 =>
-- read submitted, wait for results, no more commands
i2c_execute <= '0'; i2c_execute <= '0';
state <= error; if i2c_busy = '0' then
end if; led <= i2c_data_out;
busy_count := 3;
case busy_count is end if;
when 0 => when 3 =>
-- no command accepted yet, insert first one -- finished!
i2c_execute <= '1'; finished <= '1';
i2c_write <= '1'; null;
i2c_address <= i2c_ch7301c; end case;
i2c_data_in <= dip; else
when 1 => delay := delay + 1;
-- submit read command end if;
i2c_write <= '0';
when 2 =>
-- read submitted, wait for results, no more commands
i2c_execute <= '0';
if i2c_busy = '0' then
led <= i2c_data_out;
busy_count := 0;
state <= finished;
end if;
end case;
when finished =>
null;
when error =>
null;
end case;
end if; end if;
end process main; end process main;