---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
---- ----
|
---- ----
|
---- WISHBONE revB2 compl. I2C Master Core; byte-controller ----
|
---- WISHBONE revB2 compl. I2C Master Core; byte-controller ----
|
---- ----
|
---- ----
|
---- ----
|
---- ----
|
---- Author: Richard Herveille ----
|
---- Author: Richard Herveille ----
|
---- richard@asics.ws ----
|
---- richard@asics.ws ----
|
---- www.asics.ws ----
|
---- www.asics.ws ----
|
---- ----
|
---- ----
|
---- Downloaded from: http://www.opencores.org/projects/i2c/ ----
|
---- Downloaded from: http://www.opencores.org/projects/i2c/ ----
|
---- ----
|
---- ----
|
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
---- ----
|
---- ----
|
---- Copyright (C) 2000 Richard Herveille ----
|
---- Copyright (C) 2000 Richard Herveille ----
|
---- richard@asics.ws ----
|
---- richard@asics.ws ----
|
---- ----
|
---- ----
|
---- This source file may be used and distributed without ----
|
---- This source file may be used and distributed without ----
|
---- restriction provided that this copyright statement is not ----
|
---- restriction provided that this copyright statement is not ----
|
---- removed from the file and that any derivative work contains ----
|
---- removed from the file and that any derivative work contains ----
|
---- the original copyright notice and the associated disclaimer.----
|
---- the original copyright notice and the associated disclaimer.----
|
---- ----
|
---- ----
|
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ----
|
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ----
|
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ----
|
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ----
|
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ----
|
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ----
|
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ----
|
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ----
|
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ----
|
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ----
|
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ----
|
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ----
|
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ----
|
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ----
|
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ----
|
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ----
|
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ----
|
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ----
|
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ----
|
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ----
|
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ----
|
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ----
|
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ----
|
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ----
|
---- POSSIBILITY OF SUCH DAMAGE. ----
|
---- POSSIBILITY OF SUCH DAMAGE. ----
|
---- ----
|
---- ----
|
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
|
|
-- CVS Log
|
-- CVS Log
|
--
|
--
|
-- $Id: i2c_master_byte_ctrl.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $
|
-- $Id: i2c_master_byte_ctrl.vhd,v 1.2 2002-11-30 22:24:37 rherveille Exp $
|
--
|
--
|
-- $Date: 2001-11-05 12:02:33 $
|
-- $Date: 2002-11-30 22:24:37 $
|
-- $Revision: 1.1 $
|
-- $Revision: 1.2 $
|
-- $Author: rherveille $
|
-- $Author: rherveille $
|
-- $Locker: $
|
-- $Locker: $
|
-- $State: Exp $
|
-- $State: Exp $
|
--
|
--
|
-- Change History:
|
-- Change History:
|
-- $Log: not supported by cvs2svn $
|
-- $Log: not supported by cvs2svn $
|
|
-- Revision 1.1 2001/11/05 12:02:33 rherveille
|
|
-- Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version.
|
|
-- Code updated, is now up-to-date to doc. rev.0.4.
|
|
-- Added headers.
|
|
--
|
|
|
|
|
|
|
|
|
--
|
--
|
------------------------------------------
|
------------------------------------------
|
-- Byte controller section
|
-- Byte controller section
|
------------------------------------------
|
------------------------------------------
|
--
|
--
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
|
|
entity i2c_master_byte_ctrl is
|
entity i2c_master_byte_ctrl is
|
generic(
|
|
Tcq : time := 1 ns
|
|
);
|
|
port (
|
port (
|
clk : in std_logic;
|
clk : in std_logic;
|
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible)
|
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible)
|
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible)
|
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible)
|
ena : in std_logic; -- core enable signal
|
ena : in std_logic; -- core enable signal
|
|
|
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
|
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
|
|
|
-- input signals
|
-- input signals
|
start,
|
start,
|
stop,
|
stop,
|
read,
|
read,
|
write,
|
write,
|
ack_in : std_logic;
|
ack_in : std_logic;
|
din : in std_logic_vector(7 downto 0);
|
din : in std_logic_vector(7 downto 0);
|
|
|
-- output signals
|
-- output signals
|
cmd_ack : out std_logic;
|
cmd_ack : out std_logic;
|
ack_out : out std_logic;
|
ack_out : out std_logic;
|
i2c_busy : out std_logic;
|
i2c_busy : out std_logic;
|
dout : out std_logic_vector(7 downto 0);
|
dout : out std_logic_vector(7 downto 0);
|
|
|
-- i2c lines
|
-- i2c lines
|
scl_i : in std_logic; -- i2c clock line input
|
scl_i : in std_logic; -- i2c clock line input
|
scl_o : out std_logic; -- i2c clock line output
|
scl_o : out std_logic; -- i2c clock line output
|
scl_oen : out std_logic; -- i2c clock line output enable, active low
|
scl_oen : out std_logic; -- i2c clock line output enable, active low
|
sda_i : in std_logic; -- i2c data line input
|
sda_i : in std_logic; -- i2c data line input
|
sda_o : out std_logic; -- i2c data line output
|
sda_o : out std_logic; -- i2c data line output
|
sda_oen : out std_logic -- i2c data line output enable, active low
|
sda_oen : out std_logic -- i2c data line output enable, active low
|
);
|
);
|
end entity i2c_master_byte_ctrl;
|
end entity i2c_master_byte_ctrl;
|
|
|
architecture structural of i2c_master_byte_ctrl is
|
architecture structural of i2c_master_byte_ctrl is
|
component i2c_master_bit_ctrl is
|
component i2c_master_bit_ctrl is
|
generic(
|
|
Tcq : time := Tcq
|
|
);
|
|
port (
|
port (
|
clk : in std_logic;
|
clk : in std_logic;
|
rst : in std_logic;
|
rst : in std_logic;
|
nReset : in std_logic;
|
nReset : in std_logic;
|
ena : in std_logic; -- core enable signal
|
ena : in std_logic; -- core enable signal
|
|
|
clk_cnt : in unsigned(15 downto 0); -- clock prescale value
|
clk_cnt : in unsigned(15 downto 0); -- clock prescale value
|
|
|
cmd : in std_logic_vector(3 downto 0);
|
cmd : in std_logic_vector(3 downto 0);
|
cmd_ack : out std_logic;
|
cmd_ack : out std_logic;
|
busy : out std_logic;
|
busy : out std_logic;
|
|
|
din : in std_logic;
|
din : in std_logic;
|
dout : out std_logic;
|
dout : out std_logic;
|
|
|
-- i2c lines
|
-- i2c lines
|
scl_i : in std_logic; -- i2c clock line input
|
scl_i : in std_logic; -- i2c clock line input
|
scl_o : out std_logic; -- i2c clock line output
|
scl_o : out std_logic; -- i2c clock line output
|
scl_oen : out std_logic; -- i2c clock line output enable, active low
|
scl_oen : out std_logic; -- i2c clock line output enable, active low
|
sda_i : in std_logic; -- i2c data line input
|
sda_i : in std_logic; -- i2c data line input
|
sda_o : out std_logic; -- i2c data line output
|
sda_o : out std_logic; -- i2c data line output
|
sda_oen : out std_logic -- i2c data line output enable, active low
|
sda_oen : out std_logic -- i2c data line output enable, active low
|
);
|
);
|
end component i2c_master_bit_ctrl;
|
end component i2c_master_bit_ctrl;
|
|
|
-- commands for bit_controller block
|
-- commands for bit_controller block
|
constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000";
|
constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000";
|
constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001";
|
constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001";
|
constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010";
|
constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010";
|
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100";
|
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100";
|
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000";
|
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000";
|
|
|
-- signals for bit_controller
|
-- signals for bit_controller
|
signal core_cmd : std_logic_vector(3 downto 0);
|
signal core_cmd : std_logic_vector(3 downto 0);
|
signal core_ack, core_txd, core_rxd : std_logic;
|
signal core_ack, core_txd, core_rxd : std_logic;
|
|
|
-- signals for shift register
|
-- signals for shift register
|
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
|
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
|
signal shift, ld : std_logic;
|
signal shift, ld : std_logic;
|
|
|
-- signals for state machine
|
-- signals for state machine
|
signal go, host_ack : std_logic;
|
signal go, host_ack : std_logic;
|
signal dcnt : unsigned(2 downto 0); -- data counter
|
signal dcnt : unsigned(2 downto 0); -- data counter
|
signal cnt_done : std_logic;
|
signal cnt_done : std_logic;
|
|
|
begin
|
begin
|
-- hookup bit_controller
|
-- hookup bit_controller
|
u1: i2c_master_bit_ctrl port map(
|
u1: i2c_master_bit_ctrl port map(
|
clk => clk,
|
clk => clk,
|
rst => rst,
|
rst => rst,
|
nReset => nReset,
|
nReset => nReset,
|
ena => ena,
|
ena => ena,
|
clk_cnt => clk_cnt,
|
clk_cnt => clk_cnt,
|
cmd => core_cmd,
|
cmd => core_cmd,
|
cmd_ack => core_ack,
|
cmd_ack => core_ack,
|
busy => i2c_busy,
|
busy => i2c_busy,
|
din => core_txd,
|
din => core_txd,
|
dout => core_rxd,
|
dout => core_rxd,
|
scl_i => scl_i,
|
scl_i => scl_i,
|
scl_o => scl_o,
|
scl_o => scl_o,
|
scl_oen => scl_oen,
|
scl_oen => scl_oen,
|
sda_i => sda_i,
|
sda_i => sda_i,
|
sda_o => sda_o,
|
sda_o => sda_o,
|
sda_oen => sda_oen
|
sda_oen => sda_oen
|
);
|
);
|
|
|
-- generate host-command-acknowledge
|
-- generate host-command-acknowledge
|
cmd_ack <= host_ack;
|
cmd_ack <= host_ack;
|
|
|
-- generate go-signal
|
-- generate go-signal
|
go <= (read or write or stop) and not host_ack;
|
go <= (read or write or stop) and not host_ack;
|
|
|
-- assign Dout output to shift-register
|
-- assign Dout output to shift-register
|
dout <= sr;
|
dout <= sr;
|
|
|
-- generate shift register
|
-- generate shift register
|
shift_register: process(clk, nReset)
|
shift_register: process(clk, nReset)
|
begin
|
begin
|
if (nReset = '0') then
|
if (nReset = '0') then
|
sr <= (others => '0') after Tcq;
|
sr <= (others => '0');
|
elsif (clk'event and clk = '1') then
|
elsif (clk'event and clk = '1') then
|
if (rst = '1') then
|
if (rst = '1') then
|
sr <= (others => '0') after Tcq;
|
sr <= (others => '0');
|
elsif (ld = '1') then
|
elsif (ld = '1') then
|
sr <= din after Tcq;
|
sr <= din;
|
elsif (shift = '1') then
|
elsif (shift = '1') then
|
sr <= (sr(6 downto 0) & core_rxd) after Tcq;
|
sr <= (sr(6 downto 0) & core_rxd);
|
end if;
|
end if;
|
end if;
|
end if;
|
end process shift_register;
|
end process shift_register;
|
|
|
-- generate data-counter
|
-- generate data-counter
|
data_cnt: process(clk, nReset)
|
data_cnt: process(clk, nReset)
|
begin
|
begin
|
if (nReset = '0') then
|
if (nReset = '0') then
|
dcnt <= (others => '0') after Tcq;
|
dcnt <= (others => '0');
|
elsif (clk'event and clk = '1') then
|
elsif (clk'event and clk = '1') then
|
if (rst = '1') then
|
if (rst = '1') then
|
dcnt <= (others => '0') after Tcq;
|
dcnt <= (others => '0');
|
elsif (ld = '1') then
|
elsif (ld = '1') then
|
dcnt <= (others => '1') after Tcq; -- load counter with 7
|
dcnt <= (others => '1'); -- load counter with 7
|
elsif (shift = '1') then
|
elsif (shift = '1') then
|
dcnt <= dcnt -1 after Tcq;
|
dcnt <= dcnt -1;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process data_cnt;
|
end process data_cnt;
|
|
|
cnt_done <= '1' when (dcnt = 0) else '0';
|
cnt_done <= '1' when (dcnt = 0) else '0';
|
|
|
--
|
--
|
-- state machine
|
-- state machine
|
--
|
--
|
statemachine : block
|
statemachine : block
|
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
|
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
|
signal c_state : states;
|
signal c_state : states;
|
begin
|
begin
|
--
|
--
|
-- command interpreter, translate complex commands into simpler I2C commands
|
-- command interpreter, translate complex commands into simpler I2C commands
|
--
|
--
|
nxt_state_decoder: process(clk, nReset)
|
nxt_state_decoder: process(clk, nReset)
|
begin
|
begin
|
if (nReset = '0') then
|
if (nReset = '0') then
|
core_cmd <= I2C_CMD_NOP after Tcq;
|
core_cmd <= I2C_CMD_NOP;
|
core_txd <= '0' after Tcq;
|
core_txd <= '0';
|
|
shift <= '0';
|
shift <= '0' after Tcq;
|
ld <= '0';
|
ld <= '0' after Tcq;
|
host_ack <= '0';
|
|
c_state <= st_idle;
|
host_ack <= '0' after Tcq;
|
ack_out <= '0';
|
c_state <= st_idle after Tcq;
|
|
|
|
ack_out <= '0' after Tcq;
|
|
elsif (clk'event and clk = '1') then
|
elsif (clk'event and clk = '1') then
|
if (rst = '1') then
|
if (rst = '1') then
|
core_cmd <= I2C_CMD_NOP after Tcq;
|
core_cmd <= I2C_CMD_NOP;
|
core_txd <= '0' after Tcq;
|
core_txd <= '0';
|
|
shift <= '0';
|
shift <= '0' after Tcq;
|
ld <= '0';
|
ld <= '0' after Tcq;
|
host_ack <= '0';
|
|
c_state <= st_idle;
|
host_ack <= '0' after Tcq;
|
ack_out <= '0';
|
c_state <= st_idle after Tcq;
|
|
|
|
ack_out <= '0' after Tcq;
|
|
else
|
else
|
-- initialy reset all signal
|
-- initialy reset all signal
|
core_txd <= sr(7) after Tcq;
|
core_txd <= sr(7);
|
|
shift <= '0';
|
shift <= '0' after Tcq;
|
ld <= '0';
|
ld <= '0' after Tcq;
|
host_ack <= '0';
|
|
|
host_ack <= '0' after Tcq;
|
|
|
|
case c_state is
|
case c_state is
|
when st_idle =>
|
when st_idle =>
|
if (go = '1') then
|
if (go = '1') then
|
if (start = '1') then
|
if (start = '1') then
|
c_state <= st_start after Tcq;
|
c_state <= st_start;
|
core_cmd <= I2C_CMD_START after Tcq;
|
core_cmd <= I2C_CMD_START;
|
elsif (read = '1') then
|
elsif (read = '1') then
|
c_state <= st_read after Tcq;
|
c_state <= st_read;
|
core_cmd <= I2C_CMD_READ after Tcq;
|
core_cmd <= I2C_CMD_READ;
|
elsif (write = '1') then
|
elsif (write = '1') then
|
c_state <= st_write after Tcq;
|
c_state <= st_write;
|
core_cmd <= I2C_CMD_WRITE after Tcq;
|
core_cmd <= I2C_CMD_WRITE;
|
else -- stop
|
else -- stop
|
c_state <= st_stop after Tcq;
|
c_state <= st_stop;
|
core_cmd <= I2C_CMD_STOP after Tcq;
|
core_cmd <= I2C_CMD_STOP;
|
|
host_ack <= '1'; -- generate acknowledge signal
|
host_ack <= '1' after Tcq; -- generate acknowledge signal
|
|
end if;
|
end if;
|
|
|
ld <= '1' after Tcq;
|
ld <= '1';
|
end if;
|
end if;
|
|
|
when st_start =>
|
when st_start =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
if (read = '1') then
|
if (read = '1') then
|
c_state <= st_read after Tcq;
|
c_state <= st_read;
|
core_cmd <= I2C_CMD_READ after Tcq;
|
core_cmd <= I2C_CMD_READ;
|
else
|
else
|
c_state <= st_write after Tcq;
|
c_state <= st_write;
|
core_cmd <= I2C_CMD_WRITE after Tcq;
|
core_cmd <= I2C_CMD_WRITE;
|
end if;
|
end if;
|
|
|
ld <= '1' after Tcq;
|
ld <= '1';
|
end if;
|
end if;
|
|
|
when st_write =>
|
when st_write =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
if (cnt_done = '1') then
|
if (cnt_done = '1') then
|
c_state <= st_ack after Tcq;
|
c_state <= st_ack;
|
core_cmd <= I2C_CMD_READ after Tcq;
|
core_cmd <= I2C_CMD_READ;
|
else
|
else
|
c_state <= st_write after Tcq; -- stay in same state
|
c_state <= st_write; -- stay in same state
|
core_cmd <= I2C_CMD_WRITE after Tcq; -- write next bit
|
core_cmd <= I2C_CMD_WRITE; -- write next bit
|
|
shift <= '1';
|
shift <= '1' after Tcq;
|
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when st_read =>
|
when st_read =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
if (cnt_done = '1') then
|
if (cnt_done = '1') then
|
c_state <= st_ack after Tcq;
|
c_state <= st_ack;
|
core_cmd <= I2C_CMD_WRITE after Tcq;
|
core_cmd <= I2C_CMD_WRITE;
|
else
|
else
|
c_state <= st_read after Tcq; -- stay in same state
|
c_state <= st_read; -- stay in same state
|
core_cmd <= I2C_CMD_READ after Tcq; -- read next bit
|
core_cmd <= I2C_CMD_READ; -- read next bit
|
end if;
|
end if;
|
|
|
shift <= '1' after Tcq;
|
shift <= '1';
|
core_txd <= ack_in after Tcq;
|
core_txd <= ack_in;
|
end if;
|
end if;
|
|
|
when st_ack =>
|
when st_ack =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
-- check for stop; Should a STOP command be generated ?
|
-- check for stop; Should a STOP command be generated ?
|
if (stop = '1') then
|
if (stop = '1') then
|
c_state <= st_stop after Tcq;
|
c_state <= st_stop;
|
core_cmd <= I2C_CMD_STOP after Tcq;
|
core_cmd <= I2C_CMD_STOP;
|
else
|
else
|
c_state <= st_idle after Tcq;
|
c_state <= st_idle;
|
core_cmd <= I2C_CMD_NOP after Tcq;
|
core_cmd <= I2C_CMD_NOP;
|
end if;
|
end if;
|
|
|
-- assign ack_out output to core_rxd (contains last received bit)
|
-- assign ack_out output to core_rxd (contains last received bit)
|
ack_out <= core_rxd after Tcq;
|
ack_out <= core_rxd;
|
|
|
-- generate command acknowledge signal
|
-- generate command acknowledge signal
|
host_ack <= '1' after Tcq;
|
host_ack <= '1';
|
|
|
core_txd <= '1' after Tcq;
|
core_txd <= '1';
|
else
|
else
|
core_txd <= ack_in after Tcq;
|
core_txd <= ack_in;
|
end if;
|
end if;
|
|
|
when st_stop =>
|
when st_stop =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
c_state <= st_idle after Tcq;
|
c_state <= st_idle;
|
core_cmd <= I2C_CMD_NOP after Tcq;
|
core_cmd <= I2C_CMD_NOP;
|
end if;
|
end if;
|
|
|
when others => -- illegal states
|
when others => -- illegal states
|
c_state <= st_idle after Tcq;
|
c_state <= st_idle;
|
core_cmd <= I2C_CMD_NOP after Tcq;
|
core_cmd <= I2C_CMD_NOP;
|
report ("Byte controller entered illegal state.");
|
report ("Byte controller entered illegal state.");
|
|
|
end case;
|
end case;
|
|
|
end if;
|
end if;
|
end if;
|
end if;
|
end process nxt_state_decoder;
|
end process nxt_state_decoder;
|
|
|
end block statemachine;
|
end block statemachine;
|
|
|
end architecture structural;
|
end architecture structural;
|
|
|
|
|