--345678901234567890123456789012345678901234567890123456789012345678901234567890 -- 1 2 3 4 5 6 7 -- Title: I2C Master Controller -- Engineer: Evgeny Shumilov -- Company: For HiTechGlobal -- Project: -- File name: i2c.vhd -------------------------------------------------------------------------------- -- Purpose: -------------------------------------------------------------------------------- -- Simulator: Modelsim -- Synthesis: Xilinx ISE -------------------------------------------------------------------------------- -- Revision: 0.65 -- Modification date: 03/05/2003 -- Limitation: -- Notes: -------------------------------------------------------------------------------- -- Modifications List: -- -- -------------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; use IEEE.std_logic_unsigned.all; --use IEEE.std_logic_signed.all; USE ieee.numeric_std.all; use IEEE.std_logic_misc.all; library unisim; use unisim.vcomponents.all; entity i2c is generic ( count_div : integer range 0 to 1023:= 512 -- sysclk divide coafficien (2 to 1023 max) ); port ( ADDR_IN : in std_logic_vector (7 downto 0); -- word address DAT_IN : in std_logic_vector(7 downto 0); -- write data DEV_ADDR : in std_logic_vector (6 downto 0); -- device address CONTINUE : in std_logic; -- continue read operation from ADDR_IN AP_EN : in std_logic; -- Enable Address Phase During Write WR_OP : in std_logic; -- write operation WRITE ONE WORD <= '0', RD <= '1' WR_EN : in std_logic; -- enable write ADDR_IN, DAT_IN, ID_ADDR, WR_OP CLK : in std_logic; -- main clock RST : in std_logic; -- system reset I2C_RDATA : out std_logic_vector(7 downto 0); -- i2c read data ACK_L : out std_logic; -- acknowledge WR_EN (active '0') -- SDA : inout std_logic; -- i2c data -- SCL : out std_logic; -- i2c CLK I_SDA_I : in std_logic; O_SDA_O : out std_logic; O_SDA_T : out std_logic; I_SCL_I : in std_logic; O_SCL_O : out std_logic; O_SCL_T : out std_logic; I2C_RDY : out std_logic; -- i2c ready I2C_ACT : out std_logic; -- i2c cycle active ACK_ERR : out std_logic -- i2c(ack) error ); end entity i2c; architecture translated of i2c is component IOBUF port ( O : out std_ulogic; IO : inout std_ulogic; I : in std_ulogic; T : in std_ulogic ); end component; component OBUFT port ( O : out std_ulogic; I : in std_ulogic; T : in std_ulogic ); end component; component i2c_st port ( WRD_ADD : in std_logic_vector(7 downto 0); -- i2c address WRD_DAT : in std_logic_vector(7 downto 0); DEV_ADDR : in std_logic_vector (6 downto 0); CONTINUE : in std_logic; ENAPH : in std_logic; -- Enable Address Phase During Write WR_L : in std_logic; RST : in std_logic; -- reset CLK : in std_logic; -- mpu CLK SCL_TICK : in std_logic; -- 5 usec CLK tick I2C_GO : in std_logic; -- start i2c cycle SDA_PIN : in std_logic; -- i2c data muxed input I2C_RDATA : out std_logic_vector(7 downto 0); -- i2c read data SDA : out std_logic; -- i2c data SCL : out std_logic; -- i2c CLK SCL_CNT_EN : out std_logic; -- SCL cntr enable I2C_RDY : out std_logic; -- i2c ready I2C_ACT : out std_logic; -- i2c cycle active ACK_ERR : out std_logic -- ack error ); end component; --------------------------------------------------------------------------------------------------- constant sim_timescale : time := 1 ns; function length_ct (int_length : integer) return positive is variable conv_length : std_logic_vector(9 downto 0); variable index : positive:= 1; begin conv_length := CONV_STD_LOGIC_VECTOR(int_length, 10); for i in 9 downto 1 loop index:= i; exit when conv_length(i) = '1'; end loop; return index; end length_ct; signal cntr : std_logic_vector(length_ct(count_div) downto 0); signal cntr_length : std_logic_vector(length_ct(count_div) downto 0); signal scl_tick : std_logic; signal wrd_addr : std_logic_vector(7 downto 0); signal wrd_dat : std_logic_vector(7 downto 0); signal dev_addr_int : std_logic_vector(6 downto 0); signal ENAPH : std_logic; signal scl_cnt_en : std_logic; signal i2c_go : std_logic; signal sda_in : std_logic; signal sda_o : std_logic; signal scl_o : std_logic; signal wr_l_int : std_logic; signal port_switch : std_logic:= '0'; signal sda_o_spd : std_logic; signal scl_o_spd : std_logic; signal GND : std_logic; begin GND <= '0'; --------------------------------------------------------------------------------------------------- -- CLOCK DIVIDER SECTION: --------------------------------------------------------------------------------------------------- cntr_length <= CONV_STD_LOGIC_VECTOR(count_div, (length_ct(count_div)+1)); process (CLK,RST) begin if (RST = '1') then cntr <= (others => '0') after 1 * sim_timescale; elsif (CLK'event and CLK = '1') then if (scl_cnt_en = '1') then cntr <= cntr + 1 after 1 * sim_timescale; else cntr <= (others => '0'); end if; end if; end process; process (CLK,RST) begin if (RST = '1') then scl_tick <= '0' after 1 * sim_timescale; elsif (CLK'event and CLK = '1') then if (cntr = cntr_length) then scl_tick <= '1' after 1 * sim_timescale; else scl_tick <= '0' after 1 * sim_timescale; end if; end if; end process; --------------------------------------------------------------------------------------------------- -- ADDRESS REGISTERS SECTION: --------------------------------------------------------------------------------------------------- process (CLK) begin if (CLK'event and CLK = '1') then if WR_EN = '1' then wrd_addr <= ADDR_IN after 1 * sim_timescale; dev_addr_int <= DEV_ADDR after 1 * sim_timescale; wr_l_int <= WR_OP after 1 * sim_timescale; wrd_dat <= DAT_IN after 1 * sim_timescale; ENAPH <= AP_EN after 1 * sim_timescale; end if; end if; end process; process (CLK) begin if (CLK'event and CLK = '1') then if WR_EN = '1' then port_switch <= (DEV_ADDR(3) and not DEV_ADDR(2) and DEV_ADDR(1) and not DEV_ADDR(0)) after 1 * sim_timescale; -- "1010" (SPD) else null; end if; end if; end process; process (CLK, RST) begin -- send ack right back if (RST = '1') then i2c_go <= '0' after 1 * sim_timescale; elsif (CLK'event and CLK = '1') then if WR_EN = '1' then i2c_go <= '1' after 1 * sim_timescale; else if (scl_cnt_en = '1') then i2c_go <= '0' after 1 * sim_timescale; end if; end if; end if; end process; process (CLK, RST) begin if (RST = '1') then ACK_L <= '1' after 1 * sim_timescale; elsif (CLK'event and CLK = '1') then if WR_EN = '1' then ACK_L <= '0' after 1 * sim_timescale; else ACK_L <= '1' after 1 * sim_timescale; end if; end if; end process; --------------------------------------------------------------------------------------------------- -- I2C STATE MACHINE SECTION: --------------------------------------------------------------------------------------------------- MAIN_FSM : i2c_st port map( WRD_ADD => wrd_addr, WRD_DAT => wrd_dat, DEV_ADDR => dev_addr_int, CONTINUE => CONTINUE, ENAPH => ENAPH, WR_L => wr_l_int, RST => RST, CLK => CLK, SCL_TICK => scl_tick, I2C_GO => i2c_go, SDA_PIN => sda_in, I2C_RDATA => I2C_RDATA, SDA => sda_o, SCL => scl_o, SCL_CNT_EN => scl_cnt_en, I2C_RDY => I2C_RDY, I2C_ACT => I2C_ACT, ACK_ERR => ACK_ERR ); sda_o_spd <= sda_o; scl_o_spd <= scl_o; --SDA_BUF: IOBUF -- port map -- ( -- O => sda_in, -- IO => SDA, -- I => GND, -- T => sda_o_spd -- ); sda_in <= I_SDA_I; O_SDA_O <= GND; O_SDA_T <= sda_o_spd; --SCL_BUF: OBUFT -- port map -- ( -- O => SCL, -- I => GND, -- T => scl_o_spd -- ); -- scl_in <= I_SCL_I O_SCL_O <= GND; O_SCL_T <= scl_o_spd; end architecture translated;