Library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
--use ieee.numeric_std.all;

entity i2c_read_write is
    
    generic ( 
            address : std_logic_vector(0 to 7):="10100110";
            data    : std_logic_vector(0 to 7):="10101010"
           
          );  
  
  port(
      i_inclk    : in std_logic; --Input clock 50mhz
      i_reset    : in std_logic; --Reset 
      
      start_bit   : out std_logic;
      ledred    : out std_logic_vector(7 downto 0):=(others =>'0');
      
      o_scl      : out std_logic; --I2C SCL line
      io_sda    : inout std_logic:='Z' --I2C SDA line
        
    );
end i2c_read_write;

architecture model of i2c_read_write is

  type states is(i2c_idle,i2c_start,i2c_sendaddress,i2c_sendaddress_0,i2c_sendaddress_1,i2c_addressack,i2c_addressack_0,i2c_addressack_1,i2c_data,i2c_senddata,i2c_senddata_0,i2c_dataack,i2c_dataack_0,i2c_dataack_1,i2c_dataack_2,i2c_stop,i2c_stop_0,i2c_stop_1,i2c_stop_2,i2c_stop_3);
  signal i2c_state : states:=i2c_idle;
  
  signal scl_line  : std_logic;
  signal sda_line  : std_logic;
  
  signal slave_address : std_logic_vector(0 to 7):=(others =>'0');
  
  signal data_bytes  : std_logic_vector(0 to 7):=(others =>'0');
  
  signal index_address  : integer range 0 to 7:=0;
  signal index_data  : integer range 0 to 7:=0;
  
  signal speed_counter : integer:=0;
  
  signal i2c_tic  : std_logic:='1';
  
  signal stop_bit : std_logic:='0';
  
  signal slaveack : std_logic:='1';
  signal dataack  : std_logic:='1';
  

  
begin



  slave_address <= address;
  data_bytes <= data;
  
  process(i_inclk)
  begin
    if(rising_edge(i_inclk))then  
      if(speed_counter=125)then  
        speed_counter <= 0;
        i2c_tic <= not(i2c_tic);
      else
        speed_counter <= speed_counter+1;
      end if;
    end if;
  end process;
  
  
  start_bit <= i2c_tic;
  
  process(i2c_tic,i_reset)
  begin
    if(rising_edge(i2c_tic))then
    
      case i2c_state is
      
        when i2c_idle => --Idle           
          scl_line <= '1';
          
          sda_line <= '1';
          i2c_state <= i2c_start;
        
        when i2c_start => --Start
          if(stop_bit='0')then
            scl_line <= '1';
            sda_line <= '0';  
            i2c_state <= i2c_sendaddress;
          else
            i2c_state <= i2c_idle;
          end if;
          
        when i2c_sendaddress => --Slave address
          scl_line  <= '0';
          i2c_state <= i2c_sendaddress_0;

        when i2c_sendaddress_0 => --8 bit address transmission
          scl_line <= '0';
          sda_line  <= slave_address(index_address);
          i2c_state <= i2c_sendaddress_1;
          
        when i2c_sendaddress_1 =>
          scl_line  <= '1';
          
          sda_line  <= slave_address(index_address);
          if(index_address<7)then
            index_address <= index_address+1;
            i2c_state <= i2c_sendaddress;                                                      
          else
            index_address <= 0;
            i2c_state <= i2c_addressack;
          end if;
          
        when i2c_addressack => --Slave address acknoweldgement 
          scl_line <= '0';
          i2c_state <= i2c_addressack_0;
        
        when i2c_addressack_0 =>  
          scl_line <= '0';
          
          slaveack <= sda_line;
          i2c_state <= i2c_addressack_1;
          
        when i2c_addressack_1 =>
          scl_line <= '1';
          if(slaveack = '0')then
            i2c_state <= i2c_data;
          else
            i2c_state <= i2c_stop;
          end if;
            
        when i2c_data => --Data transmission starts 
          scl_line <= '0';
          i2c_state <= i2c_senddata_0;
        
          when i2c_senddata_0 =>
          scl_line <= '0';
          sda_line  <= data_bytes(index_data);
          i2c_state <= i2c_senddata;
          
        when i2c_senddata => --Transmitting 8 bit data
          scl_line <= '1';
          
          if(index_data<7)then
            index_data <= index_data+1;
            i2c_state <= i2c_data;
          else
            index_data <= 0;
            i2c_state <= i2c_dataack_0;
          end if;
          
        when i2c_dataack_0 => --Data acknoweldgement
          scl_line <= '0';
          i2c_state <= i2c_dataack_1;
          
        when i2c_dataack_1 =>
          scl_line <= '0';

          dataack  <= sda_line;
          i2c_state <= i2c_dataack_2;
          
        when i2c_dataack_2 =>
          scl_line <= '1';
          
          if(dataack = '0')then
            i2c_state <= i2c_stop;
          else
            i2c_state <= i2c_stop;
          end if;        
                    
        when i2c_stop => --Stop bit      
          scl_line <= '0';
          i2c_state <= i2c_stop_0;
        
        when i2c_stop_0 =>
          scl_line <= '0';
          sda_line <= '0';
          i2c_state <= i2c_stop_1;
          
        when i2c_stop_1 =>
          scl_line <= '0';
          i2c_state <= i2c_stop_2;
          
        when i2c_stop_2 =>
          scl_line <= '1';
          i2c_state <= i2c_stop_3;
        
        when i2c_stop_3 =>
          sda_line <= '1';
          stop_bit <= '1';
          stop_bit <= '1';
          i2c_state <= i2c_idle;
          
        when others =>
          i2c_state <= i2c_idle;
        
      end case;
      
    end if;
  end process;
  
 o_scl  <= scl_line;
 io_sda <= 'Z' when sda_line='1' else '0';
 
  ledred <= data_bytes;
 
end model;