Commit ff660239 authored by Theodor-Adrian Stana's avatar Theodor-Adrian Stana Committed by Tomasz Wlostowski

Made I2C slave and bridge work properly

- I2C slave component now samples SDA line one rising SCL and changes
states and shifts out bits on its falling edge
- I2C slave component has clearer status outputs
- bridge component changed to reflect changes in I2C slave interface
- bridge component also returns to IDLE state on I2C stop condition, as
reflected by the I2C slave
Signed-off-by: Theodor-Adrian Stana's avatarTheodor Stana <t.stana@cern.ch>
Signed-off-by: Tomasz Wlostowski's avatarTomasz Włostowski <tomasz.wlostowski@cern.ch>
parent cef1c699
......@@ -66,29 +66,10 @@ end entity gc_glitch_filt;
architecture behav of gc_glitch_filt is
--============================================================================
-- Component declarations
--============================================================================
component gc_sync_ffs is
generic(
g_sync_edge : string := "positive"
);
port(
clk_i : in std_logic; -- clock from the destination clock domain
rst_n_i : in std_logic; -- reset
data_i : in std_logic; -- async input
synced_o : out std_logic; -- synchronized output
npulse_o : out std_logic; -- negative edge detect output (single-clock
-- pulse)
ppulse_o : out std_logic -- positive edge detect output (single-clock
-- pulse)
);
end component gc_sync_ffs;
--============================================================================
-- Signal declarations
--============================================================================
signal gc_glitch_filt : std_logic_vector(g_len downto 0);
signal glitch_filt : std_logic_vector(g_len downto 0);
signal dat_synced : std_logic;
--==============================================================================
......@@ -112,7 +93,7 @@ begin
);
-- Then, assign the current sample of the glitch filter
gc_glitch_filt(0) <= dat_synced;
glitch_filt(0) <= dat_synced;
-- Generate glitch filter FFs when the filter length is > 0
gen_glitch_filt: if (g_len > 0) generate
......@@ -120,9 +101,9 @@ begin
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
gc_glitch_filt(g_len downto 1) <= (others => '0');
glitch_filt(g_len downto 1) <= (others => '0');
else
gc_glitch_filt(g_len downto 1) <= gc_glitch_filt(g_len-1 downto 0);
glitch_filt(g_len downto 1) <= glitch_filt(g_len-1 downto 0);
end if;
end if;
end process p_glitch_filt;
......@@ -134,9 +115,9 @@ begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
dat_o <= '0';
elsif (gc_glitch_filt = (gc_glitch_filt'range => '1')) then
elsif (glitch_filt = (glitch_filt'range => '1')) then
dat_o <= '1';
elsif (gc_glitch_filt = (gc_glitch_filt'range => '0')) then
elsif (glitch_filt = (glitch_filt'range => '0')) then
dat_o <= '0';
end if;
end if;
......
......@@ -49,6 +49,8 @@
--==============================================================================
-- last changes:
-- 2013-03-13 Theodor Stana t.stana@cern.ch File created
-- 2013-11-22 Theodor Stana Changed to sampling SDA
-- on SCL rising edge
--==============================================================================
-- TODO:
-- - Stop condition
......@@ -61,53 +63,57 @@ use ieee.numeric_std.all;
use work.gencores_pkg.all;
entity gc_i2c_slave is
generic
(
-- Length of glitch filter
-- 0 - SCL and SDA lines are passed only through synchronizer
-- 1 - one clk_i glitches filtered
-- 2 - two clk_i glitches filtered
g_gf_len : natural := 0
);
port
(
-- Clock, reset ports
clk_i : in std_logic;
rst_n_i : in std_logic;
clk_i : in std_logic;
rst_n_i : in std_logic;
-- I2C lines
scl_i : in std_logic;
scl_o : out std_logic;
scl_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
sda_en_o : out std_logic;
scl_i : in std_logic;
scl_o : out std_logic;
scl_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
sda_en_o : out std_logic;
-- Slave address
i2c_addr_i : in std_logic_vector(6 downto 0);
addr_i : in std_logic_vector(6 downto 0);
-- ACK input, should be set after done_p_o = '1'
-- (note that the bit is reversed wrt I2C ACK bit)
-- '1' - ACK
-- '0' - NACK
i2c_ack_i : in std_logic;
-- I2C bus operation, set after address detection
-- '0' - write
-- '1' - read
op_o : out std_logic;
ack_i : in std_logic;
-- Byte to send, should be loaded while done_p_o = '1'
tx_byte_i : in std_logic_vector(7 downto 0);
tx_byte_i : in std_logic_vector(7 downto 0);
-- Received byte, valid after done_p_o = '1'
rx_byte_o : out std_logic_vector(7 downto 0);
-- Done pulse signal, valid when
-- * received address matches i2c_addr_i, signaling valid op_o;
-- * a byte was received, signaling valid rx_byte_o and an ACK/NACK should be
-- sent to master;
-- * sent a byte, should set tx_byte_i.
done_p_o : out std_logic;
-- I2C transfer state
-- "00" - Idle
-- "01" - Got address, matches i2c_addr_i
-- "10" - Read done, waiting ACK/NACK
-- "11" - Write done, waiting next byte
stat_o : out std_logic_vector(1 downto 0)
rx_byte_o : out std_logic_vector(7 downto 0);
-- Pulse outputs signaling various I2C actions
-- Start and stop conditions
sta_p_o : out std_logic;
sto_p_o : out std_logic;
-- Received address corresponds addr_i
addr_good_p_o : out std_logic;
-- Read and write done
r_done_p_o : out std_logic;
w_done_p_o : out std_logic;
-- I2C bus operation, set after address detection
-- '0' - write
-- '1' - read
op_o : out std_logic
);
end entity gc_i2c_slave;
......@@ -120,8 +126,8 @@ architecture behav of gc_i2c_slave is
type t_state is
(
IDLE, -- idle
STA, -- start condition received
ADDR, -- shift in I2C address bits
ADDR_CHECK, -- check received I2C address
ADDR_ACK, -- ACK/NACK to I2C address
RD, -- shift in byte to read
RD_ACK, -- ACK/NACK to received byte
......@@ -134,8 +140,8 @@ architecture behav of gc_i2c_slave is
-- Signal declarations
--============================================================================
-- Deglitched signals and delays for SCL and SDA lines
signal scl_deglitched : std_logic;
signal scl_deglitched_d0 : std_logic;
signal scl_deglitched : std_logic;
signal scl_deglitched_d0 : std_logic;
signal sda_deglitched : std_logic;
signal sda_deglitched_d0 : std_logic;
signal scl_r_edge_p : std_logic;
......@@ -143,30 +149,32 @@ architecture behav of gc_i2c_slave is
signal sda_f_edge_p : std_logic;
signal sda_r_edge_p : std_logic;
-- FSM
signal state : t_state;
-- FSM tick
signal tick_p : std_logic;
signal tick_cnt : std_logic_vector(5 downto 0);
-- FSM signals
signal state : t_state;
signal inhibit : std_logic;
-- RX and TX shift registers
signal txsr : std_logic_vector(7 downto 0);
signal rxsr : std_logic_vector(7 downto 0);
signal txsr : std_logic_vector(7 downto 0);
signal rxsr : std_logic_vector(7 downto 0);
-- Bit counter on RX & TX
signal bit_cnt : unsigned(2 downto 0);
signal bit_cnt : unsigned(2 downto 0);
-- Start and stop condition pulse signals
signal sta_p, sto_p : std_logic;
-- Watchdog counter signals
signal watchdog_cnt : unsigned(26 downto 0);
signal watchdog_rst : std_logic;
signal rst_fr_watchdog : std_logic;
-- Master ACKed after it has read a byte from the slave
signal mst_acked : std_logic;
signal sda_en : std_logic;
--==============================================================================
-- architecture begin
--==============================================================================
begin
sda_en_o <= sda_en;
--============================================================================
-- I/O logic
--============================================================================
......@@ -187,7 +195,7 @@ begin
cmp_scl_deglitch : gc_glitch_filt
generic map
(
g_len => 7
g_len => g_gf_len
)
port map
(
......@@ -203,9 +211,9 @@ begin
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
scl_deglitched_d0 <= '0';
scl_f_edge_p <= '0';
scl_r_edge_p <= '0';
scl_deglitched_d0 <= '0';
scl_f_edge_p <= '0';
scl_r_edge_p <= '0';
else
scl_deglitched_d0 <= scl_deglitched;
scl_f_edge_p <= (not scl_deglitched) and scl_deglitched_d0;
......@@ -218,7 +226,7 @@ begin
cmp_sda_deglitch : gc_glitch_filt
generic map
(
g_len => 7
g_len => g_gf_len
)
port map
(
......@@ -234,9 +242,9 @@ begin
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
sda_deglitched_d0 <= '0';
sda_f_edge_p <= '0';
sda_r_edge_p <= '0';
sda_deglitched_d0 <= '0';
sda_f_edge_p <= '0';
sda_r_edge_p <= '0';
else
sda_deglitched_d0 <= sda_deglitched;
sda_f_edge_p <= (not sda_deglitched) and sda_deglitched_d0;
......@@ -246,30 +254,23 @@ begin
end process p_sda_deglitched_d0;
--============================================================================
-- Tick generation
-- Start and stop condition outputs
--============================================================================
-- p_tick : process (clk_i) is
-- begin
-- if rising_edge(clk_i) then
-- if (rst_n_i = '0') then
-- tick_cnt <= '0';
-- tick_p <= '0';
-- elsif (scl_f_edge_p = '1') then
-- tick_en <= '1';
-- else
-- if (tick_en = '1') then
-- tick_cnt <= tick_cnt + 1;
-- tick_p <= '0';
-- if (tick_cnt = (tick_cnt'range => '1')) then
-- tick_p <= '1';
-- tick_en <= '0';
-- end if;
-- else
-- tick_p <= '0';
-- end if;
-- end if;
-- end if;
-- end process p_tick;
p_sta_sto : process (clk_i) is
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
sta_p <= '0';
sto_p <= '0';
else
sta_p <= sda_f_edge_p and scl_deglitched;
sto_p <= sda_r_edge_p and scl_deglitched;
end if;
end if;
end process p_sta_sto;
sta_p_o <= sta_p;
sto_p_o <= sto_p;
--============================================================================
-- FSM logic
......@@ -277,28 +278,24 @@ begin
p_fsm: process (clk_i) is
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') or (rst_fr_watchdog = '1') then
state <= IDLE;
watchdog_rst <= '1';
bit_cnt <= (others => '0');
rxsr <= (others => '0');
txsr <= (others => '0');
sda_en_o <= '0';
done_p_o <= '0';
op_o <= '0';
stat_o <= c_i2cs_idle;
-- I2C start condition
elsif (sda_f_edge_p = '1') and (scl_deglitched = '1') then
state <= ADDR;
bit_cnt <= (others => '0');
watchdog_rst <= '0';
-- I2C stop condition
elsif (sda_r_edge_p = '1') and (scl_deglitched = '1') then
state <= IDLE;
done_p_o <= '1';
stat_o <= c_i2cs_idle;
if (rst_n_i = '0') then
state <= IDLE;
inhibit <= '0';
bit_cnt <= (others => '0');
rxsr <= (others => '0');
txsr <= (others => '0');
mst_acked <= '0';
sda_en <= '0';
r_done_p_o <= '0';
w_done_p_o <= '0';
addr_good_p_o <= '0';
op_o <= '0';
-- start and stop conditions take the FSM back to IDLE and reset the
-- FSM inhibit signal to read the address
elsif (sta_p = '1') or (sto_p = '1') then
state <= IDLE;
inhibit <= '0';
-- state machine logic
else
......@@ -307,27 +304,20 @@ begin
-- IDLE
---------------------------------------------------------------------
-- When idle, outputs and bit counters are cleared, while waiting
-- for a start condition.
-- for a falling edge on SCL. The falling edge has to be validated
-- by the inhibit signal, which states whether it is this or another
-- slave being addressed.
---------------------------------------------------------------------
when IDLE =>
bit_cnt <= (others => '0');
sda_en_o <= '0';
done_p_o <= '0';
watchdog_rst <= '1';
stat_o <= c_i2cs_idle;
-- ---------------------------------------------------------------------
-- -- STA
-- ---------------------------------------------------------------------
-- -- When a start condition is received, the bit counter gets cleared
-- -- to prepare for receiving the address byte. On the falling edge of
-- -- SCL, we go into the address state.
-- ---------------------------------------------------------------------
-- when STA =>
-- bit_cnt <= (others => '0');
-- if (scl_f_edge_p = '1') then
-- state <= ADDR;
-- end if;
bit_cnt <= (others => '0');
sda_en <= '0';
mst_acked <= '0';
r_done_p_o <= '0';
w_done_p_o <= '0';
addr_good_p_o <= '0';
if (scl_f_edge_p = '1') and (inhibit = '0') then
state <= ADDR;
end if;
---------------------------------------------------------------------
-- ADDR
......@@ -342,67 +332,65 @@ begin
if (scl_r_edge_p = '1') then
rxsr <= rxsr(6 downto 0) & sda_deglitched;
bit_cnt <= bit_cnt + 1;
end if;
if (scl_f_edge_p = '1') then
-- Shifted in 8 bits, go to ADDR_ACK. Check to see if received
-- address is ours and set op_o if so.
if (bit_cnt = 7) then
state <= ADDR_ACK;
if (rxsr(6 downto 0) = i2c_addr_i) then
op_o <= sda_deglitched;
done_p_o <= '1';
stat_o <= c_i2cs_addr_good;
end if;
if (bit_cnt = 0) then
state <= ADDR_CHECK;
end if;
end if;
---------------------------------------------------------------------
-- ADDR_ACK
-- ADDR_CHECK
---------------------------------------------------------------------
-- Here, we check to see if the address is ours and ACK/NACK
-- accordingly. The next action is dependent upon the state of the
-- R/W bit received via I2C.
when ADDR_CHECK =>
-- if the address is ours, set the OP output and go to ACK state
if (rxsr(7 downto 1) = addr_i) then
op_o <= rxsr(0);
addr_good_p_o <= '1';
state <= ADDR_ACK;
-- if the address is not ours, the FSM should be inhibited so a
-- byte sent to another slave doesn't get interpreted as this
-- slave's address
else
inhibit <= '1';
state <= IDLE;
end if;
---------------------------------------------------------------------
-- ADDR_ACK
---------------------------------------------------------------------
when ADDR_ACK =>
-- Clear done pulse
done_p_o <= '0';
-- we write the ACK bit, so enable output
sda_en_o <= i2c_ack_i;
-- If the received address is ours, send the ACK set by external
-- module and, on the falling edge of SCL, go to appropriate state
-- based on R/W bit.
if (rxsr(7 downto 1) = i2c_addr_i) then
if (scl_f_edge_p = '1') then
sda_en_o <= '0';
if (rxsr(0) = '0') then
state <= RD;
else
state <= WR_LOAD_TXSR;
end if;
addr_good_p_o <= '0';
sda_en <= ack_i;
if (scl_f_edge_p = '1') then
if (rxsr(0) = '0') then
state <= RD;
else
state <= WR_LOAD_TXSR;
end if;
-- If received address is not ours, NACK and go back to IDLE
else
sda_en_o <= '0';
state <= IDLE;
end if;
---------------------------------------------------------------------
-- RD
---------------------------------------------------------------------
-- Shift in bits sent by the master.
-- Shift in bits sent by the master
---------------------------------------------------------------------
when RD =>
-- Shifting occurs on falling edge of SCL
if (scl_f_edge_p = '1') then
sda_en <= '0';
if (scl_r_edge_p = '1') then
rxsr <= rxsr(6 downto 0) & sda_deglitched;
bit_cnt <= bit_cnt + 1;
end if;
if (scl_f_edge_p = '1') then
-- Received 8 bits, go to RD_ACK and signal external module
if (bit_cnt = 7) then
state <= RD_ACK;
done_p_o <= '1';
stat_o <= c_i2cs_rd_done;
if (bit_cnt = 0) then
state <= RD_ACK;
r_done_p_o <= '1';
end if;
end if;
......@@ -413,16 +401,15 @@ begin
---------------------------------------------------------------------
when RD_ACK =>
-- Clear done pulse
done_p_o <= '0';
r_done_p_o <= '0';
-- we write the ACK bit, so enable output and send the ACK bit
sda_en_o <= i2c_ack_i;
sda_en <= ack_i;
-- based on the ACK received by external command, we read the next
-- bit (ACK) or go back to idle state (NACK)
if (scl_f_edge_p = '1') then
sda_en_o <= '0';
if (i2c_ack_i = '1') then
if (ack_i = '1') then
state <= RD;
else
state <= IDLE;
......@@ -432,7 +419,7 @@ begin
---------------------------------------------------------------------
-- WR_LOAD_TXSR
---------------------------------------------------------------------
-- Load TXSR with the input value.
-- Load TXSR with the input value
---------------------------------------------------------------------
when WR_LOAD_TXSR =>
txsr <= tx_byte_i;
......@@ -441,39 +428,48 @@ begin
---------------------------------------------------------------------
-- WR
---------------------------------------------------------------------
-- Shift out the eight bits of TXSR.
-- Shift out the eight bits of TXSR
---------------------------------------------------------------------
when WR =>
-- slave writes, so enable output
sda_en_o <= txsr(7);
-- slave writes, SDA output enable is the negated value of the bit
-- to send (since on I2C, '1' is a release of the bus)
sda_en <= not txsr(7);
-- Shift TXSR on falling edge of SCL
if (scl_f_edge_p = '1') then
txsr <= txsr(6 downto 0) & '0';
-- increment bit counter on rising edge
if (scl_r_edge_p = '1') then
bit_cnt <= bit_cnt + 1;
end if;
-- Shift TXSR after falling edge of SCL
if (scl_f_edge_p = '1') then
txsr <= txsr(6 downto 0) & '0';
-- Eight bits sent, disable SDA end go to WR_ACK
if (bit_cnt = 7) then
sda_en_o <= '0';
state <= WR_ACK;
done_p_o <= '1';
stat_o <= c_i2cs_wr_done;
-- Eight bits sent, disable SDA and go to WR_ACK
if (bit_cnt = 0) then
state <= WR_ACK;
w_done_p_o <= '1';
end if;
end if;
---------------------------------------------------------------------
-- WR_ACK
---------------------------------------------------------------------
-- The master drives the ACK bit here, so on the falling edge of
-- SCL, we check the ack bit. A '0' (ACK) means more bits should be sent,
-- so we load the next value of the TXSR. A '1' (NACK) means the
-- master is done reading and a STO follows, so we go back to IDLE
-- state.
-- Check the ACK bit received from the master and go back to writing
-- another byte if ACKed, or to IDLE if NACKed
---------------------------------------------------------------------
when WR_ACK =>
done_p_o <= '0';
if (scl_f_edge_p = '1') then
sda_en <= '0';
w_done_p_o <= '0';
if (scl_r_edge_p = '1') then
if (sda_deglitched = '0') then
mst_acked <= '1';
else
mst_acked <= '0';
end if;
end if;
if (scl_f_edge_p = '1') then
if (mst_acked = '1') then
state <= WR_LOAD_TXSR;
else
state <= IDLE;
......@@ -481,7 +477,7 @@ begin
end if;
---------------------------------------------------------------------
-- Any other state: go back to idle.
-- Any other state: go back to IDLE
---------------------------------------------------------------------
when others =>
state <= IDLE;
......@@ -491,30 +487,6 @@ begin
end if;
end process p_fsm;
--============================================================================
-- Watchdog counter process
-- Resets the FSM after one second. The watchdog_rst signal is controlled by
-- the FSM and resets the watchdog if the I2C master still controls the
-- slave, signaled by the SCL line going low. If for one second the master
-- does not toggle the SCL line, the FSM gets reset.
--============================================================================
p_watchdog: process(clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') or (watchdog_rst = '1') then
watchdog_cnt <= (others => '0');
rst_fr_watchdog <= '0';
else
watchdog_cnt <= watchdog_cnt + 1;
rst_fr_watchdog <= '0';
if (watchdog_cnt = 124999999) then
watchdog_cnt <= (others => '0');
rst_fr_watchdog <= '1';
end if;
end if;
end if;
end process p_watchdog;
end architecture behav;
--==============================================================================
-- architecture end
......
......@@ -4,9 +4,10 @@
-------------------------------------------------------------------------------
-- File : gencores_pkg.vhd
-- Author : Tomasz Wlostowski
-- Theodor-Adrian Stana
-- Company : CERN
-- Created : 2009-09-01
-- Last update: 2013-07-02
-- Last update: 2013-11-20
-- Platform : FPGA-generic
-- Standard : VHDL '93
-------------------------------------------------------------------------------
......@@ -38,6 +39,7 @@
-- Date Version Author Description
-- 2009-09-01 0.9 twlostow Created
-- 2011-04-18 1.0 twlostow Added comments & header
-- 2013-11-20 1.1 tstana Added glitch filter and I2C slave
-------------------------------------------------------------------------------
library ieee;
......@@ -48,7 +50,9 @@ use work.genram_pkg.all;
package gencores_pkg is
--============================================================================
-- Component instantiations
--============================================================================
component gc_extend_pulse
generic (
g_width : natural);
......@@ -201,7 +205,7 @@ package gencores_pkg is
q_valid_o : out std_logic;
q_input_id_o : out std_logic_vector(f_log2_size(g_num_inputs)-1 downto 0));
end component;
-- Power-On reset generation
component gc_reset is
generic(
......@@ -240,7 +244,7 @@ package gencores_pkg is
q_o : out std_logic_vector(g_output_width-1 downto 0);
q_valid_o : out std_logic;
q_req_i : in std_logic);
end component;
end component;
component gc_big_adder is
generic(
......@@ -256,8 +260,7 @@ package gencores_pkg is
x2_o : out std_logic_vector(g_data_bits-1 downto 0);
c2_o : out std_logic);
end component;
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- I2C slave
------------------------------------------------------------------------------
constant c_i2cs_idle : std_logic_vector(1 downto 0) := "00";
......@@ -266,53 +269,57 @@ package gencores_pkg is
constant c_i2cs_wr_done : std_logic_vector(1 downto 0) := "11";
component gc_i2c_slave is
generic
(
-- Length of glitch filter
-- 0 - SCL and SDA lines are passed only through synchronizer
-- 1 - one clk_i glitches filtered
-- 2 - two clk_i glitches filtered
g_gf_len : natural := 0
);
port
(
-- Clock, reset ports
clk_i : in std_logic;
rst_n_i : in std_logic;
clk_i : in std_logic;
rst_n_i : in std_logic;
-- I2C lines
scl_i : in std_logic;
scl_o : out std_logic;
scl_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
sda_en_o : out std_logic;
scl_i : in std_logic;
scl_o : out std_logic;
scl_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
sda_en_o : out std_logic;
-- Slave address
i2c_addr_i : in std_logic_vector(6 downto 0);
addr_i : in std_logic_vector(6 downto 0);
-- ACK input, should be set after done_p_o = '1'
-- (note that the bit is reversed wrt I2C ACK bit)
-- '1' - ACK
-- '0' - NACK
i2c_ack_i : in std_logic;
-- I2C bus operation, set after address detection
-- '0' - write
-- '1' - read
op_o : out std_logic;
ack_i : in std_logic;
-- Byte to send, should be loaded while done_p_o = '1'
tx_byte_i : in std_logic_vector(7 downto 0);
tx_byte_i : in std_logic_vector(7 downto 0);
-- Received byte, valid after done_p_o = '1'
rx_byte_o : out std_logic_vector(7 downto 0);
-- Done pulse signal, valid when
-- * received address matches i2c_addr_i, signaling valid op_o;
-- * a byte was received, signaling valid rx_byte_o and an ACK/NACK should be
-- sent to master;
-- * sent a byte, should set tx_byte_i.
done_p_o : out std_logic;
-- I2C transfer state
-- "00" - Idle
-- "01" - Got address, matches i2c_addr_i
-- "10" - Read done, waiting ACK/NACK
-- "11" - Write done, waiting next byte
stat_o : out std_logic_vector(1 downto 0)
rx_byte_o : out std_logic_vector(7 downto 0);
-- Pulse outputs signaling various I2C actions
-- Start and stop conditions
sta_p_o : out std_logic;
sto_p_o : out std_logic;
-- Received address corresponds addr_i
addr_good_p_o : out std_logic;
-- Read and write done
r_done_p_o : out std_logic;
w_done_p_o : out std_logic;
-- I2C bus operation, set after address detection
-- '0' - write
-- '1' - read
op_o : out std_logic
);
end component gc_i2c_slave;
......@@ -342,10 +349,32 @@ package gencores_pkg is
);
end component gc_glitch_filt;
------------------------------------------------------------------------------
-- FSM Watchdog Timer
------------------------------------------------------------------------------
component gc_fsm_watchdog is
generic
(
-- Maximum value of watchdog timer in clk_i cycles
g_wdt_max : positive := 65535
);
port
(
-- Clock and active-low reset line
clk_i : in std_logic;
rst_n_i : in std_logic;
-- Active-high watchdog timer reset line, synchronous to clk_i
wdt_rst_i : in std_logic;
-- Active-high reset output, synchronous to clk_i
fsm_rst_o : out std_logic
);
end component gc_fsm_watchdog;
--============================================================================
-- Procedures
--============================================================================ procedure f_rr_arbitrate (
-- Procedures and functions
--============================================================================
procedure f_rr_arbitrate (
signal req : in std_logic_vector;
signal pre_grant : in std_logic_vector;
......@@ -359,7 +388,7 @@ package body gencores_pkg is
-- req = requests (1 = pending request),
-- pre_grant = previous grant vector (1 cycle delay)
-- grant = new grant vector
procedure f_rr_arbitrate (
signal req : in std_logic_vector;
signal pre_grant : in std_logic_vector;
......@@ -370,7 +399,7 @@ package body gencores_pkg is
variable gnt : std_logic_vector(req'length - 1 downto 0);
variable gntM : std_logic_vector(req'length - 1 downto 0);
variable zeros : std_logic_vector(req'length - 1 downto 0);
begin
zeros := (others => '0');
......@@ -390,7 +419,7 @@ package body gencores_pkg is
else
grant <= pre_grant;
end if;
end f_rr_arbitrate;
function f_big_ripple(a, b : std_logic_vector; c : std_logic) return std_logic_vector is
......
......@@ -66,24 +66,30 @@ entity wb_i2c_bridge is
rst_n_i : in std_logic;
-- I2C lines
sda_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
scl_en_o : out std_logic;
scl_i : in std_logic;
scl_o : out std_logic;
scl_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
sda_en_o : out std_logic;
-- I2C address
i2c_addr_i : in std_logic_vector(6 downto 0);
-- Transfer In Progress (TIP) and Error outputs
-- TIP : '1' when the I2C slave detects a matching I2C address, thus a
-- transfer is in progress
-- '0' when idle
-- ERR : '1' when the SysMon attempts to access an invalid WB slave
-- Status outputs
-- TIP : Transfer In Progress
-- '1' when the I2C slave detects a matching I2C address, thus a
-- transfer is in progress
-- '0' when idle
-- ERR : Error
-- '1' when the SysMon attempts to access an invalid WB slave
-- '0' when idle
tip_o : out std_logic;
err_o : out std_logic;
-- WDTO : Watchdog timeout (single clock cycle pulse)
-- '1' -- timeout of watchdog occured
-- '0' -- when idle
tip_o : out std_logic;
err_p_o : out std_logic;
wdto_p_o : out std_logic;
-- Wishbone master signals
wbm_stb_o : out std_logic;
......@@ -120,77 +126,75 @@ architecture behav of wb_i2c_bridge is
-- Signal declarations
--============================================================================
-- Slave component signals
signal i2c_ack : std_logic;
signal op : std_logic;
signal start_op : std_logic;
signal tx_byte : std_logic_vector(7 downto 0);
signal rx_byte : std_logic_vector(7 downto 0);
signal done : std_logic;
signal done_d0 : std_logic;
signal stat : std_logic_vector(1 downto 0);
signal slv_ack : std_logic;
signal op : std_logic;
signal tx_byte : std_logic_vector(7 downto 0);
signal rx_byte : std_logic_vector(7 downto 0);
signal slv_sta_p : std_logic;
signal slv_sto_p : std_logic;
signal slv_addr_good_p : std_logic;
signal slv_r_done_p : std_logic;
signal slv_w_done_p : std_logic;
-- Wishbone temporary signals
signal wb_dat_out : std_logic_vector(31 downto 0);
signal wb_dat_in : std_logic_vector(31 downto 0);
signal wb_adr : std_logic_vector(15 downto 0);
signal wb_cyc : std_logic;
signal wb_stb : std_logic;
signal wb_we : std_logic;
signal wb_ack : std_logic;
signal wb_err : std_logic;
signal wb_rty : std_logic;
signal wb_dat_out : std_logic_vector(31 downto 0);
signal wb_dat_in : std_logic_vector(31 downto 0);
signal wb_adr : std_logic_vector(15 downto 0);
signal wb_cyc : std_logic;
signal wb_stb : std_logic;
signal wb_we : std_logic;
signal wb_ack : std_logic;
signal wb_err : std_logic;
signal wb_rty : std_logic;
-- FSM control signals
signal state : t_state;
signal dat_byte_cnt : unsigned(1 downto 0);
signal adr_byte_cnt : unsigned(0 downto 0);
signal state : t_state;
signal dat_byte_cnt : unsigned(1 downto 0);
signal adr_byte_cnt : unsigned(0 downto 0);
-- FSM watchdog signals
signal wdt_rst : std_logic;
signal rst_fr_wdt : std_logic;
signal rst_fr_wdt_d0 : std_logic;
--==============================================================================
-- architecture begin
--==============================================================================
begin
--============================================================================
-- Slave component instantiation and connection
--============================================================================
cmp_i2c_slave: gc_i2c_slave
generic map
(
g_gf_len => 8
)
port map
(
clk_i => clk_i,
rst_n_i => rst_n_i,
-- I2C lines
scl_i => scl_i,
scl_o => scl_o,
scl_en_o => scl_en_o,
sda_i => sda_i,
sda_o => sda_o,
sda_en_o => sda_en_o,
-- Slave address
i2c_addr_i => i2c_addr_i,
-- ACK input, should be set after done_p_o = '1'
-- '0' - ACK
-- '1' - NACK
i2c_ack_i => i2c_ack,
-- I2C bus operation, set after address detection
-- '0' - write
-- '1' - read
op_o => op,
-- Byte to send, should be loaded while done_p_o = '1'
tx_byte_i => tx_byte,
-- Received byte, valid after done_p_o = '1'
rx_byte_o => rx_byte,
-- Done signal, valid when
-- * received address matches i2c_addr_i, signaling valid op_o;
-- * a byte was received, signaling valid rx_byte_o and an ACK/NACK should be
-- sent to master;
-- * sent a byte, should set tx_byte_i.
done_p_o => done,
stat_o => stat
clk_i => clk_i,
rst_n_i => rst_n_i,
scl_i => scl_i,
scl_o => scl_o,
scl_en_o => scl_en_o,
sda_i => sda_i,
sda_o => sda_o,
sda_en_o => sda_en_o,
addr_i => i2c_addr_i,
ack_i => slv_ack,
tx_byte_i => tx_byte,
rx_byte_o => rx_byte,
sta_p_o => open,
sto_p_o => slv_sto_p,
addr_good_p_o => slv_addr_good_p,
r_done_p_o => slv_r_done_p,
w_done_p_o => slv_w_done_p,
op_o => op
);
--============================================================================
......@@ -218,7 +222,7 @@ begin
p_fsm: process (clk_i) is
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
if (rst_n_i = '0') or (rst_fr_wdt = '1') then
state <= IDLE;
wb_adr <= (others => '0');
wb_dat_out <= (others => '0');
......@@ -226,13 +230,16 @@ begin
wb_cyc <= '0';
wb_stb <= '0';
wb_we <= '0';
start_op <= '0';
i2c_ack <= '0';
slv_ack <= '0';
tip_o <= '0';
err_o <= '0';
err_p_o <= '0';
wdt_rst <= '1';
adr_byte_cnt <= (others => '0');
dat_byte_cnt <= (others => '0');
elsif (slv_sto_p = '1') then
state <= IDLE;
else
case state is
---------------------------------------------------------------------
......@@ -245,15 +252,17 @@ begin
-- address, start_op will be '0' (write).
---------------------------------------------------------------------
when IDLE =>
err_o <= '0';
tip_o <= '0';
i2c_ack <= '0';
err_p_o <= '0';
tip_o <= '0';
slv_ack <= '0';
adr_byte_cnt <= (others => '0');
dat_byte_cnt <= (others => '0');
if (done = '1') and (stat = c_i2cs_addr_good) then
wdt_rst <= '1';
if (slv_addr_good_p = '1') then
tip_o <= '1';
i2c_ack <= '1';
slv_ack <= '1';
wdt_rst <= '0';
state <= SYSMON_WB_ADR;
start_op <= op;
end if;
---------------------------------------------------------------------
......@@ -263,17 +272,12 @@ begin
-- them. The second byte's ACK is also controlled by the next state.
---------------------------------------------------------------------
when SYSMON_WB_ADR =>
if (done = '1') then
if (stat = c_i2cs_rd_done) then
wb_adr <= wb_adr(7 downto 0) & rx_byte;
i2c_ack <= '1';
adr_byte_cnt <= adr_byte_cnt + 1;
if (adr_byte_cnt = 1) then
state <= SIM_WB_TRANSF;
end if;
else
i2c_ack <= '0';
state <= IDLE;
if (slv_r_done_p = '1') then
wb_adr <= wb_adr(7 downto 0) & rx_byte;
slv_ack <= '1';
adr_byte_cnt <= adr_byte_cnt + 1;
if (adr_byte_cnt = 1) then
state <= SIM_WB_TRANSF;
end if;
end if;
......@@ -288,13 +292,13 @@ begin
wb_cyc <= '1';
wb_stb <= '1';
if (wb_ack = '1') then
i2c_ack <= '1';
slv_ack <= '1';
wb_cyc <= '0';
wb_stb <= '0';
state <= OPER;
elsif (wb_err = '1') then
err_o <= '1';
i2c_ack <= '0';
err_p_o <= '1';
slv_ack <= '0';
wb_cyc <= '0';
wb_stb <= '0';
state <= IDLE;
......@@ -317,19 +321,14 @@ begin
-- output are cleared to avoid conflicts with future transfers.
---------------------------------------------------------------------
when OPER =>
if (done = '1') then
if (stat = c_i2cs_rd_done) then
wb_dat_out <= rx_byte & wb_dat_out(31 downto 8);
dat_byte_cnt <= dat_byte_cnt + 1;
i2c_ack <= '1';
state <= SYSMON_WR;
elsif (stat = c_i2cs_addr_good) and (op /= start_op) then
i2c_ack <= '1';
state <= SYSMON_RD_WB;
else
i2c_ack <= '0';
state <= IDLE;
end if;
if (slv_r_done_p = '1') then
wb_dat_out <= rx_byte & wb_dat_out(31 downto 8);
dat_byte_cnt <= dat_byte_cnt + 1;
slv_ack <= '1';
state <= SYSMON_WR;
elsif (slv_addr_good_p = '1') and (op = '1') then
slv_ack <= '1';
state <= SYSMON_RD_WB;
end if;
---------------------------------------------------------------------
......@@ -340,18 +339,15 @@ begin
-- write transfer is initiated in the next state.
---------------------------------------------------------------------
when SYSMON_WR =>
if (done = '1') then
if (stat = c_i2cs_rd_done) then
wb_dat_out <= rx_byte & wb_dat_out(31 downto 8);
dat_byte_cnt <= dat_byte_cnt + 1;
i2c_ack <= '1';
if (dat_byte_cnt = 3) then
state <= SYSMON_WR_WB;
end if;
else
i2c_ack <= '0';
state <= IDLE;
if (slv_r_done_p = '1') then
wb_dat_out <= rx_byte & wb_dat_out(31 downto 8);
dat_byte_cnt <= dat_byte_cnt + 1;
slv_ack <= '1';
if (dat_byte_cnt = 3) then
state <= SYSMON_WR_WB;
end if;
-- elsif (slv_sto_p = '1') then
-- state <= IDLE;
end if;
---------------------------------------------------------------------
......@@ -370,7 +366,7 @@ begin
wb_we <= '0';
state <= SYSMON_WR; --IDLE;
elsif (wb_err = '1') then
err_o <= '1';
err_p_o <= '1';
state <= IDLE;
end if;
......@@ -391,10 +387,10 @@ begin
wb_stb <= '0';
state <= SYSMON_RD;
elsif (wb_err = '1') then
err_o <= '1';
wb_cyc <= '0';
wb_stb <= '0';
state <= IDLE;
err_p_o <= '1';
wb_cyc <= '0';
wb_stb <= '0';
state <= IDLE;
end if;
---------------------------------------------------------------------
......@@ -403,18 +399,15 @@ begin
-- Shift out the bytes over I2C and go back to IDLE state.
---------------------------------------------------------------------
when SYSMON_RD =>
if (done = '1') then
if (stat = c_i2cs_wr_done) then
wb_dat_in <= x"00" & wb_dat_in(31 downto 8);
dat_byte_cnt <= dat_byte_cnt + 1;
i2c_ack <= '1';
if (dat_byte_cnt = 3) then
state <= IDLE;
end if;
else
i2c_ack <= '0';
state <= IDLE;
if (slv_w_done_p = '1') then
wb_dat_in <= x"00" & wb_dat_in(31 downto 8);
dat_byte_cnt <= dat_byte_cnt + 1;
slv_ack <= '1';
if (dat_byte_cnt = 3) then
state <= IDLE;
end if;
-- elsif (slv_sto_p = '1') then
-- state <= IDLE;
end if;
---------------------------------------------------------------------
......@@ -428,4 +421,48 @@ begin
end if;
end process p_fsm;
--============================================================================
-- FSM watchdog timer
--============================================================================
-- * in the case of writemregs command, a maximum of 35 bytes can be written
-- - 1 I2C address byte
-- - 2 register (Wishbone) address bytes
-- - 8*4 Wishbone register values
-- * we will therefore set the watchdog max. value to allow for 36 bytes to
-- be sent, considering a maximum clk_i frequency of 20 MHz (period = 50 ns)
-- and an SCL frequency of 100 kHz
-- * 100 us / 50 ns = 2000 clock cycles to send one byte
-- * 2000 * 36 bytes = 72000 clock cycles to send 36 bytes
-- * g_wdt_max = 72000
cmp_watchdog : gc_fsm_watchdog
generic map
(
g_wdt_max => 72000
)
port map
(
clk_i => clk_i,
rst_n_i => rst_n_i,
wdt_rst_i => wdt_rst,
fsm_rst_o => rst_fr_wdt
);
-- Process to set the timeout status pulse
p_wdto_outp : process (clk_i)
begin
if rising_edge(clk_i) then
if (rst_n_i = '0') then
rst_fr_wdt_d0 <= '0';
wdto_p_o <= '0';
else
rst_fr_wdt_d0 <= rst_fr_wdt;
wdto_p_o <= rst_fr_wdt and (not rst_fr_wdt_d0);
end if;
end if;
end process p_wdto_outp;
end behav;
--==============================================================================
-- architecture end
--==============================================================================
......@@ -910,24 +910,30 @@ package wishbone_pkg is
rst_n_i : in std_logic;
-- I2C lines
sda_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
scl_en_o : out std_logic;
scl_i : in std_logic;
scl_o : out std_logic;
scl_en_o : out std_logic;
sda_i : in std_logic;
sda_o : out std_logic;
sda_en_o : out std_logic;
-- I2C address
i2c_addr_i : in std_logic_vector(6 downto 0);
-- Transfer In Progress (TIP) and Error outputs
-- TIP : '1' when the I2C slave detects a matching I2C address, thus a
-- transfer is in progress
-- '0' when idle
-- ERR : '1' when the SysMon attempts to access an invalid WB slave
-- Status outputs
-- TIP : Transfer In Progress
-- '1' when the I2C slave detects a matching I2C address, thus a
-- transfer is in progress
-- '0' when idle
-- ERR : Error
-- '1' when the SysMon attempts to access an invalid WB slave
-- '0' when idle
tip_o : out std_logic;
err_o : out std_logic;
-- WDTO : Watchdog timeout (single clock cycle pulse)
-- '1' -- timeout of watchdog occured
-- '0' -- when idle
tip_o : out std_logic;
err_p_o : out std_logic;
wdto_p_o : out std_logic;
-- Wishbone master signals
wbm_stb_o : out std_logic;
......
--==============================================================================
-- CERN (BE-CO-HT)
-- I2C bus model
--==============================================================================
--
-- author: Theodor Stana (t.stana@cern.ch)
--
-- date of creation: 2013-11-27
--
-- version: 1.0
--
-- description:
-- A very simple I2C bus model for use in simulation, implementing the
-- wired-AND on the I2C protocol.
--
-- Masters and slaves should implement the buffers internally and connect the
-- SCL and SDA lines to the input ports of this model, as below:
-- - masters should connect to mscl_i and msda_i
-- - slaves should connect to sscl_i and ssda_i
--
-- dependencies:
--
-- references:
--
--==============================================================================
-- GNU LESSER GENERAL PUBLIC LICENSE
--==============================================================================
-- This source file is free software; you can redistribute it and/or modify it
-- under the terms of the GNU Lesser General Public License as published by the
-- Free Software Foundation; either version 2.1 of the License, or (at your
-- option) any later version. This source is distributed in the hope that it
-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--==============================================================================
-- last changes:
-- 2013-11-27 Theodor Stana File created
--==============================================================================
-- TODO: -
--==============================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity i2c_bus_model is
generic
(
g_nr_masters : positive := 1;
g_nr_slaves : positive := 1
);
port
(
-- Input ports from master lines
mscl_i : in std_logic_vector(g_nr_masters-1 downto 0);
msda_i : in std_logic_vector(g_nr_masters-1 downto 0);
-- Input ports from slave lines
sscl_i : in std_logic_vector(g_nr_slaves-1 downto 0);
ssda_i : in std_logic_vector(g_nr_slaves-1 downto 0);
-- SCL and SDA line outputs
scl_o : out std_logic;
sda_o : out std_logic
);
end entity i2c_bus_model;
architecture behav of i2c_bus_model is
--==============================================================================
-- architecture begin
--==============================================================================
begin
scl_o <= '1' when (mscl_i = (mscl_i'range => '1')) and
(sscl_i = (sscl_i'range => '1')) else
'0';
sda_o <= '1' when (msda_i = (msda_i'range => '1')) and
(ssda_i = (ssda_i'range => '1')) else
'0';
end architecture behav;
--==============================================================================
-- architecture end
--==============================================================================
---------------------------------------------------------------------
---- ----
---- WISHBONE revB2 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.17 2009-02-04 20:17:34 rherveille Exp $
--
-- $Date: 2009-02-04 20:17:34 $
-- $Revision: 1.17 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
--
-- Change History:
-- $Log: not supported by cvs2svn $
-- Revision 1.16 2009/01/20 20:40:36 rherveille
-- Fixed type iscl_oen instead of scl_oen
--
-- Revision 1.15 2009/01/20 10:34:51 rherveille
-- Added SCL clock synchronization logic
-- Fixed slave_wait signal generation
--
-- Revision 1.14 2006/10/11 12:10:13 rherveille
-- Added missing semicolons ';' on endif
--
-- Revision 1.13 2006/10/06 10:48:24 rherveille
-- fixed short scl high pulse after clock stretch
--
-- Revision 1.12 2004/05/07 11:53:31 rherveille
-- Fixed previous fix :) Made a variable vs signal mistake.
--
-- Revision 1.11 2004/05/07 11:04:00 rherveille
-- Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit.
--
-- Revision 1.10 2004/02/27 07:49:43 rherveille
-- Fixed a bug in the arbitration-lost signal generation. VHDL version only.
--
-- Revision 1.9 2003/08/12 14:48:37 rherveille
-- Forgot an 'end if' :-/
--
-- Revision 1.8 2003/08/09 07:01:13 rherveille
-- Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
-- Fixed a potential bug in the byte controller's host-acknowledge generation.
--
-- Revision 1.7 2003/02/05 00:06:02 rherveille
-- Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles.
--
-- Revision 1.6 2003/02/01 02:03:06 rherveille
-- Fixed a few 'arbitration lost' bugs. VHDL version only.
--
-- Revision 1.5 2002/12/26 16:05:47 rherveille
-- Core is now a Multimaster I2C controller.
--
-- Revision 1.4 2002/11/30 22:24:37 rherveille
-- Cleaned up code
--
-- Revision 1.3 2002/10/30 18:09:53 rherveille
-- Fixed some reported minor start/stop generation timing issuess.
--
-- Revision 1.2 2002/06/15 07:37:04 rherveille
-- Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
--
-- 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.
--
--
-------------------------------------
-- Bit controller section
------------------------------------
--
-- Translate simple commands into SCL/SDA transitions
-- Each command has 5 states, A/B/C/D/idle
--
-- start: SCL ~~~~~~~~~~~~~~\____
-- SDA XX/~~~~~~~\______
-- 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 XXX===============XX
-- x | A | B | C | D | i
--
--- read SCL ______/~~~~~~~\____
-- SDA XXXXXXX=XXXXXXXXXXX
-- 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.numeric_std.all;
entity i2c_master_bit_ctrl is
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; -- command completed
busy : out std_logic; -- i2c bus busy
al : out std_logic; -- arbitration lost
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, start_e,
stop_a, stop_b, stop_c, stop_d, 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 sda_chk : std_logic; -- check SDA status (multi-master arbitration)
signal dscl_oen : std_logic; -- delayed scl_oen signals
signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs
signal dSCL, dSDA : std_logic; -- delayed versions ofsSCL and sSDA
signal clk_en : std_logic; -- statemachine clock enable
signal scl_sync, slave_wait : std_logic; -- clock generation signals
signal ial : std_logic; -- internal arbitration lost signal
signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis)
begin
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
-- delay scl_oen
process (clk, nReset)
begin
if (nReset = '0') then
dscl_oen <= '0';
elsif (clk'event and clk = '1') then
dscl_oen <= iscl_oen;
end if;
end process;
-- slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low
-- slave_wait remains asserted until the slave releases SCL
process (clk, nReset)
begin
if (nReset = '0') then
slave_wait <= '0';
elsif (clk'event and clk = '1') then
slave_wait <= (iscl_oen and not dscl_oen and not sSCL) or (slave_wait and not sSCL);
end if;
end process;
-- master drives SCL high, but another master pulls it low
-- master start counting down its low cycle now (clock synchronization)
scl_sync <= dSCL and not sSCL and iscl_oen;
-- generate clk enable signal
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0');
clk_en <= '1';
elsif (clk'event and clk = '1') then
if ((rst = '1') or (cnt = 0) or (ena = '0') or (scl_sync = '1')) then
cnt <= clk_cnt;
clk_en <= '1';
elsif (slave_wait = '1') then
cnt <= cnt;
clk_en <= '0';
else
cnt <= cnt -1;
clk_en <= '0';
end if;
end if;
end process gen_clken;
-- generate bus status controller
bus_status_ctrl: block
signal cSCL, cSDA : std_logic_vector( 1 downto 0); -- capture SDA and SCL
signal fSCL, fSDA : std_logic_vector( 2 downto 0); -- filter inputs for SCL and SDA
signal filter_cnt : unsigned(13 downto 0); -- clock divider for filter
signal sta_condition : std_logic; -- start detected
signal sto_condition : std_logic; -- stop detected
signal cmd_stop : std_logic; -- STOP command
signal ibusy : std_logic; -- internal busy signal
begin
-- capture SCL and SDA
capture_scl_sda: process(clk, nReset)
begin
if (nReset = '0') then
cSCL <= "00";
cSDA <= "00";
elsif (clk'event and clk = '1') then
if (rst = '1') then
cSCL <= "00";
cSDA <= "00";
else
cSCL <= (cSCL(0) & scl_i);
cSDA <= (cSDA(0) & sda_i);
end if;
end if;
end process capture_scl_sda;
-- filter SCL and SDA; (attempt to) remove glitches
filter_divider: process(clk, nReset)
begin
if (nReset = '0') then
filter_cnt <= (others => '0');
elsif (clk'event and clk = '1') then
if ( (rst = '1') or (ena = '0') ) then
filter_cnt <= (others => '0');
elsif (filter_cnt = 0) then
filter_cnt <= clk_cnt(15 downto 2);
else
filter_cnt <= filter_cnt -1;
end if;
end if;
end process filter_divider;
filter_scl_sda: process(clk, nReset)
begin
if (nReset = '0') then
fSCL <= (others => '1');
fSDA <= (others => '1');
elsif (clk'event and clk = '1') then
if (rst = '1') then
fSCL <= (others => '1');
fSDA <= (others => '1');
elsif (filter_cnt = 0) then
fSCL <= (fSCL(1 downto 0) & cSCL(1));
fSDA <= (fSDA(1 downto 0) & cSDA(1));
end if;
end if;
end process filter_scl_sda;
-- generate filtered SCL and SDA signals
scl_sda: process(clk, nReset)
begin
if (nReset = '0') then
sSCL <= '1';
sSDA <= '1';
dSCL <= '1';
dSDA <= '1';
elsif (clk'event and clk = '1') then
if (rst = '1') then
sSCL <= '1';
sSDA <= '1';
dSCL <= '1';
dSDA <= '1';
else
sSCL <= (fSCL(2) and fSCL(1)) or
(fSCL(2) and fSCL(0)) or
(fSCL(1) and fSCL(0));
sSDA <= (fSDA(2) and fSDA(1)) or
(fSDA(2) and fSDA(0)) or
(fSDA(1) and fSDA(0));
dSCL <= sSCL;
dSDA <= sSDA;
end if;
end if;
end process scl_sda;
-- 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, nReset)
begin
if (nReset = '0') then
sta_condition <= '0';
sto_condition <= '0';
elsif (clk'event and clk = '1') then
if (rst = '1') then
sta_condition <= '0';
sto_condition <= '0';
else
sta_condition <= (not sSDA and dSDA) and sSCL;
sto_condition <= (sSDA and not dSDA) and sSCL;
end if;
end if;
end process detect_sta_sto;
-- generate i2c-bus busy signal
gen_busy: process(clk, nReset)
begin
if (nReset = '0') then
ibusy <= '0';
elsif (clk'event and clk = '1') then
if (rst = '1') then
ibusy <= '0';
else
ibusy <= (sta_condition or ibusy) and not sto_condition;
end if;
end if;
end process gen_busy;
busy <= ibusy;
-- generate arbitration lost signal
-- aribitration lost when:
-- 1) master drives SDA high, but the i2c bus is low
-- 2) stop detected while not requested (detect during 'idle' state)
gen_al: process(clk, nReset)
begin
if (nReset = '0') then
cmd_stop <= '0';
ial <= '0';
elsif (clk'event and clk = '1') then
if (rst = '1') then
cmd_stop <= '0';
ial <= '0';
else
if (clk_en = '1') then
if (cmd = I2C_CMD_STOP) then
cmd_stop <= '1';
else
cmd_stop <= '0';
end if;
end if;
if (c_state = idle) then
ial <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not cmd_stop);
else
ial <= (sda_chk and not sSDA and isda_oen);
end if;
end if;
end if;
end process gen_al;
al <= ial;
-- generate dout signal, store dout on rising edge of SCL
gen_dout: process(clk, nReset)
begin
if (nReset = '0') then
dout <= '0';
elsif (clk'event and clk = '1') then
if (sSCL = '1' and dSCL = '0') then
dout <= sSDA;
end if;
end if;
end process gen_dout;
end block bus_status_ctrl;
-- generate statemachine
nxt_state_decoder : process (clk, nReset)
begin
if (nReset = '0') then
c_state <= idle;
cmd_ack <= '0';
iscl_oen <= '1';
isda_oen <= '1';
sda_chk <= '0';
elsif (clk'event and clk = '1') then
if (rst = '1' or ial = '1') then
c_state <= idle;
cmd_ack <= '0';
iscl_oen <= '1';
isda_oen <= '1';
sda_chk <= '0';
else
cmd_ack <= '0'; -- default no acknowledge
if (clk_en = '1') then
case (c_state) is
-- idle
when idle =>
case cmd is
when I2C_CMD_START => c_state <= start_a;
when I2C_CMD_STOP => c_state <= stop_a;
when I2C_CMD_WRITE => c_state <= wr_a;
when I2C_CMD_READ => c_state <= rd_a;
when others => c_state <= idle; -- NOP command
end case;
iscl_oen <= iscl_oen; -- keep SCL in same state
isda_oen <= isda_oen; -- keep SDA in same state
sda_chk <= '0'; -- don't check SDA
-- start
when start_a =>
c_state <= start_b;
iscl_oen <= iscl_oen; -- keep SCL in same state (for repeated start)
isda_oen <= '1'; -- set SDA high
sda_chk <= '0'; -- don't check SDA
when start_b =>
c_state <= start_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= '1'; -- keep SDA high
sda_chk <= '0'; -- don't check SDA
when start_c =>
c_state <= start_d;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '0'; -- set SDA low
sda_chk <= '0'; -- don't check SDA
when start_d =>
c_state <= start_e;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA
when start_e =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '0'; -- set SCL low
isda_oen <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA
-- stop
when stop_a =>
c_state <= stop_b;
iscl_oen <= '0'; -- keep SCL low
isda_oen <= '0'; -- set SDA low
sda_chk <= '0'; -- don't check SDA
when stop_b =>
c_state <= stop_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA
when stop_c =>
c_state <= stop_d;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '0'; -- keep SDA low
sda_chk <= '0'; -- don't check SDA
when stop_d =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '1'; -- set SDA high
sda_chk <= '0'; -- don't check SDA
-- read
when rd_a =>
c_state <= rd_b;
iscl_oen <= '0'; -- keep SCL low
isda_oen <= '1'; -- tri-state SDA
sda_chk <= '0'; -- don't check SDA
when rd_b =>
c_state <= rd_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= '1'; -- tri-state SDA
sda_chk <= '0'; -- don't check SDA
when rd_c =>
c_state <= rd_d;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= '1'; -- tri-state SDA
sda_chk <= '0'; -- don't check SDA
when rd_d =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '0'; -- set SCL low
isda_oen <= '1'; -- tri-state SDA
sda_chk <= '0'; -- don't check SDA
-- write
when wr_a =>
c_state <= wr_b;
iscl_oen <= '0'; -- keep SCL low
isda_oen <= din; -- set SDA
sda_chk <= '0'; -- don't check SDA (SCL low)
when wr_b =>
c_state <= wr_c;
iscl_oen <= '1'; -- set SCL high
isda_oen <= din; -- keep SDA
sda_chk <= '0'; -- don't check SDA yet
-- Allow some more time for SDA and SCL to settle
when wr_c =>
c_state <= wr_d;
iscl_oen <= '1'; -- keep SCL high
isda_oen <= din; -- keep SDA
sda_chk <= '1'; -- check SDA
when wr_d =>
c_state <= idle;
cmd_ack <= '1'; -- command completed
iscl_oen <= '0'; -- set SCL low
isda_oen <= din; -- keep SDA
sda_chk <= '0'; -- don't check SDA (SCL low)
when others =>
end case;
end if;
end if;
end if;
end process nxt_state_decoder;
-- assign outputs
scl_o <= '0';
scl_oen <= iscl_oen;
sda_o <= '0';
sda_oen <= isda_oen;
end architecture structural;
---------------------------------------------------------------------
---- ----
---- 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.5 2004-02-18 11:41:48 rherveille Exp $
--
-- $Date: 2004-02-18 11:41:48 $
-- $Revision: 1.5 $
-- $Author: rherveille $
-- $Locker: $
-- $State: Exp $
--
-- Change History:
-- $Log: not supported by cvs2svn $
-- Revision 1.4 2003/08/09 07:01:13 rherveille
-- Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
-- Fixed a potential bug in the byte controller's host-acknowledge generation.
--
-- Revision 1.3 2002/12/26 16:05:47 rherveille
-- Core is now a Multimaster I2C controller.
--
-- Revision 1.2 2002/11/30 22:24:37 rherveille
-- Cleaned up code
--
-- 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
------------------------------------------
--
library ieee;
use ieee.std_logic_1164.all;
--use ieee.std_logic_arith.all;
use ieee.numeric_std.all;
entity i2c_master_byte_ctrl is
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; -- command done
ack_out : out std_logic;
i2c_busy : out std_logic; -- arbitration lost
i2c_al : out std_logic; -- i2c bus busy
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
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; -- command done
busy : out std_logic; -- i2c bus busy
al : out std_logic; -- arbitration lost
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;
signal al : 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;
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal c_state : states;
begin
-- hookup bit_controller
bit_ctrl: 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,
al => al,
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
);
i2c_al <= al;
-- 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');
elsif (clk'event and clk = '1') then
if (rst = '1') then
sr <= (others => '0');
elsif (ld = '1') then
sr <= din;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd);
end if;
end if;
end process shift_register;
-- generate data-counter
data_cnt: process(clk, nReset)
begin
if (nReset = '0') then
dcnt <= (others => '0');
elsif (clk'event and clk = '1') then
if (rst = '1') then
dcnt <= (others => '0');
elsif (ld = '1') then
dcnt <= (others => '1'); -- load counter with 7
elsif (shift = '1') then
dcnt <= dcnt -1;
end if;
end if;
end process data_cnt;
cnt_done <= '1' when (dcnt = 0) else '0';
--
-- state machine
--
statemachine : block
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;
core_txd <= '0';
shift <= '0';
ld <= '0';
host_ack <= '0';
c_state <= st_idle;
ack_out <= '0';
elsif (clk'event and clk = '1') then
if (rst = '1' or al = '1') then
core_cmd <= I2C_CMD_NOP;
core_txd <= '0';
shift <= '0';
ld <= '0';
host_ack <= '0';
c_state <= st_idle;
ack_out <= '0';
else
-- initialy reset all signal
core_txd <= sr(7);
shift <= '0';
ld <= '0';
host_ack <= '0';
case c_state is
when st_idle =>
if (go = '1') then
if (start = '1') then
c_state <= st_start;
core_cmd <= I2C_CMD_START;
elsif (read = '1') then
c_state <= st_read;
core_cmd <= I2C_CMD_READ;
elsif (write = '1') then
c_state <= st_write;
core_cmd <= I2C_CMD_WRITE;
else -- stop
c_state <= st_stop;
core_cmd <= I2C_CMD_STOP;
end if;
ld <= '1';
end if;
when st_start =>
if (core_ack = '1') then
if (read = '1') then
c_state <= st_read;
core_cmd <= I2C_CMD_READ;
else
c_state <= st_write;
core_cmd <= I2C_CMD_WRITE;
end if;
ld <= '1';
end if;
when st_write =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack;
core_cmd <= I2C_CMD_READ;
else
c_state <= st_write; -- stay in same state
core_cmd <= I2C_CMD_WRITE; -- write next bit
shift <= '1';
end if;
end if;
when st_read =>
if (core_ack = '1') then
if (cnt_done = '1') then
c_state <= st_ack;
core_cmd <= I2C_CMD_WRITE;
else
c_state <= st_read; -- stay in same state
core_cmd <= I2C_CMD_READ; -- read next bit
end if;
shift <= '1';
core_txd <= ack_in;
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;
core_cmd <= I2C_CMD_STOP;
else
c_state <= st_idle;
core_cmd <= I2C_CMD_NOP;
-- generate command acknowledge signal
host_ack <= '1';
end if;
-- assign ack_out output to core_rxd (contains last received bit)
ack_out <= core_rxd;
core_txd <= '1';
else
core_txd <= ack_in;
end if;
when st_stop =>
if (core_ack = '1') then
c_state <= st_idle;
core_cmd <= I2C_CMD_NOP;
-- generate command acknowledge signal
host_ack <= '1';
end if;
when others => -- illegal states
c_state <= st_idle;
core_cmd <= I2C_CMD_NOP;
report ("Byte controller entered illegal state.");
end case;
end if;
end if;
end process nxt_state_decoder;
end block statemachine;
end architecture structural;
vlib work
vcom -explicit -93 "../../modules/genrams/genram_pkg.vhd"
vcom -explicit -93 "../../modules/common/gencores_pkg.vhd"
vcom -explicit -93 "../../modules/wishbone/wishbone_pkg.vhd"
vcom -explicit -93 "../../modules/common/gc_sync_ffs.vhd"
vcom -explicit -93 "../../modules/common/gc_glitch_filt.vhd"
vcom -explicit -93 "../../modules/common/gc_fsm_watchdog.vhd"
vcom -explicit -93 "../../modules/common/gc_i2c_slave.vhd"
vcom -explicit -93 "../../modules/wishbone/wb_i2c_bridge/wb_i2c_bridge.vhd"
vcom -explicit -93 "i2c_master_bit_ctrl.vhd"
vcom -explicit -93 "i2c_master_byte_ctrl.vhd"
vcom -explicit -93 "i2c_bus_model.vhd"
vcom -explicit -93 "tb_wb_i2c_bridge.vhd"
#vcom -explicit -93 "tb_gc_i2c_slave.vhd"
vsim -t 1ps -voptargs="+acc" -lib work work.tb_wb_i2c_bridge
radix -hexadecimal
#add wave *
do wave.do
#do busmdl.do
#do wave-i2cs.do
run 20 ms
wave zoomfull
--==============================================================================
-- CERN (BE-CO-HT)
-- Testbench for old repeater design
--==============================================================================
--
-- author: Theodor Stana (t.stana@cern.ch)
--
-- date of creation: 2013-02-28
--
-- version: 1.0
--
-- description:
--
-- dependencies:
--
-- references:
--
--==============================================================================
-- GNU LESSER GENERAL PUBLIC LICENSE
--==============================================================================
-- This source file is free software; you can redistribute it and/or modify it
-- under the terms of the GNU Lesser General Public License as published by the
-- Free Software Foundation; either version 2.1 of the License, or (at your
-- option) any later version. This source is distributed in the hope that it
-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--==============================================================================
-- last changes:
-- 2013-02-28 Theodor Stana t.stana@cern.ch File created
--==============================================================================
-- TODO: -
--==============================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
entity tb_gc_i2c_slave is
end entity tb_gc_i2c_slave;
architecture behav of tb_gc_i2c_slave is
--============================================================================
-- Type declarations
--============================================================================
type t_state_mst is
(
MST_IDLE,
MST_W1, MST_W1_ACK,
MST_W2, MST_W2_ACK,
MST_W3, MST_W3_ACK,
MST_R1, MST_R1_ACK,
MST_R2,
MST_R3,
MST_SUCCESS,
MST_ERR
);
type t_state_slv is
(
SLV_IDLE,
SLV_DETOP,
SLV_R1, SLV_R1_ACK,
SLV_R2, SLV_R2_ACK,
SLV_W1, SLV_W1_ACK,
SLV_W2, SLV_W2_ACK
);
--============================================================================
-- Constant declarations
--============================================================================
constant c_clk_per : time := 50 ns;
constant c_reset_width : time := 31 ns;
--============================================================================
-- Component declarations
--============================================================================
-- I2C master
component i2c_master_byte_ctrl is
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; -- command done
ack_out : out std_logic;
i2c_busy : out std_logic; -- arbitration lost
i2c_al : out std_logic; -- i2c bus busy
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;
--============================================================================
-- Signal declarations
--============================================================================
signal clk, rst_n : std_logic := '0';
signal rst : std_logic;
signal scl_to_slv : std_logic;
signal scl_fr_slv : std_logic;
signal scl_en_slv : std_logic;
signal sda_to_slv : std_logic;
signal sda_fr_slv : std_logic;
signal sda_en_slv : std_logic;
signal slv_ack : std_logic;
signal slv_op : std_logic;
signal scl_to_mst : std_logic;
signal scl_fr_mst : std_logic;
signal scl_en_mst : std_logic;
signal sda_to_mst : std_logic;
signal sda_fr_mst : std_logic;
signal sda_en_mst : std_logic;
signal addr : std_logic_vector(6 downto 0);
signal txb, rxb : std_logic_vector(7 downto 0);
signal rcvd : std_logic_vector(7 downto 0);
signal slv_r_done_p : std_logic;
signal slv_w_done_p : std_logic;
signal slv_addr_good_p : std_logic;
signal slv_sta_p : std_logic;
signal slv_sto_p : std_logic;
signal mst_sta : std_logic;
signal mst_sto : std_logic;
signal mst_rd : std_logic;
signal mst_wr : std_logic;
signal mst_ack : std_logic;
signal mst_dat_in : std_logic_vector(7 downto 0);
signal mst_dat_out : std_logic_vector(7 downto 0);
signal mst_cmd_ack : std_logic;
signal ack_fr_slv : std_logic;
signal state_mst : t_state_mst;
signal state_slv : t_state_slv;
signal cnt : unsigned(2 downto 0);
signal once : boolean;
signal tmp : std_logic_vector(7 downto 0);
--==============================================================================
-- architecture begin
--==============================================================================
begin
-- CLOCK GENERATION
p_clk: process
begin
clk <= not clk;
wait for c_clk_per/2;
end process p_clk;
-- RESET GENERATION
rst <= not rst_n;
p_rst_n: process
begin
rst_n <= '0';
wait for c_reset_width;
rst_n <= '1';
wait;
end process p_rst_n;
-- DUT INSTANTIATION
DUT: gc_i2c_slave
port map
(
clk_i => clk,
rst_n_i => rst_n,
scl_i => scl_to_slv,
scl_o => scl_fr_slv,
scl_en_o => scl_en_slv,
sda_i => sda_to_slv,
sda_o => sda_fr_slv,
sda_en_o => sda_en_slv,
addr_i => addr,
ack_i => slv_ack,
tx_byte_i => txb,
rx_byte_o => rxb,
sta_p_o => slv_sta_p,
sto_p_o => slv_sto_p,
addr_good_p_o => slv_addr_good_p,
r_done_p_o => slv_r_done_p,
w_done_p_o => slv_w_done_p,
op_o => slv_op
);
scl_to_slv <= scl_fr_mst when scl_en_mst = '0' else
scl_fr_slv when scl_en_slv = '1' else
'1';
sda_to_slv <= sda_fr_slv when sda_en_slv = '1' else
sda_fr_mst when sda_en_mst = '0' else
'1';
-- MASTER INSTANTIATION
cmp_master: i2c_master_byte_ctrl
port map
(
clk => clk,
rst => rst,
nReset => rst_n,
ena => '1',
clk_cnt => x"00FA",
-- input signals
start => mst_sta,
stop => mst_sto,
read => mst_rd,
write => mst_wr,
ack_in => mst_ack,
din => mst_dat_in,
-- output signals
cmd_ack => mst_cmd_ack,
ack_out => ack_fr_slv,
i2c_busy => open,
i2c_al => open,
dout => mst_dat_out,
-- i2c lines
scl_i => scl_to_mst,
scl_o => scl_fr_mst,
scl_oen => scl_en_mst,
sda_i => sda_to_mst,
sda_o => sda_fr_mst,
sda_oen => sda_en_mst
);
-- BUS MODEL
scl_to_mst <= scl_fr_mst when scl_en_mst = '0' else
scl_fr_slv when scl_en_slv = '1' else
'1';
sda_to_mst <= sda_fr_slv when sda_en_slv = '1' else
sda_fr_mst when sda_en_mst = '0' else
'1';
-- STIMULI
addr <= "1011110";
-- I2C SLAVE FSM
p_slv_fsm: process (clk) is
begin
if rising_edge(clk) then
if (rst_n = '0') then
state_slv <= SLV_IDLE;
slv_ack <= '0';
txb <= (others => '0');
else
case state_slv is
-- IDLE, wait for slave to do something
when SLV_IDLE =>
if (slv_addr_good_p = '1') then
slv_ack <= '1';
state_slv <= SLV_DETOP;
end if;
-- master sent something to our slave, see what
-- we have to do...
when SLV_DETOP =>
if (slv_op = '0') then
state_slv <= SLV_R1;
else
state_slv <= SLV_W1;
end if;
-- SLV_R1
-- when done = '1', the slave goes into
-- WAIT_ACK state, so we must provide ACK.
when SLV_R1 =>
if (slv_r_done_p = '1') then
state_slv <= SLV_R1_ACK;
rcvd <= rxb;
end if;
-- tell the slave to ACK, go back to IDLE
when SLV_R1_ACK =>
slv_ack <= '1';
state_slv <= SLV_R2;
-- reading second byte from master, wait until
-- done = '1', and go to R2_ACK state
when SLV_R2 =>
if (slv_r_done_p = '1') then
state_slv <= SLV_R2_ACK;
rcvd <= rxb;
end if;
-- R2_ACK
when SLV_R2_ACK =>
slv_ack <= '1';
state_slv <= SLV_IDLE;
-- loopback received byte
when SLV_W1 =>
txb <= rcvd;
if (slv_w_done_p = '1') then
state_slv <= SLV_W2;
end if;
-- loopback received byte
when SLV_W2 =>
txb <= rcvd;
if (slv_w_done_p = '1') then
state_slv <= SLV_IDLE;
end if;
when others =>
state_slv <= SLV_IDLE;
end case;
end if;
end if;
end process p_slv_fsm;
-- I2C MASTER FSM
tmp <= mst_dat_out;
p_mst_fsm: process (clk) is
begin
if rising_edge(clk) then
if (rst_n = '0') then
state_mst <= MST_IDLE;
mst_sta <= '0';
mst_wr <= '0';
mst_sto <= '0';
mst_rd <= '0';
mst_dat_in <= (others => '0');
mst_ack <= '1';
cnt <= (others => '0');
once <= true;
else
case state_mst is
when MST_IDLE =>
state_mst <= MST_W1;
when MST_W1 =>
mst_sta <= '1';
mst_wr <= '1';
mst_dat_in <= addr & '0';
if (mst_cmd_ack = '1') then
mst_sta <= '0';
mst_wr <= '0';
state_mst <= MST_W1_ACK;
end if;
when MST_W1_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state_mst <= MST_W2;
else
state_mst <= MST_ERR;
end if;
end if;
when MST_W2 =>
mst_wr <= '1';
mst_dat_in <= x"33";
if (mst_cmd_ack = '1') then
mst_wr <= '0';
state_mst <= MST_W2_ACK;
end if;
when MST_W2_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state_mst <= MST_W3;
else
state_mst <= MST_ERR;
end if;
end if;
when MST_W3 =>
mst_wr <= '1';
mst_dat_in <= x"12";
if (mst_cmd_ack = '1') then
mst_wr <= '0';
mst_sto <= '0';
state_mst <= MST_W3_ACK;
end if;
when MST_W3_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state_mst <= MST_R1;
else
state_mst <= MST_ERR;
end if;
end if;
when MST_R1 =>
mst_sta <= '1';
mst_wr <= '1';
mst_dat_in <= addr & '1';
if (mst_cmd_ack = '1') then
mst_sta <= '0';
mst_wr <= '0';
state_mst <= MST_R1_ACK;
end if;
when MST_R1_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state_mst <= MST_R2;
else
state_mst <= MST_ERR;
end if;
end if;
when MST_R2 =>
mst_rd <= '1';
--mst_sto <= '1';
mst_ack <= '0';
if (mst_cmd_ack = '1') then
mst_rd <= '0';
mst_sto <= '0';
if (tmp = x"12") then
state_mst <= MST_R3;
else
state_mst <= MST_ERR;
end if;
end if;
when MST_R3 =>
mst_rd <= '1';
mst_sto <= '1';
mst_ack <= '0';
if (mst_cmd_ack = '1') then
mst_rd <= '0';
mst_sto <= '0';
if (tmp = x"12") then
state_mst <= MST_SUCCESS;
else
state_mst <= MST_ERR;
end if;
end if;
when MST_SUCCESS =>
if (once) then
report("Success!");
once <= false;
end if;
when MST_ERR =>
if (once) then
report("Error!");
once <= false;
end if;
when others =>
state_mst <= MST_ERR;
end case;
end if;
end if;
end process p_mst_fsm;
end architecture behav;
--==============================================================================
-- architecture end
--==============================================================================
--==============================================================================
-- CERN (BE-CO-HT)
-- Testbench for old repeater design
--==============================================================================
--
-- author: Theodor Stana (t.stana@cern.ch)
--
-- date of creation: 2013-02-28
--
-- version: 1.0
--
-- description:
--
-- dependencies:
--
-- references:
--
--==============================================================================
-- GNU LESSER GENERAL PUBLIC LICENSE
--==============================================================================
-- This source file is free software; you can redistribute it and/or modify it
-- under the terms of the GNU Lesser General Public License as published by the
-- Free Software Foundation; either version 2.1 of the License, or (at your
-- option) any later version. This source is distributed in the hope that it
-- will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-- See the GNU Lesser General Public License for more details. You should have
-- received a copy of the GNU Lesser General Public License along with this
-- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
--==============================================================================
-- last changes:
-- 2013-02-28 Theodor Stana t.stana@cern.ch File created
--==============================================================================
-- TODO: -
--==============================================================================
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_pkg.all;
entity tb_wb_i2c_bridge is
end entity tb_wb_i2c_bridge;
architecture behav of tb_wb_i2c_bridge is
--============================================================================
-- Type declarations
--============================================================================
type t_state is
(
IDLE,
I2C_ADDR, I2C_ADDR_ACK,
WB_ADDR_B0, WB_ADDR_B0_ACK,
WB_ADDR_B1, WB_ADDR_B1_ACK,
ST_OP,
RD_RESTART, RD_RESTART_ACK,
RD, RD_ACK,
WR, WR_ACK,
STO,
SUCCESS,
ERR
);
type t_reg is array(0 to 3) of std_logic_vector(31 downto 0);
--============================================================================
-- Constant declarations
--============================================================================
constant c_clk_per : time := 50 ns;
constant c_reset_width : time := 112 ns;
constant c_nr_masters : positive := 1;
constant c_nr_slaves : positive := 2;
constant c_sval : unsigned := x"424c4f24";
constant c_eval : unsigned := c_sval + x"A";
--============================================================================
-- Component declarations
--============================================================================
-- I2C master
component i2c_master_byte_ctrl is
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; -- command done
ack_out : out std_logic;
i2c_busy : out std_logic; -- arbitration lost
i2c_al : out std_logic; -- i2c bus busy
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;
-- I2C bus model
component i2c_bus_model is
generic
(
g_nr_masters : positive := 1;
g_nr_slaves : positive := 1
);
port
(
-- Input ports from master lines
mscl_i : in std_logic_vector(g_nr_masters-1 downto 0);
msda_i : in std_logic_vector(g_nr_masters-1 downto 0);
-- Input ports from slave lines
sscl_i : in std_logic_vector(g_nr_slaves-1 downto 0);
ssda_i : in std_logic_vector(g_nr_slaves-1 downto 0);
-- SCL and SDA line outputs
scl_o : out std_logic;
sda_o : out std_logic
);
end component i2c_bus_model;
--============================================================================
-- Signal declarations
--============================================================================
-- Clock, reset signals
signal clk, rst_n : std_logic := '0';
signal rst : std_logic;
-- Slave-side I2C signals
signal scl_to_slv : std_logic;
signal scl_fr_slv : std_logic;
signal scl_en_slv : std_logic;
signal sda_to_slv : std_logic;
signal sda_fr_slv : std_logic;
signal sda_en_slv : std_logic;
signal scl_to_slv_1 : std_logic;
signal scl_fr_slv_1 : std_logic;
signal scl_en_slv_1 : std_logic;
signal sda_to_slv_1 : std_logic;
signal sda_fr_slv_1 : std_logic;
signal sda_en_slv_1 : std_logic;
-- SCL and SDA signals from slaves
signal sscl, ssda : std_logic_vector(c_nr_slaves-1 downto 0);
-- Master-side I2C signals
signal scl_to_mst : std_logic;
signal scl_fr_mst : std_logic;
signal scl_en_mst : std_logic;
signal sda_to_mst : std_logic;
signal sda_fr_mst : std_logic;
signal sda_en_mst : std_logic;
-- SCL and SDA signals from master
signal mscl, msda : std_logic_vector(c_nr_masters-1 downto 0);
-- I2C bus signals
signal scl, sda : std_logic;
-- I2C address, done
signal slv_addr : std_logic_vector(6 downto 0);
signal i2c_tip : std_logic;
signal i2c_err : std_logic;
signal i2c_tip_1 : std_logic;
signal i2c_err_1 : std_logic;
-- I2C master signals
signal mst_sta : std_logic;
signal mst_sto : std_logic;
signal mst_rd : std_logic;
signal mst_wr : std_logic;
signal mst_ack : std_logic;
signal mst_dat_in : std_logic_vector(7 downto 0);
signal mst_dat_out : std_logic_vector(7 downto 0);
signal mst_cmd_ack : std_logic;
signal ack_fr_slv : std_logic;
-- Master FSM signals
signal state : t_state;
signal mst_fsm_op : std_logic;
signal mst_fsm_start : std_logic;
signal stim_cnt : unsigned(31 downto 0);
-- misc signals
signal cnt : unsigned(2 downto 0);
signal once : boolean;
signal byte_cnt : unsigned(1 downto 0);
signal rcvd : std_logic_vector(31 downto 0);
signal read4 : std_logic;
signal send : std_logic_vector(31 downto 0);
signal wrote : std_logic;
signal adr : std_logic_vector(31 downto 0);
-- Wishbone signals
signal wb_stb : std_logic;
signal wb_cyc : std_logic;
signal wb_sel : std_logic_vector(3 downto 0);
signal wb_we : std_logic;
signal wb_dat_m2s : std_logic_vector(31 downto 0);
signal wb_dat_s2m : std_logic_vector(31 downto 0);
signal wb_adr : std_logic_vector(31 downto 0);
signal wb_ack : std_logic;
signal reg : t_reg;
signal wb_stb_1 : std_logic;
signal wb_cyc_1 : std_logic;
signal wb_sel_1 : std_logic_vector(3 downto 0);
signal wb_we_1 : std_logic;
signal wb_dat_m2s_1 : std_logic_vector(31 downto 0);
signal wb_dat_s2m_1 : std_logic_vector(31 downto 0);
signal wb_adr_1 : std_logic_vector(31 downto 0);
signal wb_ack_1 : std_logic;
signal reg_1 : t_reg;
--==============================================================================
-- architecture begin
--==============================================================================
begin
--============================================================================
-- Reset and clock generation
--============================================================================
-- clock
p_clk: process
begin
clk <= not clk;
wait for c_clk_per/2;
end process p_clk;
-- reset
rst <= not rst_n;
p_rst_n: process
begin
rst_n <= '0';
wait for c_reset_width;
rst_n <= '1';
wait;
end process p_rst_n;
--============================================================================
-- DUT instantiation
--============================================================================
------------------------------------------------------------------------------
-- SLAVE 1
------------------------------------------------------------------------------
-- First, the instantiation itself
DUT : wb_i2c_bridge
port map
(
-- Clock, reset
clk_i => clk,
rst_n_i => rst_n,
-- I2C lines
scl_i => scl,
scl_o => scl_fr_slv,
scl_en_o => scl_en_slv,
sda_i => sda,
sda_o => sda_fr_slv,
sda_en_o => sda_en_slv,
-- I2C address and status
i2c_addr_i => "1011110",
tip_o => i2c_tip,
err_p_o => i2c_err,
-- Wishbone master signals
wbm_stb_o => wb_stb,
wbm_cyc_o => wb_cyc,
wbm_sel_o => wb_sel,
wbm_we_o => wb_we,
wbm_dat_i => wb_dat_s2m,
wbm_dat_o => wb_dat_m2s,
wbm_adr_o => wb_adr,
wbm_ack_i => wb_ack,
wbm_rty_i => '0',
wbm_err_i => '0'
);
-- Then, the tri-state buffer for the I2C lines
sscl(0) <= scl_fr_slv when (scl_en_slv = '1') else
'1';
ssda(0) <= sda_fr_slv when (sda_en_slv = '1') else
'1';
------------------------------------------------------------------------------
-- SLAVE 2
------------------------------------------------------------------------------
-- First, the instantiation itself
DUT_1 : wb_i2c_bridge
port map
(
-- Clock, reset
clk_i => clk,
rst_n_i => rst_n,
-- I2C lines
scl_i => scl,
scl_o => scl_fr_slv_1,
scl_en_o => scl_en_slv_1,
sda_i => sda,
sda_o => sda_fr_slv_1,
sda_en_o => sda_en_slv_1,
-- I2C address and status
i2c_addr_i => "1011101",
tip_o => i2c_tip_1,
err_p_o => i2c_err_1,
-- Wishbone master signals
wbm_stb_o => wb_stb_1,
wbm_cyc_o => wb_cyc_1,
wbm_sel_o => wb_sel_1,
wbm_we_o => wb_we_1,
wbm_dat_i => wb_dat_s2m_1,
wbm_dat_o => wb_dat_m2s_1,
wbm_adr_o => wb_adr_1,
wbm_ack_i => wb_ack_1,
wbm_rty_i => '0',
wbm_err_i => '0'
);
-- Then, the tri-state buffer for the I2C lines
sscl(1) <= scl_fr_slv_1 when (scl_en_slv_1 = '1') else
'1';
ssda(1) <= sda_fr_slv_1 when (sda_en_slv_1 = '1') else
'1';
--============================================================================
-- Master instantiation
--============================================================================
-- First, the component instantiation
cmp_master: i2c_master_byte_ctrl
port map
(
clk => clk,
rst => rst,
nReset => rst_n,
ena => '1',
clk_cnt => x"0027",
-- input signals
start => mst_sta,
stop => mst_sto,
read => mst_rd,
write => mst_wr,
ack_in => mst_ack,
din => mst_dat_in,
-- output signals
cmd_ack => mst_cmd_ack,
ack_out => ack_fr_slv,
i2c_busy => open,
i2c_al => open,
dout => mst_dat_out,
-- i2c lines
scl_i => scl,
scl_o => scl_fr_mst,
scl_oen => scl_en_mst,
sda_i => sda,
sda_o => sda_fr_mst,
sda_oen => sda_en_mst
);
-- Then, the tri-state buffers on the line
mscl(0) <= scl_fr_mst when (scl_en_mst = '0') else
'1';
msda(0) <= sda_fr_mst when (sda_en_mst = '0') else
'1';
--============================================================================
-- Bus model instantiation and connection to master and slaves
--============================================================================
cmp_i2c_bus : i2c_bus_model
generic map
(
g_nr_masters => c_nr_masters,
g_nr_slaves => c_nr_slaves
)
port map
(
mscl_i => mscl,
msda_i => msda,
sscl_i => sscl,
ssda_i => ssda,
scl_o => scl,
sda_o => sda
);
--============================================================================
-- I2C Master FSM
--============================================================================
-- This FSM controls the signals to the master component to implement the I2C
-- protocol defined together with ELMA. The FSM is controlled by the
-- stimuli process below
p_mst_fsm : process (clk) is
begin
if rising_edge(clk) then
if (rst_n = '0') then
state <= IDLE;
mst_sta <= '0';
mst_wr <= '0';
mst_sto <= '0';
mst_rd <= '0';
mst_dat_in <= (others => '0');
mst_ack <= '0';
cnt <= (others => '0');
once <= true;
byte_cnt <= (others => '0');
rcvd <= (others => '0');
wrote <= '0';
send <= (others => '0');
else
case state is
when IDLE =>
if (mst_fsm_start = '1') then
state <= I2C_ADDR;
send <= std_logic_vector(stim_cnt);
end if;
when I2C_ADDR =>
mst_sta <= '1';
mst_wr <= '1';
mst_dat_in <= slv_addr & '0';
if (mst_cmd_ack = '1') then
mst_sta <= '0';
mst_wr <= '0';
state <= I2C_ADDR_ACK;
end if;
when I2C_ADDR_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state <= WB_ADDR_B0;
else
state <= ERR;
end if;
end if;
when WB_ADDR_B0 =>
mst_wr <= '1';
mst_dat_in <= adr(15 downto 8);
if (mst_cmd_ack = '1') then
mst_wr <= '0';
state <= WB_ADDR_B0_ACK;
end if;
when WB_ADDR_B0_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state <= WB_ADDR_B1;
else
state <= ERR;
end if;
end if;
when WB_ADDR_B1 =>
mst_wr <= '1';
mst_dat_in <= adr(7 downto 0);
if (mst_cmd_ack = '1') then
mst_wr <= '0';
state <= WB_ADDR_B1_ACK;
end if;
when WB_ADDR_B1_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state <= ST_OP;
else
state <= ERR;
end if;
end if;
when ST_OP =>
if (mst_fsm_op = '1') then
state <= RD_RESTART;
else
state <= WR;
end if;
when RD_RESTART =>
mst_wr <= '1';
mst_dat_in <= slv_addr & '1';
mst_sta <= '1';
if (mst_cmd_ack = '1') then
mst_sta <= '0';
mst_wr <= '0';
state <= RD_RESTART_ACK;
end if;
when RD_RESTART_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
state <= RD;
else
state <= ERR;
end if;
end if;
when RD =>
mst_rd <= '1';
mst_ack <= '0';
if (byte_cnt = 3) then
mst_ack <= '1';
end if;
if (mst_cmd_ack = '1') then
mst_rd <= '0';
byte_cnt <= byte_cnt + 1;
rcvd <= mst_dat_out & rcvd(31 downto 8);
mst_ack <= '0';
state <= RD;
if (byte_cnt = 3) then
state <= STO;
end if;
end if;
when RD_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
byte_cnt <= byte_cnt + 1;
rcvd <= mst_dat_out & rcvd(31 downto 8);
mst_ack <= '0';
state <= RD;
if (byte_cnt = 3) then
state <= STO;
end if;
end if;
when WR =>
mst_wr <= '1';
mst_dat_in <= send(7 downto 0);
if (mst_cmd_ack = '1') then
mst_wr <= '0';
state <= WR_ACK;
end if;
when WR_ACK =>
cnt <= cnt + 1;
if (cnt = 7) then
if (ack_fr_slv = '0') then
byte_cnt <= byte_cnt + 1;
send <= x"00" & send(31 downto 8);
state <= WR;
if (byte_cnt = 3) then
state <= STO;
end if;
else
state <= ERR;
end if;
end if;
when STO =>
mst_sto <= '1';
if (mst_cmd_ack = '1') then
mst_sto <= '0';
state <= IDLE;
end if;
when ERR =>
if (once) then
report("Error!");
once <= false;
end if;
when others =>
state <= ERR;
end case;
end if;
end if;
end process p_mst_fsm;
--============================================================================
-- Wishbone slaves
--============================================================================
-- First slave
p_wb_slv: process (clk) is
begin
if rising_edge(clk) then
if (rst_n = '0') then
reg <= (
x"00000000",
x"00000000",
x"00000000",
x"00000000"
);
wb_ack <= '0';
wb_dat_s2m <= (others => '0');
else
wb_ack <= '0';
if (wb_cyc = '1') and (wb_stb = '1') then
wb_ack <= '1';
wb_dat_s2m <= reg(to_integer(unsigned(wb_adr)));
if (wb_we = '1') then
reg(to_integer(unsigned(wb_adr))) <= wb_dat_m2s;
end if;
end if;
end if;
end if;
end process p_wb_slv;
-- Second slave
p_wb_slv_1: process (clk) is
begin
if rising_edge(clk) then
if (rst_n = '0') then
reg_1 <= (
x"00000000",
x"00000000",
x"00000000",
x"00000000"
);
wb_ack_1 <= '0';
wb_dat_s2m_1 <= (others => '0');
else
wb_ack_1 <= '0';
if (wb_cyc_1 = '1') and (wb_stb_1 = '1') then
wb_ack_1 <= '1';
wb_dat_s2m_1 <= reg_1(to_integer(unsigned(wb_adr_1)));
if (wb_we_1 = '1') then
reg_1(to_integer(unsigned(wb_adr_1))) <= wb_dat_m2s_1;
end if;
end if;
end if;
end if;
end process p_wb_slv_1;
--============================================================================
-- A stimuli process to control the I2C FSM
--============================================================================
p_stim : process (rst_n, state)
begin
if (rst_n = '0') then
stim_cnt <= c_sval; --(others => '0');
mst_fsm_start <= '0';
mst_fsm_op <= '0';
slv_addr <= "1011110";
adr <= (others => '0');
elsif (state = IDLE) then
stim_cnt <= stim_cnt + 1;
mst_fsm_start <= '1';
adr(1 downto 0) <= std_logic_vector(stim_cnt(1 downto 0));
if (stim_cnt(0) = '1') then
slv_addr <= "1011110";
else
slv_addr <= "1011101";
end if;
case to_integer(stim_cnt) is
when to_integer(c_sval) to to_integer(c_eval) =>
mst_fsm_op <= '0';
when others =>
mst_fsm_op <= '1';
end case;
end if;
end process p_stim;
end architecture behav;
--==============================================================================
-- architecture end
--==============================================================================
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /tb_gc_i2c_slave/clk
add wave -noupdate /tb_gc_i2c_slave/state_mst
add wave -noupdate /tb_gc_i2c_slave/state_slv
add wave -noupdate /tb_gc_i2c_slave/scl_to_slv
add wave -noupdate /tb_gc_i2c_slave/sda_to_slv
add wave -noupdate /tb_gc_i2c_slave/sda_fr_slv
add wave -noupdate /tb_gc_i2c_slave/scl_fr_mst
add wave -noupdate /tb_gc_i2c_slave/sda_to_mst
add wave -noupdate /tb_gc_i2c_slave/sda_fr_mst
add wave -noupdate -divider BUS
add wave -noupdate /tb_gc_i2c_slave/scl_to_slv
add wave -noupdate /tb_gc_i2c_slave/scl_fr_slv
add wave -noupdate /tb_gc_i2c_slave/sda_to_slv
add wave -noupdate /tb_gc_i2c_slave/sda_fr_slv
add wave -noupdate /tb_gc_i2c_slave/scl_to_mst
add wave -noupdate /tb_gc_i2c_slave/scl_fr_mst
add wave -noupdate /tb_gc_i2c_slave/sda_to_mst
add wave -noupdate /tb_gc_i2c_slave/sda_fr_mst
add wave -noupdate -divider loopback
add wave -noupdate /tb_gc_i2c_slave/txb
add wave -noupdate /tb_gc_i2c_slave/rxb
add wave -noupdate /tb_gc_i2c_slave/rcvd
add wave -noupdate /tb_gc_i2c_slave/tmp
add wave -noupdate -divider slave
add wave -noupdate /tb_gc_i2c_slave/DUT/scl_i
add wave -noupdate /tb_gc_i2c_slave/DUT/sda_i
add wave -noupdate /tb_gc_i2c_slave/DUT/tick_p
add wave -noupdate /tb_gc_i2c_slave/DUT/tick_en
add wave -noupdate /tb_gc_i2c_slave/DUT/tick_cnt
add wave -noupdate /tb_gc_i2c_slave/DUT/ack_i
add wave -noupdate /tb_gc_i2c_slave/DUT/sda_en_o
add wave -noupdate /tb_gc_i2c_slave/DUT/tx_byte_i
add wave -noupdate /tb_gc_i2c_slave/DUT/rx_byte_o
add wave -noupdate /tb_gc_i2c_slave/DUT/state
add wave -noupdate /tb_gc_i2c_slave/DUT/txsr
add wave -noupdate /tb_gc_i2c_slave/DUT/rxsr
add wave -noupdate /tb_gc_i2c_slave/DUT/bit_cnt
add wave -noupdate /tb_gc_i2c_slave/cnt
add wave -noupdate /tb_gc_i2c_slave/DUT/op_o
add wave -noupdate /tb_gc_i2c_slave/DUT/sta_p_o
add wave -noupdate /tb_gc_i2c_slave/DUT/sto_p_o
add wave -noupdate /tb_gc_i2c_slave/DUT/addr_good_p_o
add wave -noupdate /tb_gc_i2c_slave/DUT/r_done_p_o
add wave -noupdate /tb_gc_i2c_slave/DUT/w_done_p_o
add wave -noupdate /tb_gc_i2c_slave/DUT/op_o
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 1} {2555133080 ps} 0}
configure wave -namecolwidth 400
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ps} {4200 us}
onerror {resume}
quietly WaveActivateNextPane {} 0
add wave -noupdate /tb_wb_i2c_bridge/clk
add wave -noupdate /tb_wb_i2c_bridge/scl
add wave -noupdate /tb_wb_i2c_bridge/sscl
add wave -noupdate /tb_wb_i2c_bridge/sda
add wave -noupdate -expand /tb_wb_i2c_bridge/ssda
add wave -noupdate /tb_wb_i2c_bridge/state
add wave -noupdate /tb_wb_i2c_bridge/stim_cnt
add wave -noupdate /tb_wb_i2c_bridge/send
add wave -noupdate -expand /tb_wb_i2c_bridge/reg
add wave -noupdate -expand /tb_wb_i2c_bridge/reg_1
add wave -noupdate /tb_wb_i2c_bridge/rcvd
add wave -noupdate /tb_wb_i2c_bridge/DUT/cmp_i2c_slave/state
add wave -noupdate /tb_wb_i2c_bridge/DUT_1/cmp_i2c_slave/state
TreeUpdate [SetDefaultTree]
WaveRestoreCursors {{Cursor 2} {728700000 ps} 0}
configure wave -namecolwidth 400
configure wave -valuecolwidth 100
configure wave -justifyvalue left
configure wave -signalnamewidth 0
configure wave -snapdistance 10
configure wave -datasetprefix 0
configure wave -rowmargin 4
configure wave -childrowmargin 2
configure wave -gridoffset 0
configure wave -gridperiod 1
configure wave -griddelta 40
configure wave -timeline 0
configure wave -timelineunits ns
update
WaveRestoreZoom {0 ps} {1640625 ns}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment