--345678901234567890123456789012345678901234567890123456789012345678901234567890 --****************************************************************************** --* --* Module : I2C_IF --* File : i2c_if.vhd --* Library : ieee --* Description : It is the I2C interface module --* Simulator : Modelsim --* Synthesizer : Lenoardo Spectrum + Quartus II --* Author/Designer : C. SOOS ( Csaba.Soos@cern.ch) --* --* Revision history: --* 9-Apr-2003 CS Original coding --* --* 17-Jan-2011 VA Move the bidirectional cell to the top --****************************************************************************** library ieee; use ieee.std_logic_1164.all; entity i2c_if is port ( clock : in std_logic; arstn : in std_logic; i2c_address : in std_logic_vector ( 7 downto 0); i2c_wrdata : in std_logic_vector ( 7 downto 0); i2c_rddata : out std_logic_vector ( 7 downto 0); i2c_rdwrn : in std_logic; i2c_req : in std_logic; i2c_ack : out std_logic; i2c_error : out std_logic; -- i2c_sda : inout std_logic; i2c_sda_i : in std_logic; i2c_sda_o : out std_logic; i2c_sda_e : out std_logic; i2c_scl : out std_logic); end i2c_if; library ieee; use ieee.std_logic_1164.all; use work.my_conversions.all; use work.my_utilities.all; architecture SYN of i2c_if is type scl_state is ( SCL_HIGH, SCL_GOLOW, SCL_LOW, SCL_GOHIGH ); type i2c_state is ( I2C_IDLE, I2C_TXSTART, I2C_CTRLWR, I2C_CTRLWRACK, I2C_TXADDR, I2C_ADDRACK, I2C_TXDATA, I2C_DATAACK, I2C_TXSTART2, I2C_CTRLRD, I2C_CTRLRDACK, I2C_RXDATA, I2C_TXNACK, I2C_TXSTOP, I2C_READY ); signal s_sda_ena : std_logic; signal s_sda_out : std_logic; signal s_sda_in : std_logic; begin -- SYN -- move the bidirectional cell to the top i2c_sda_o <= s_sda_out; i2c_sda_e <= s_sda_ena; s_sda_in <= i2c_sda_i; --process (i2c_sda, s_sda_ena, s_sda_out) --begin -- process -- if s_sda_ena = '1' then -- i2c_sda <= s_sda_out; -- s_sda_in <= '1'; -- else -- i2c_sda <= 'Z'; -- s_sda_in <= i2c_sda; -- end if; --end process; proc_main: process (clock, arstn) variable b_scl_tick : boolean; variable b_scl_low : boolean; variable b_scl_high : boolean; variable b_scl_rise : boolean; -- variable b_scl_fall : boolean; variable b_scl_ena : boolean; variable b_bitct_clr : boolean; variable b_bitct_inc : boolean; variable b_read_sdi : boolean; variable b_i2c_req : boolean; variable sda_cmux : std_logic; variable sda_amux : std_logic; variable sda_dmux : std_logic; variable bit_count : std_logic_vector ( 2 downto 0); variable scl_timer : std_logic_vector ( 9 downto 0); variable scl_present : scl_state; variable scl_next : scl_state; variable i2c_present : i2c_state; variable i2c_next : i2c_state; begin -- process proc_main if arstn = '0' then -- asynchronous reset (active low) i2c_scl <= '1'; s_sda_out <= '1'; s_sda_ena <= '1'; i2c_rddata <= (others => '1'); i2c_ack <= '0'; i2c_error <= '0'; b_scl_tick := false; b_scl_low := false; b_scl_high := true; b_scl_rise := false; -- b_scl_fall := false; b_scl_ena := false; b_bitct_clr := true; b_bitct_inc := false; b_read_sdi := false; b_i2c_req := false; sda_cmux := '1'; sda_amux := '1'; sda_dmux := '1'; scl_timer := (others => '0'); bit_count := (others => '0'); scl_present := SCL_HIGH; scl_next := SCL_HIGH; i2c_present := I2C_IDLE; i2c_next := I2C_IDLE; elsif clock'event and clock = '1' then -- rising clock edge i2c_error <= '0'; i2c_ack <= '0'; if b_read_sdi then case bit_count is when "000" => i2c_rddata(0) <= s_sda_in; when "001" => i2c_rddata(1) <= s_sda_in; when "010" => i2c_rddata(2) <= s_sda_in; when "011" => i2c_rddata(3) <= s_sda_in; when "100" => i2c_rddata(4) <= s_sda_in; when "101" => i2c_rddata(5) <= s_sda_in; when "110" => i2c_rddata(6) <= s_sda_in; when "111" => i2c_rddata(7) <= s_sda_in; when others => null; end case; end if; case bit_count is when "000" => sda_cmux := '1'; sda_amux := i2c_address(0); sda_dmux := i2c_wrdata(0); when "001" => sda_cmux := '0'; sda_amux := i2c_address(1); sda_dmux := i2c_wrdata(1); when "010" => sda_cmux := '1'; sda_amux := i2c_address(2); sda_dmux := i2c_wrdata(2); when "011" => sda_cmux := '0'; sda_amux := i2c_address(3); sda_dmux := i2c_wrdata(3); when "100" => sda_cmux := '1'; sda_amux := i2c_address(4); sda_dmux := i2c_wrdata(4); when "101" => sda_cmux := '1'; sda_amux := i2c_address(5); sda_dmux := i2c_wrdata(5); when "110" => sda_cmux := '1'; sda_amux := i2c_address(6); sda_dmux := i2c_wrdata(6); when "111" => sda_cmux := bool2sl(i2c_present = I2C_CTRLRD); sda_amux := i2c_address(7); sda_dmux := i2c_wrdata(7); when others => null; end case; if b_bitct_clr then bit_count := (others => '0'); elsif b_bitct_inc then bit_count := inc(bit_count); end if; b_bitct_clr := false; b_bitct_inc := false; b_scl_tick := scl_timer(8) = '1'; if b_scl_tick then scl_timer := (others => '0'); else scl_timer := inc(scl_timer); end if; b_scl_low := scl_present = SCL_LOW; b_scl_high := scl_present = SCL_HIGH; b_scl_rise := scl_present = SCL_GOHIGH and b_scl_tick; -- b_scl_fall := scl_present = SCL_GOLOW and b_scl_tick; case scl_present is when SCL_HIGH => i2c_scl <= '1'; if b_scl_tick and b_scl_ena then scl_next := SCL_GOLOW; else scl_next := SCL_HIGH; end if; when SCL_GOLOW => if b_scl_tick then i2c_scl <= '0'; scl_next := SCL_LOW; else scl_next := SCL_GOLOW; end if; when SCL_LOW => i2c_scl <= '0'; if b_scl_tick then scl_next := SCL_GOHIGH; else scl_next := SCL_LOW; end if; when SCL_GOHIGH => if b_scl_tick then i2c_scl <= '1'; scl_next := SCL_HIGH; else scl_next := SCL_GOHIGH; end if; end case; scl_present := scl_next; b_read_sdi := i2c_present = I2C_RXDATA and b_scl_high and b_scl_tick; case i2c_present is when I2C_IDLE => b_scl_ena := false; s_sda_out <= '1'; s_sda_ena <= '1'; if b_i2c_req then i2c_next := I2C_TXSTART; else i2c_next := I2C_IDLE; end if; when I2C_TXSTART => b_scl_ena := true; s_sda_out <= '0'; b_bitct_clr := true; if b_scl_low and b_scl_tick then i2c_next := I2C_CTRLWR; else i2c_next := I2C_TXSTART; end if; when I2C_CTRLWR => b_scl_ena := true; s_sda_out <= sda_cmux; s_sda_ena <= '1'; if b_scl_low and b_scl_tick then b_bitct_inc := true; if bit_count = "111" then i2c_next := I2C_CTRLWRACK; else i2c_next := I2C_CTRLWR; end if; else i2c_next := I2C_CTRLWR; end if; when I2C_CTRLWRACK => b_scl_ena := true; s_sda_ena <= '0'; b_bitct_clr := true; if b_scl_high and b_scl_tick then if s_sda_in = '1' then i2c_next := I2C_TXSTART; else i2c_next := I2C_CTRLWRACK; end if; elsif b_scl_low and b_scl_tick then i2c_next := I2C_TXADDR; else i2c_next := I2C_CTRLWRACK; end if; when I2C_TXADDR => b_scl_ena := true; s_sda_out <= sda_amux; s_sda_ena <= '1'; if b_scl_low and b_scl_tick then b_bitct_inc := true; if bit_count = "111" then i2c_next := I2C_ADDRACK; else i2c_next := I2C_TXADDR; end if; else i2c_next := I2C_TXADDR; end if; when I2C_ADDRACK => b_scl_ena := true; s_sda_out <= '1'; s_sda_ena <= '0'; b_bitct_clr := true; if b_scl_high and b_scl_tick then if s_sda_in = '1' then i2c_next := I2C_TXSTART; else i2c_next := I2C_ADDRACK; end if; elsif b_scl_low and b_scl_tick then if i2c_rdwrn = '1' then i2c_next := I2C_TXSTART2; else i2c_next := I2C_TXDATA; end if; else i2c_next := I2C_ADDRACK; end if; when I2C_TXDATA => b_scl_ena := true; s_sda_out <= sda_dmux; s_sda_ena <= '1'; if b_scl_low and b_scl_tick then b_bitct_inc := true; if bit_count = "111" then i2c_next := I2C_DATAACK; else i2c_next := I2C_TXDATA; end if; else i2c_next := I2C_TXDATA; end if; when I2C_DATAACK => b_scl_ena := true; s_sda_out <= '0'; s_sda_ena <= '0'; if b_scl_high and b_scl_tick then i2c_next := I2C_DATAACK; -- error could be tested here (if NACK ...) elsif b_scl_low and b_scl_tick then i2c_next := I2C_TXSTOP; else i2c_next := I2C_DATAACK; end if; when I2C_TXSTART2 => b_scl_ena := true; s_sda_ena <= '1'; b_bitct_clr := true; if b_scl_high and b_scl_tick then s_sda_out <= '0'; i2c_next := I2C_TXSTART2; elsif b_scl_low and b_scl_tick then i2c_next := I2C_CTRLRD; else i2c_next := I2C_TXSTART2; end if; when I2C_CTRLRD => b_scl_ena := true; s_sda_out <= sda_cmux; s_sda_ena <= '1'; if b_scl_low and b_scl_tick then b_bitct_inc := true; if bit_count = "111" then i2c_next := I2C_CTRLRDACK; else i2c_next := I2C_CTRLRD; end if; else i2c_next := I2C_CTRLRD; end if; when I2C_CTRLRDACK => b_scl_ena := true; s_sda_ena <= '0'; b_bitct_clr := true; if b_scl_high and b_scl_tick then -- error could be tested here (if NACK ...) i2c_next := I2C_CTRLRDACK; elsif b_scl_low and b_scl_tick then i2c_next := I2C_RXDATA; else i2c_next := I2C_CTRLRDACK; end if; when I2C_RXDATA => b_scl_ena := true; s_sda_out <= '1'; s_sda_ena <= '0'; if b_scl_low and b_scl_tick then b_bitct_inc := true; if bit_count = "111" then i2c_next := I2C_TXNACK; else i2c_next := I2C_RXDATA; end if; else i2c_next := I2C_RXDATA; end if; when I2C_TXNACK => b_scl_ena := true; s_sda_out <= '0'; s_sda_ena <= '0'; if b_scl_low and b_scl_tick then i2c_next := I2C_TXSTOP; else i2c_next := I2C_TXNACK; end if; when I2C_TXSTOP => s_sda_ena <= '1'; if b_scl_rise then b_scl_ena := false; i2c_next := I2C_TXSTOP; elsif b_scl_high and b_scl_tick then s_sda_out <= '1'; i2c_next := I2C_READY; else i2c_next := I2C_TXSTOP; end if; when I2C_READY => i2c_ack <= '1'; if not b_i2c_req then i2c_next := I2C_IDLE; else i2c_next := I2C_READY; end if; end case; i2c_present := i2c_next; b_i2c_req := i2c_req = '1'; end if; end process proc_main; end SYN;