306 lines
8.2 KiB
VHDL
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;
|