Files
alinx_z19_ad9082/ip_repo/Si5332/src/i2c.vhd
T

306 lines
8.2 KiB
VHDL

--345678901234567890123456789012345678901234567890123456789012345678901234567890
-- 1 2 3 4 5 6 7
-- Title: I2C Master Controller
-- Engineer: Evgeny Shumilov <eugene.shumilov@gmail.com>
-- 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;