---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 14:25:56 05/29/2008 -- Design Name: -- Module Name: i2c - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; use IEEE.std_logic_arith.all; ---- Uncomment the following library declaration if instantiating ---- any Xilinx primitives in this code. --library UNISIM; --use UNISIM.VComponents.all; entity i2c is port( scl : inout std_logic; sda : inout std_logic; clk : in std_logic; reset : in std_logic; address : out std_logic_vector(6 downto 0); valid_address : in std_logic; data_in : in std_logic_vector(7 downto 0); data_out : out std_logic_vector(7 downto 0); transaction : out std_logic; -- keep '1' in the same transaction dir : out std_logic; -- OUT => '0', IN => '1' request : out std_logic; -- request to client ready : in std_logic); -- client ready end i2c; architecture Behavioral of i2c is type state_type is (POR, IDLE, RX_ADDRESS_RW, SEND_ACK, DATA_RX, SEND_ACK_IN_RX, DATA_TX, WAIT_ACK_IN_TX); signal current_state : state_type := POR; signal scl_buf, scl_buf2 : std_logic; signal sda_buf, sda_buf2 : std_logic; signal scl_fallen, scl_risen : boolean; signal start_cond, stop_cond : boolean; signal sda_sampled : std_logic; signal sda_oe : std_logic; signal scl_oe : std_logic; signal shift_register : std_logic_vector(7 downto 0); signal shift_count : std_logic_vector(3 downto 0); signal dir_buf : std_logic; begin process(clk) begin if (clk'event and clk = '1') then scl_buf <= scl; sda_buf <= sda; scl_buf2 <= scl_buf; sda_buf2 <= sda_buf; if current_state = POR then scl_fallen <= false; scl_risen <= false; elsif ((scl_buf2 /= '0') and (scl_buf = '0')) then scl_fallen <= true; scl_risen <= false; elsif ((scl_buf2 = '0') and (scl_buf /= '0')) then scl_fallen <= false; scl_risen <= true; else scl_fallen <= false; scl_risen <= false; end if; if current_state /= POR and scl_buf2 /= '0' and scl_buf /= '0' and sda_buf2 /= '0' and sda_buf = '0' then start_cond <= true; else start_cond <= false; end if; if current_state /= POR and scl_buf2 /= '0' and scl_buf /= '0' and sda_buf2 = '0' and sda_buf /= '0' then stop_cond <= true; else stop_cond <= false; end if; if (scl_buf2 = '0') and (scl_buf /= '0') then if sda_buf = '0' then sda_sampled <= '0'; else sda_sampled <= '1'; end if; else sda_sampled <= sda_sampled; end if; end if; end process; process(clk, reset) begin if reset = '1' then sda_oe <= '0'; elsif (clk'event and clk = '1') then if start_cond or stop_cond then sda_oe <= '0'; else case current_state is when SEND_ACK => sda_oe <= '1'; when SEND_ACK_IN_RX => sda_oe <= '1'; when DATA_TX => if scl_buf = '0' then if shift_register(7) = '0' then sda_oe <= '1'; else sda_oe <= '0'; end if; else sda_oe <= sda_oe; end if; when others => sda_oe <= '0'; end case; end if; end if; end process; sda <= '0' when sda_oe = '1' else 'Z'; process(clk, reset) begin if reset = '1' then scl_oe <= '0'; elsif (clk'event and clk = '1') then if start_cond or stop_cond then scl_oe <= '0'; else case current_state is when SEND_ACK => if dir_buf = '1' and ready = '0' then scl_oe <= '1'; else scl_oe <= '0'; end if; when SEND_ACK_IN_RX => if ready = '0' then scl_oe <= '1'; else scl_oe <= '0'; end if; when WAIT_ACK_IN_TX => if ready = '0' then scl_oe <= '1'; else scl_oe <= '0'; end if; when others => scl_oe <= '0'; end case; end if; end if; end process; scl <= '0' when scl_oe = '1' else 'Z'; process(clk) begin if clk'event and clk = '1' then if start_cond then -- START bit shift_count <= (others => '0'); elsif (current_state = RX_ADDRESS_RW) or (current_state = DATA_RX) or (current_state = DATA_TX) then if scl_risen then shift_count <= shift_count + 1; else shift_count <= shift_count; end if; else shift_count <= (others => '0'); end if; end if; end process; process(clk) begin if (clk'event and clk = '1') then if scl_risen and ((current_state = RX_ADDRESS_RW) or (current_state = DATA_RX)) then shift_register <= shift_register(6 downto 0) & sda_sampled; elsif ((current_state = SEND_ACK) or (current_state = WAIT_ACK_IN_TX)) and (ready = '1') then shift_register <= data_in; elsif scl_risen and (current_state = DATA_TX) then shift_register <= shift_register(6 downto 0) & shift_register(0); else shift_register <= shift_register; end if; end if; end process; process(clk) begin if (clk'event and clk = '1') then if (current_state = RX_ADDRESS_RW) and (shift_count = conv_std_logic_vector(8, 4)) then dir_buf <= shift_register(0); address <= shift_register(7 downto 1); else null; end if; end if; end process; dir <= dir_buf; process(clk) begin if (clk'event and clk = '1') then if (current_state = DATA_RX) and (shift_count = conv_std_logic_vector(8, 4)) then data_out <= shift_register; else null; end if; end if; end process; process(clk) begin if (clk'event and clk = '1') then if ((current_state = SEND_ACK and dir_buf = '1') or (current_state = SEND_ACK_IN_RX) or (current_state = WAIT_ACK_IN_TX)) then request <= '1'; else request <= '0'; end if; end if; end process; process(clk, reset) begin if (clk'event and clk = '1') then if (current_state = POR) or (current_state = IDLE) or (start_cond or stop_cond) then transaction <= '0'; else transaction <= '1'; end if; end if; end process; process(clk, reset) begin if reset = '1' then current_state <= POR; elsif (clk'event and clk = '1') then if start_cond then -- START bit current_state <= RX_ADDRESS_RW; elsif stop_cond then -- STOP bit current_state <= IDLE; else current_state <= current_state; case current_state is when POR => current_state <= IDLE; when IDLE => null; when RX_ADDRESS_RW => if scl_fallen and shift_count = conv_std_logic_vector(8, 4) and valid_address = '1' then current_state <= SEND_ACK; else null; end if; when SEND_ACK => if scl_fallen then if dir_buf = '1' then current_state <= DATA_TX; else current_state <= DATA_RX; end if; else null; end if; when DATA_RX => if scl_fallen and shift_count = conv_std_logic_vector(8, 4) then current_state <= SEND_ACK_IN_RX; else null; end if; when SEND_ACK_IN_RX => if scl_fallen then current_state <= DATA_RX; else null; end if; when DATA_TX => if scl_fallen and shift_count = conv_std_logic_vector(8, 4) then current_state <= WAIT_ACK_IN_TX; else null; end if; when WAIT_ACK_IN_TX => if scl_fallen then if sda_sampled = '1' then current_state <= IDLE; else current_state <= DATA_TX; end if; else null; end if; end case; end if; end if; end process; end Behavioral;