OpenCores
URL https://opencores.org/ocsvn/i2c/i2c/trunk

Subversion Repositories i2c

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 14 to Rev 15
    Reverse comparison

Rev 14 → Rev 15

/trunk/rtl/vhdl/i2c_master_byte_ctrl.vhd
0,0 → 1,361
---------------------------------------------------------------------
---- ----
---- WISHBONE revB2 compl. I2C Master Core; byte-controller ----
---- ----
---- ----
---- Author: Richard Herveille ----
---- richard@asics.ws ----
---- www.asics.ws ----
---- ----
---- Downloaded from: http://www.opencores.org/projects/i2c/ ----
---- ----
---------------------------------------------------------------------
---- ----
---- Copyright (C) 2000 Richard Herveille ----
---- richard@asics.ws ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer.----
---- ----
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ----
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ----
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ----
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ----
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ----
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ----
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ----
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ----
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ----
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ----
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ----
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ----
---- POSSIBILITY OF SUCH DAMAGE. ----
---- ----
---------------------------------------------------------------------
 
-- CVS Log
--
-- $Id: i2c_master_byte_ctrl.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $
--
-- $Date: 2001-11-05 12:02:33 $
-- $Revision: 1.1 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
--
-- Change History:
-- $Log: not supported by cvs2svn $
 
 
 
 
--
------------------------------------------
-- Byte controller section
------------------------------------------
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity i2c_master_byte_ctrl is
generic(
Tcq : time := 1 ns
);
port (
clk : in std_logic;
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible)
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible)
ena : in std_logic; -- core enable signal
 
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
 
-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
din : in std_logic_vector(7 downto 0);
 
-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
i2c_busy : out std_logic;
dout : out std_logic_vector(7 downto 0);
 
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
end entity i2c_master_byte_ctrl;
 
