library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity i2C_master is generic ( system_frequency : real := 50.0E6; -- 50 MHz i2c_rate : real := 20.0E3 -- 20 kHz ); port ( clk : in std_logic; resetn : in std_logic; go : in std_logic; ready : out std_logic; data_in : in std_logic_vector(23 downto 0); -- adress & command & data ack : out std_logic; -- i2c i2c_scl : out std_logic; -- A6 i2c_sda : inout std_logic -- B6 ); end entity; architecture rtl of i2c_master is constant mod_ctr_tempo : positive := integer(system_frequency/(i2c_rate)); constant mod_ctr_bit : positive := 35; type state is (wait_for_go, wait_for_i2clk, tx, wait_for_not_go); signal current_state : state; signal next_state : state; signal sdo : std_logic; signal ctr_tempo : natural range 0 to mod_ctr_tempo-1; signal end_tempo : std_logic; signal ctr_bit : natural range 0 to mod_ctr_bit-1; signal ack1 : std_logic; signal ack2 : std_logic; signal ack3 : std_logic; signal reg_data : std_logic_vector(data_in'range); signal cmd_data : std_logic_vector(1 downto 0); signal cmd_bit : std_logic_vector(1 downto 0); signal cmd_ack1 : std_logic_vector(1 downto 0); signal cmd_ack2 : std_logic_vector(1 downto 0); signal cmd_ack3 : std_logic_vector(1 downto 0); signal sclk : std_logic; signal i2c_clk : std_logic; signal ready_i : std_logic; begin i2c_sda <= 'Z' when sdo = '1' else '0'; i2c_scl <= '1' when sclk='1' else not i2c_clk when (ctr_bit>=3 and ctr_bit <= 30) else '0'; ack <= ack1 or ack2 or ack3; end_tempo <= '0' when ctr_tempo< mod_ctr_tempo-1 else '1'; process(resetn, clk) is begin if resetn = '0' then i2c_clk <= '0'; ctr_tempo <= 0; ctr_bit <= 0; reg_data <= (others => '0'); --sclk <= '1'; ACK1 <= '0'; ACK2 <= '0'; ACK3 <= '0'; ready <= '1'; current_state <= wait_for_go; elsif rising_edge(clk) then current_state <= next_state; ready <= ready_i; -- temporisation et i2_clk if current_state = wait_for_go then ctr_tempo <= 0; i2c_clk <= '0'; elsif end_tempo='0' then ctr_tempo <= ctr_tempo +1; else ctr_tempo <= 0; i2c_clk <= not i2c_clk; end if; -- reg_data case cmd_data is when "10" => reg_data <= data_in; when "11" => reg_data <= reg_data(22 downto 0)&'0'; when others => null; end case; -- ctr_bit case cmd_bit is when "10" => ctr_bit <= 0; when "11" => if ctr_bit null; end case; -- ack1 case cmd_ack1 is when "10" => ack1 <= '0'; when "11" => ack1 <= '1'; when others => null; end case; -- ack2 case cmd_ack2 is when "10" => ack2 <= '0'; when "11" => ack2 <= '1'; when others => null; end case; -- ack1 case cmd_ack3 is when "10" => ack3 <= '0'; when "11" => ack3 <= '1'; when others => null; end case; end if; end process; -------------------------------- -- FSM ------------------------------- process(current_state, end_tempo, i2c_clk, go,reg_data(23), i2c_sda,ctr_bit) is begin next_state <= current_state; ready_i <= '0'; cmd_ack1 <= "00"; cmd_ack2 <= "00"; cmd_ack3 <= "00"; cmd_bit <= "00"; cmd_data <= "00"; sdo <= '1'; sclk <= '0'; case current_state is when wait_for_not_go => if go = '0' then next_state <=wait_for_go; end if; ready_i <= '1'; cmd_bit <= "10"; cmd_data <= "10"; sclk <= '1'; when wait_for_go => if go = '1' then next_state <=wait_for_i2clk; end if; ready_i <= '1'; cmd_bit <= "10"; cmd_data <= "10"; sclk <= '1'; when wait_for_i2clk => if end_tempo='1' then next_state <=tx; cmd_bit <= "11"; end if; cmd_ack1 <= "10"; cmd_ack2 <= "10"; cmd_ack3 <= "10"; sclk <= '1'; when tx => if ctr_bit< mod_ctr_bit-1 then if i2c_clk='0' and end_tempo='1'then cmd_bit <= "11"; end if; elsif end_tempo='1'then next_state <= wait_for_go; end if; case ctr_bit is when 0 => sdo <= '1'; sclk <= '1'; -- start when 1 => sdo <= '0'; sclk <= '1'; when 2 => sdo <= '0'; sclk <= '0'; -- slave address when 3 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 4 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 5 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 6 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 7 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 8 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 9 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 10 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 11 => sdo <= '1'; -- ack if i2c_clk='0' and end_tempo='1' then if i2c_sda='0' then cmd_ack1 <= "10" ; else cmd_ack1 <= "11" ; end if; end if; -- cmd_ack1 <= "11" ; -- command when 12 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 13 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 14 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 15 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 16 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 17 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 18 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 19 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 20 => sdo <= '1'; -- ack if i2c_clk='0' and end_tempo='1' then if i2c_sda='0' then cmd_ack2 <= "10" ; else cmd_ack2 <= "11" ; end if; end if; -- cmd_ack2 <= "11" ; -- data when 21 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 22 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 23 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 24 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 25 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 26 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 27 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 28 => sdo <= reg_data(23); if i2c_clk='0' and end_tempo='1'then cmd_data <= "11"; end if; when 29 => sdo <= '1'; -- ack if i2c_clk='0' and end_tempo='1' then if i2c_sda='0' then cmd_ack3 <= "10" ; else cmd_ack3 <= "11" ; end if; end if; -- cmd_ack3 <= "11" ; --stop when 30 => sdo <= '0'; sclk <= '0'; when 31 => sdo <= '0'; sclk <= '1'; when others => sdo <= '1'; sclk <= '1'; ready_i <= '1'; end case; end case; end process; end architecture;