architecture structural of i2c_master_byte_ctrl is
component i2c_master_bit_ctrl is
generic(
Tcq : time := Tcq
);
port (
clk : in std_logic;
rst : in std_logic;
nReset : in std_logic;
ena : in std_logic; -- core enable signal
 
clk_cnt : in unsigned(15 downto 0); -- clock prescale value
 
cmd : in std_logic_vector(3 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;
 
din : in std_logic;
dout : out std_logic;
 
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
end component i2c_master_bit_ctrl;
 
-- commands for bit_controller block
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_STOP : std_logic_vector(3 downto 0) := "0010";
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100";
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000";
 
-- signals for bit_controller
signal core_cmd : std_logic_vector(3 downto 0);
signal core_ack, core_txd, core_rxd : std_logic;
 
-- signals for shift register
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
signal shift, ld : std_logic;
 
-- signals for state machine
signal go, host_ack : std_logic;
signal dcnt : unsigned(2 downto 0); -- data counter
signal cnt_done : std_logic;
 
begin
-- hookup bit_controller
u1: i2c_master_bit_ctrl port map(
clk => clk,
rst => rst,
nReset => nReset,
ena => ena,
clk_cnt => clk_cnt,
cmd => core_cmd,
cmd_ack => core_ack,
busy => i2c_busy,
din => core_txd,
dout => core_rxd,
scl_i => scl_i,
scl_o => scl_o,
scl_oen => scl_oen,
sda_i => sda_i,
sda_o => sda_o,
sda_oen => sda_oen
);
 
-- generate host-command-acknowledge
cmd_ack <= host_ack;
-- generate go-signal
go <= (read or write or stop) and not host_ack;
 
-- assign Dout output to shift-register
dout <= sr;
 
-- generate shift register
shift_register: process(clk, nReset)
begin
if (nReset = '0') then
sr <= (others => '0') after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
sr <= (others => '0') after Tcq;
elsif (ld = '1') then
sr <= din after Tcq;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd) after Tcq;
end if;
end if;
end process shift_register;
 
-- generate data-counter
data_cnt: process(clk, nReset)
begin
if (nReset = '0') then
dcnt <= (others => '0') after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
dcnt <= (others => '0') after Tcq;
elsif (ld = '1') then
dcnt <= (others => '1') after Tcq; -- load counter with 7
elsif (shift = '1') then
dcnt <= dcnt -1 after Tcq;
end if;
end if;
end process data_cnt;
 
cnt_done <= '1' when (dcnt = 0) else '0';
 
--
-- state machine
--
statemachine : block
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal c_state : states;
begin
--
-- command interpreter, translate complex commands into simpler I2C commands
--
nxt_state_decoder: process(clk, nReset)
begin
if (nReset = '0') then
core_cmd <= I2C_CMD_NOP after Tcq;
core_txd <= '0' after Tcq;
shift <= '0' after Tcq;
ld <= '0' after Tcq;
 
host_ack <= '0' after Tcq;
c_state <= st_idle after Tcq;
 
ack_out <= '0' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
core_cmd <= I2C_CMD_NOP after Tcq;
core_txd <= '0' after Tcq;
shift <= '0' after Tcq;
ld <= '0' after Tcq;
 
host_ack <= '0' after Tcq;
c_state <= st_idle after Tcq;
 
ack_out <= '0' after Tcq;
else
-- initialy reset all signal
core_txd <= sr(7) after Tcq;
 
shift <= '0' after Tcq;
ld <= '0' after Tcq;
 
host_ack <= '0' after Tcq;
 
case c_state is
when st_idle =>
if (go = '1') then
if (start = '1') then
c_state <= st_start after Tcq;
core_cmd <= I2C_CMD_START after Tcq;
elsif (read = '1') then
c_state <= st_read after Tcq;
core_cmd <= I2C_CMD_READ after Tcq;
elsif (write = '1') then
c_state <= st_write after Tcq;
core_cmd <= I2C_CMD_WRITE after Tcq;
else -- stop
c_state <= st_stop after Tcq;
core_cmd <= I2C_CMD_STOP after Tcq;
 
host_ack <= '1' after Tcq; -- generate acknowledge signal
end if;
 
ld <= '1' after Tcq;
end if;
 
when st_start =>
if (core_ack = '1') then
if (read = '1') then
c_state <= st_read after Tcq;
core_cmd <= I2C_CMD_READ after Tcq;
else
c_state <= st_write after Tcq;
core_cmd <= I2C_CMD_WRITE after Tcq;
end if;
 
ld <= '1' after Tcq;
end if;
 
when st_write =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack after Tcq;
core_cmd <= I2C_CMD_READ after Tcq;
else
c_state <= st_write after Tcq; -- stay in same state
core_cmd <= I2C_CMD_WRITE after Tcq; -- write next bit
 
shift <= '1' after Tcq;
end if;
end if;
 
when st_read =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack after Tcq;
core_cmd <= I2C_CMD_WRITE after Tcq;
else
c_state <= st_read after Tcq; -- stay in same state
core_cmd <= I2C_CMD_READ after Tcq; -- read next bit
end if;
 
shift <= '1' after Tcq;
core_txd <= ack_in after Tcq;
end if;
 
when st_ack =>
if (core_ack = '1') then
-- check for stop; Should a STOP command be generated ?
if (stop = '1') then
c_state <= st_stop after Tcq;
core_cmd <= I2C_CMD_STOP after Tcq;
else
c_state <= st_idle after Tcq;
core_cmd <= I2C_CMD_NOP after Tcq;
end if;
 
-- assign ack_out output to core_rxd (contains last received bit)
ack_out <= core_rxd after Tcq;
 
-- generate command acknowledge signal
host_ack <= '1' after Tcq;
 
core_txd <= '1' after Tcq;
else
core_txd <= ack_in after Tcq;
end if;
 
when st_stop =>
if (core_ack = '1') then
c_state <= st_idle after Tcq;
core_cmd <= I2C_CMD_NOP after Tcq;
end if;
 
when others => -- illegal states
c_state <= st_idle after Tcq;
core_cmd <= I2C_CMD_NOP after Tcq;
report ("Byte controller entered illegal state.");
 
end case;
 
end if;
end if;
end process nxt_state_decoder;
 
end block statemachine;
 
end architecture structural;
 
/trunk/rtl/vhdl/i2c_master_bit_ctrl.vhd
0,0 → 1,428
---------------------------------------------------------------------
---- ----
---- WISHBONE revB2 compl. I2C Master Core; bit-controller ----
---- ----
---- ----
---- Author: Richard Herveille ----
---- richard@asics.ws ----
---- www.asics.ws ----
---- ----
---- Downloaded from: http://www.opencores.org/projects/i2c/ ----
---- ----
---------------------------------------------------------------------
---- ----
---- Copyright (C) 2000 Richard Herveille ----
---- richard@asics.ws ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer.----
---- ----
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ----
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ----
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ----
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ----
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ----
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ----
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ----
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ----
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ----
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ----
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ----
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ----
---- POSSIBILITY OF SUCH DAMAGE. ----
---- ----
---------------------------------------------------------------------
 
-- CVS Log
--
-- $Id: i2c_master_bit_ctrl.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $
--
-- $Date: 2001-11-05 12:02:33 $
-- $Revision: 1.1 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
--
-- Change History:
-- $Log: not supported by cvs2svn $
 
 
--
-------------------------------------
-- Bit controller section
------------------------------------
--
-- Translate simple commands into SCL/SDA transitions
-- Each command has 5 states, A/B/C/D/idle
--
-- start: SCL ~~~~~~~~~~\____
-- SDA ~~~~~~~~\______
-- x | A | B | C | D | i
--
-- repstart SCL ____/~~~~\___
-- SDA __/~~~\______
-- x | A | B | C | D | i
--
-- stop SCL ____/~~~~~~~~
-- SDA ==\____/~~~~~
-- x | A | B | C | D | i
--
--- write SCL ____/~~~~\____
-- SDA ==X=========X=
-- x | A | B | C | D | i
--
--- read SCL ____/~~~~\____
-- SDA XXXX=====XXXX
-- x | A | B | C | D | i
--
 
-- Timing: Normal mode Fast mode
-----------------------------------------------------------------
-- Fscl 100KHz 400KHz
-- Th_scl 4.0us 0.6us High period of SCL
-- Tl_scl 4.7us 1.3us Low period of SCL
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity i2c_master_bit_ctrl is
generic(
Tcq : time := 1 ns
);
port (
clk : in std_logic;
rst : in std_logic;
nReset : in std_logic;
ena : in std_logic; -- core enable signal
 
clk_cnt : in unsigned(15 downto 0); -- clock prescale value
 
cmd : in std_logic_vector(3 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;
 
din : in std_logic;
dout : out std_logic;
 
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
end entity i2c_master_bit_ctrl;
 
architecture structural of i2c_master_bit_ctrl is
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_STOP : std_logic_vector(3 downto 0) := "0010";
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100";
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000";
 
type states is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
signal c_state : states;
 
signal iscl_oen, isda_oen : std_logic; -- internal I2C lines
signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs
 
signal clk_en, slave_wait :std_logic; -- clock generation signals
-- signal cnt : unsigned(15 downto 0) := clk_cnt; -- clock divider counter (simulation)
signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis)
 
begin
-- synchronize SCL and SDA inputs
synch_scl_sda: process(clk)
begin
if (clk'event and clk = '1') then
sSCL <= scl_i after Tcq;
sSDA <= sda_i after Tcq;
end if;
end process synch_SCL_SDA;
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
slave_wait <= iscl_oen and not sSCL;
 
-- generate clk enable signal
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
cnt <= (others => '0') after Tcq;
clk_en <= '1' after Tcq;
else
if ( (cnt = 0) or (ena = '0') ) then
clk_en <= '1' after Tcq;
cnt <= clk_cnt after Tcq;
else
if (slave_wait = '0') then
cnt <= cnt -1 after Tcq;
end if;
clk_en <= '0' after Tcq;
end if;
end if;
end if;
end process gen_clken;
 
 
-- generate bus status controller
bus_status_ctrl: block
signal dSDA : std_logic;
signal sta_condition : std_logic;
signal sto_condition : std_logic;
 
signal ibusy : std_logic;
begin
-- detect start condition => detect falling edge on SDA while SCL is high
-- detect stop condition => detect rising edge on SDA while SCL is high
detect_sta_sto: process(clk)
begin
if (clk'event and clk = '1') then
dSDA <= sSDA; -- generate a delayed version of sSDA
 
sta_condition <= (not sSDA and dSDA) and sSCL;
sto_condition <= (sSDA and not dSDA) and sSCL;
end if;
end process detect_sta_sto;
 
-- generate bus busy signal
gen_busy: process(clk, nReset)
begin
if (nReset = '0') then
ibusy <= '0' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
ibusy <= '0' after Tcq;
else
ibusy <= (sta_condition or ibusy) and not sto_condition after Tcq;
end if;
end if;
end process gen_busy;
 
-- assign output
busy <= ibusy;
end block bus_status_ctrl;
 
 
-- generate statemachine
nxt_state_decoder : process (clk, nReset, c_state, cmd)
variable nxt_state : states;
variable icmd_ack, store_sda : std_logic;
begin
 
nxt_state := c_state;
 
icmd_ack := '0'; -- default no acknowledge
 
store_sda := '0';
 
case (c_state) is
-- idle
when idle =>
case cmd is
when I2C_CMD_START =>
nxt_state := start_a;
 
when I2C_CMD_STOP =>
nxt_state := stop_a;
 
when I2C_CMD_WRITE =>
nxt_state := wr_a;
 
when I2C_CMD_READ =>
nxt_state := rd_a;
 
when others => -- NOP command
nxt_state := idle;
end case;
 
-- start
when start_a =>
nxt_state := start_b;
 
when start_b =>
nxt_state := start_c;
 
when start_c =>
nxt_state := start_d;
 
when start_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
-- stop
when stop_a =>
nxt_state := stop_b;
 
when stop_b =>
nxt_state := stop_c;
 
when stop_c =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
-- read
when rd_a =>
nxt_state := rd_b;
 
when rd_b =>
nxt_state := rd_c;
 
when rd_c =>
nxt_state := rd_d;
store_sda := '1';
 
when rd_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
-- write
when wr_a =>
nxt_state := wr_b;
 
when wr_b =>
nxt_state := wr_c;
 
when wr_c =>
nxt_state := wr_d;
 
when wr_d =>
nxt_state := idle;
icmd_ack := '1'; -- command completed
 
end case;
 
-- generate regs
if (nReset = '0') then
c_state <= idle after Tcq;
cmd_ack <= '0' after Tcq;
Dout <= '0' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
c_state <= idle after Tcq;
cmd_ack <= '0' after Tcq;
Dout <= '0' after Tcq;
else
if (clk_en = '1') then
c_state <= nxt_state after Tcq;
 
if (store_sda = '1') then
dout <= sSDA after Tcq;
end if;
end if;
 
cmd_ack <= icmd_ack and clk_en;
end if;
end if;
end process nxt_state_decoder;
 
--
-- convert states to SCL and SDA signals
--
output_decoder: process (clk, nReset, c_state, iscl_oen, isda_oen, din)
variable iscl, isda : std_logic;
begin
case (c_state) is
when idle =>
iscl := iscl_oen; -- keep SCL in same state
isda := isda_oen; -- keep SDA in same state
 
-- start
when start_a =>
iscl := iscl_oen; -- keep SCL in same state (for repeated start)
isda := '1'; -- set SDA high
 
when start_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- keep SDA high
 
when start_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- sel SDA low
 
when start_d =>
iscl := '0'; -- set SCL low
isda := '0'; -- keep SDA low
 
-- stop
when stop_a =>
iscl := '0'; -- keep SCL disabled
isda := '0'; -- set SDA low
 
when stop_b =>
iscl := '1'; -- set SCL high
isda := '0'; -- keep SDA low
 
when stop_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- set SDA high
 
-- write
when wr_a =>
iscl := '0'; -- keep SCL low
isda := din; -- set SDA
 
when wr_b =>
iscl := '1'; -- set SCL high
isda := din; -- keep SDA
 
when wr_c =>
iscl := '1'; -- keep SCL high
isda := din; -- keep SDA
 
when wr_d =>
iscl := '0'; -- set SCL low
isda := din; -- keep SDA
 
-- read
when rd_a =>
iscl := '0'; -- keep SCL low
isda := '1'; -- tri-state SDA
 
when rd_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- tri-state SDA
 
when rd_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- tri-state SDA
 
when rd_d =>
iscl := '0'; -- set SCL low
isda := '1'; -- tri-state SDA
end case;
 
-- generate registers
if (nReset = '0') then
iscl_oen <= '1' after Tcq;
isda_oen <= '1' after Tcq;
elsif (clk'event and clk = '1') then
if (rst = '1') then
iscl_oen <= '1' after Tcq;
isda_oen <= '1' after Tcq;
else
if (clk_en = '1') then
iscl_oen <= iscl after Tcq;
isda_oen <= isda after Tcq;
end if;
end if;
end if;
end process output_decoder;
 
-- assign outputs
scl_o <= '0';
scl_oen <= iscl_oen;
sda_o <= '0';
sda_oen <= isda_oen;
end architecture structural;
/trunk/rtl/vhdl/i2c_master_top.vhd
0,0 → 1,342
---------------------------------------------------------------------
---- ----
---- WISHBONE revB2 compl. I2C Master Core; top level ----
---- ----
---- ----
---- Author: Richard Herveille ----
---- richard@asics.ws ----
---- www.asics.ws ----
---- ----
---- Downloaded from: http://www.opencores.org/projects/i2c/ ----
---- ----
---------------------------------------------------------------------
---- ----
---- Copyright (C) 2000 Richard Herveille ----
---- richard@asics.ws ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer.----
---- ----
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ----
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ----
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ----
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ----
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ----
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ----
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ----
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ----
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ----
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ----
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ----
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ----
---- POSSIBILITY OF SUCH DAMAGE. ----
---- ----
---------------------------------------------------------------------
 
-- CVS Log
--
-- $Id: i2c_master_top.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $
--
-- $Date: 2001-11-05 12:02:33 $
-- $Revision: 1.1 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
--
-- Change History:
-- $Log: not supported by cvs2svn $
 
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
 
entity i2c_master_top is
generic(
ARST_LVL : std_logic := '0'; -- asynchronous reset level
 
-- Register timing parameters.
-- Last parameters in list for
-- verilog compatibility
Tcq : time := 1 ns -- Clock to output delay
);
port (
-- wishbone signals
wb_clk_i : in std_logic; -- master clock input
wb_rst_i : in std_logic := '0'; -- synchronous active high reset
arst_i : in std_logic := not ARST_LVL; -- asynchronous reset
wb_adr_i : in unsigned(2 downto 0); -- lower address bits
wb_dat_i : in std_logic_vector(7 downto 0); -- Databus input
wb_dat_o : out std_logic_vector(7 downto 0); -- Databus output
wb_we_i : in std_logic; -- Write enable input
wb_stb_i : in std_logic; -- Strobe signals / core select signal
wb_cyc_i : in std_logic; -- Valid bus cycle input
wb_ack_o : out std_logic; -- Bus cycle acknowledge output
wb_inta_o : out std_logic; -- interrupt request output signal
 
-- i2c lines
scl_pad_i : in std_logic; -- i2c clock line input
scl_pad_o : out std_logic; -- i2c clock line output
scl_padoen_o : out std_logic; -- i2c clock line output enable, active low
sda_pad_i : in std_logic; -- i2c data line input
sda_pad_o : out std_logic; -- i2c data line output
sda_padoen_o : out std_logic -- i2c data line output enable, active low
);
end entity i2c_master_top;
 
architecture structural of i2c_master_top is
component i2c_master_byte_ctrl is
generic(
Tcq : time := Tcq
);
port (
clk : in std_logic;
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible)
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible)
ena : in std_logic; -- core enable signal
 
clk_cnt : in unsigned(15 downto 0); -- 4x SCL
 
-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
din : in std_logic_vector(7 downto 0);
 
-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
i2c_busy : out std_logic;
dout : out std_logic_vector(7 downto 0);
 
-- i2c lines
scl_i : in std_logic; -- i2c clock line input
scl_o : out std_logic; -- i2c clock line output
scl_oen : out std_logic; -- i2c clock line output enable, active low
sda_i : in std_logic; -- i2c data line input
sda_o : out std_logic; -- i2c data line output
sda_oen : out std_logic -- i2c data line output enable, active low
);
end component i2c_master_byte_ctrl;
 
-- registers
signal prer : unsigned(15 downto 0); -- clock prescale register
signal ctr : std_logic_vector(7 downto 0); -- control register
signal txr : std_logic_vector(7 downto 0); -- transmit register
signal rxr : std_logic_vector(7 downto 0); -- receive register
signal cr : std_logic_vector(7 downto 0); -- command register
signal sr : std_logic_vector(7 downto 0); -- status register
 
-- internal reset signal
signal rst_i : std_logic;
 
-- done signal: command completed, clear command register
signal done : std_logic;
 
-- command register signals
signal sta, sto, rd, wr, ack, iack : std_logic;
 
-- core enable signal
signal core_en : std_logic;
signal ien : std_logic;
 
-- status register signals
signal irxack, rxack : std_logic; -- received aknowledge from slave
signal tip : std_logic; -- transfer in progress
signal irq_flag : std_logic; -- interrupt pending flag
signal i2c_busy : std_logic; -- bus busy (start signal detected)
 
begin
-- generate internal reset signal
rst_i <= arst_i xor ARST_LVL;
 
-- generate acknowledge output signal
wb_ack_o <= wb_cyc_i and wb_stb_i; -- because timing is always honored
 
-- assign wb_dat_o
assign_dato : process(wb_adr_i, prer, ctr, txr, cr, rxr, sr)
begin
case wb_adr_i is
when "000" =>
wb_dat_o <= std_logic_vector(prer( 7 downto 0));
 
when "001" =>
wb_dat_o <= std_logic_vector(prer(15 downto 8));
 
when "010" =>
wb_dat_o <= ctr;
 
when "011" =>
wb_dat_o <= rxr; -- write is transmit register TxR
 
when "100" =>
wb_dat_o <= sr; -- write is command register CR
 
-- Debugging registers:
-- These registers are not documented.
-- Functionality could change in future releases
 
when "101" =>
wb_dat_o <= txr;
 
when "110" =>
wb_dat_o <= cr;
 
when "111" =>
wb_dat_o <= (others => '0');
 
when others =>
wb_dat_o <= (others => 'X'); -- for simulation only
 
end case;
end process assign_dato;
 
 
-- registers block
regs_block: process(rst_i, wb_clk_i)
begin
if (rst_i = '0') then
prer <= (others => '0') after Tcq;
ctr <= (others => '0') after Tcq;
txr <= (others => '0') after Tcq;
cr <= (others => '0') after Tcq;
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
prer <= (others => '0') after Tcq;
ctr <= (others => '0') after Tcq;
txr <= (others => '0') after Tcq;
cr <= (others => '0') after Tcq;
else
if (wb_cyc_i = '1' and wb_stb_i = '1' and wb_we_i = '1') then
if (wb_adr_i(2) = '0') then
case wb_adr_i(1 downto 0) is
when "00" => prer( 7 downto 0) <= unsigned(wb_dat_i) after Tcq;
when "01" => prer(15 downto 8) <= unsigned(wb_dat_i) after Tcq;
when "10" => ctr <= wb_dat_i after Tcq;
when "11" => txr <= wb_dat_i after Tcq;
 
-- illegal cases, for simulation only
when others =>
report ("Illegal write address, setting all registers to unknown.");
prer <= (others => 'X');
ctr <= (others => 'X');
txr <= (others => 'X');
end case;
elsif ( (core_en = '1') and (wb_adr_i(1 downto 0) = 0) ) then
-- only take new commands when i2c ore enabled
-- pending commands are finished
cr <= wb_dat_i after Tcq;
end if;
else
-- clear command bits when done
if (done = '1') then
cr(7 downto 4) <= (others => '0') after Tcq;
end if;
 
-- reserved bits
cr(2 downto 1) <= (others => '0') after Tcq;
 
-- clear iack when irq_flag cleared
cr(0) <= cr(0) and irq_flag;
end if;
end if;
end if;
end process regs_block;
-- decode command register
sta <= cr(7);
sto <= cr(6);
rd <= cr(5);
wr <= cr(4);
ack <= cr(3);
iack <= cr(0);
 
-- decode control register
core_en <= ctr(7);
ien <= ctr(6);
 
-- hookup byte controller block
u1: i2c_master_byte_ctrl port map (
clk => wb_clk_i,
rst => wb_rst_i,
nReset => rst_i,
ena => core_en,
clk_cnt => prer,
start => sta,
stop => sto,
read => rd,
write => wr,
ack_in => ack,
i2c_busy => i2c_busy,
din => txr,
cmd_ack => done,
ack_out => irxack,
dout => rxr,
scl_i => scl_pad_i,
scl_o => scl_pad_o,
scl_oen => scl_padoen_o,
sda_i => sda_pad_i,
sda_o => sda_pad_o,
sda_oen => sda_padoen_o
);
 
 
-- status register block + interrupt request signal
st_irq_block : block
begin
-- generate status register bits
gen_sr_bits: process (wb_clk_i, rst_i)
begin
if (rst_i = '0') then
rxack <= '0' after Tcq;
tip <= '0' after Tcq;
irq_flag <= '0' after Tcq;
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
rxack <= '0' after Tcq;
tip <= '0' after Tcq;
irq_flag <= '0' after Tcq;
else
rxack <= irxack after Tcq;
tip <= (rd or wr) after Tcq;
 
-- interrupt request flag is always generated
irq_flag <= (done or irq_flag) and not iack after Tcq;
end if;
end if;
end process gen_sr_bits;
 
-- generate interrupt request signals
gen_irq: process (wb_clk_i, rst_i)
begin
if (rst_i = '0') then
wb_inta_o <= '0' after Tcq;
elsif (wb_clk_i'event and wb_clk_i = '1') then
if (wb_rst_i = '1') then
wb_inta_o <= '0' after Tcq;
else
-- interrupt signal is only generated when IEN (interrupt enable bit) is set
wb_inta_o <= irq_flag and ien after Tcq;
end if;
end if;
end process gen_irq;
 
-- assign status register bits
sr(7) <= rxack;
sr(6) <= i2c_busy;
sr(5 downto 2) <= (others => '0'); -- reserved
sr(1) <= tip;
sr(0) <= irq_flag;
end block;
 
end architecture structural;
 
 
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.