Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Questions on Using Spartan 3E

Status
Not open for further replies.

daisyzari

Junior Member level 3
Joined
Feb 8, 2011
Messages
29
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,907
Is it possible to implement an I2C Master in the Spartan 3E starter kit

Also can someone suggest a vhdl code for an I2C Master mode

thanks

*** bless:)
 

Check out xilinx XAPP385. That also comes with verilog and vhdl code for an i2c core.
 

    V

    Points: 2
    Helpful Answer Positive Rating
I would just like to ask sir/ma'am what do you think is the probable reason why is it that no waveform can be seen when the code is simulated?
 

Code + screenshot of simulation?

Quick guess: simulation duration in ISIM is 1000 ns by default, which could be too short to see anything useful.
 

Hi this is the code and the snapshot. I've tried adjusting the simulation duration but still, no waveform can be seen..**broken link removed**
--
--
-- State machine for reading data from Dallas 1621
--
-- Testsystem for i2c controller
--
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

use work.i2c.all;

entity DS1621_interface is
port (
clk : in std_logic;
nReset : in std_logic;

Dout : out std_logic_vector(7 downto 0); -- data read from ds1621

error : out std_logic; -- no correct ack received

SCL : inout std_logic;
SDA : inout std_logic
);
end entity DS1621_interface;

architecture structural of DS1621_interface is
constant SLAVE_ADDR : std_logic_vector(6 downto 0) := "1001000";
constant CLK_CNT : unsigned(7 downto 0) := conv_unsigned(20, 8);

signal cmd_ack : std_logic;
signal D : std_logic_vector(7 downto 0);
signal lack, store_dout : std_logic;

signal start, read, write, ack, stop : std_logic;
signal i2c_dout : std_logic_vector(7 downto 0);

begin
-- hookup I2C controller
u1: simple_i2c port map (clk => clk, ena => '1', clk_cnt => clk_cnt, nReset => nReset,
read => read, write => write, start => start, stop => stop, ack_in => ack, cmd_ack => cmd_ack,
Din => D, Dout => i2c_dout, ack_out => lack, SCL => SCL, SDA => SDA);

init_statemachine : block
type states is (i1, i2, i3, i4, i5, t1, t2, t3, t4, t5);
signal state : states;
begin
nxt_state_decoder: process(clk, nReset, state)
variable nxt_state : states;
variable iD : std_logic_vector(7 downto 0);
variable ierr : std_logic;
variable istart, iread, iwrite, iack, istop : std_logic;
variable istore_dout : std_logic;
begin
nxt_state := state;
ierr := '0';
istore_dout := '0';

istart := start;
iread := read;
iwrite := write;
iack := ack;
istop := stop;
iD := D;

case (state) is
-- init DS1621
-- 1) send start condition
-- 2) send slave address + write
-- 3) check ack
-- 4) send "access config" command (0xAC)
-- 5) check ack
-- 6) send config register data (0x00)
-- 7) check ack
-- 8) send stop condition
-- 9) send start condition
-- 10) send slave address + write
-- 11) check ack
-- 12) send "start conversion" command (0xEE)
-- 13) check ack
-- 14) send stop condition

when i1 => -- send start condition, sent slave address + write
nxt_state := i2;
istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')

when i2 => -- send "access config" command
if (cmd_ack = '1') then
nxt_state := i3;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := x"AC";
end if;

when i3 => -- send config register data, sent stop condition
if (cmd_ack = '1') then
nxt_state := i4;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '1';
iD := x"00";
end if;

when i4 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state := i5;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
end if;

when i5 => -- send "start conversion" command + stop condition
if (cmd_ack = '1') then
nxt_state := t1;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '1';
iD := x"EE";
end if;
-- read temperature
-- 1) sent start condition
-- 2) sent slave address + write
-- 3) check ack
-- 4) sent "read temperature" command (0xAA)
-- 5) check ack
-- 6) sent start condition
-- 7) sent slave address + read
-- 8) check ack
-- 9) read msb
-- 10) send ack
-- 11) read lsb
-- 12) send nack
-- 13) send stop condition

when t1 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state := t2;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
end if;

when t2 => -- send read temperature command
if (cmd_ack = '1') then
nxt_state := t3;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := x"AA";
end if;

when t3 => -- send (repeated) start condition, send slave address + read
if (cmd_ack = '1') then
nxt_state := t4;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received, expected ACK
end if;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '1'); -- read from slave (R/W = '1')
end if;

when t4 => -- read MSB (hi-byte), send acknowledge
if (cmd_ack = '1') then
nxt_state := t5;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '1';
iwrite := '0';
iack := '0'; --ACK
istop := '0';
end if;

when t5 => -- read LSB (lo-byte), send acknowledge, sent stop
if (cmd_ack = '1') then
nxt_state := t1;

istart := '0';
iread := '1';
iwrite := '0';
iack := '1'; --NACK
istop := '1';

istore_dout := '1';
end if;
end case;

-- genregs
if (nReset = '0') then
state <= i1;
error <= '0';
store_dout <= '0';

start <= '0';
read <= '0';
write <= '0';
ack <= '0';
stop <= '0';
D <= (others => '0');
elsif (clk'event and clk = '1') then
state <= nxt_state;
error <= ierr;
store_dout <= istore_dout;

start <= istart;
read <= iread;
write <= iwrite;
ack <= iack;
stop <= istop;
D <= iD;
end if;
end process nxt_state_decoder;
end block init_statemachine;

-- store temp
gen_dout : process(clk)
begin
if (clk'event and clk = '1') then
if (store_dout = '1') then
Dout <= i2c_dout;
end if;
end if;
end process gen_dout;

end architecture structural;





--
-- Simple I2C controller
--
-- 1) No multimaster
-- 2) No slave mode
-- 3) No fifo's
--
-- notes:
-- Every command is acknowledged. Do not set a new command before previous is acknowledged.
-- Dout is available 1 clock cycle later as cmd_ack
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

package I2C is
component simple_i2c is
port (
clk : in std_logic;
ena : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0); -- 4x SCL

-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
Din : in std_logic_vector(7 downto 0);

-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
Dout : out std_logic_vector(7 downto 0);

-- i2c signals
SCL : inout std_logic;
SDA : inout std_logic
);
end component simple_i2c;
end package I2C;


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity simple_i2c is
port (
clk : in std_logic;
ena : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0); -- 4x SCL

-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
Din : in std_logic_vector(7 downto 0);

-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
Dout : out std_logic_vector(7 downto 0);

-- i2c signals
SCL : inout std_logic;
SDA : inout std_logic
);
end entity simple_i2c;

architecture structural of simple_i2c is
component i2c_core is
port (
clk : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0);

cmd : in std_logic_vector(2 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;

Din : in std_logic;
Dout : out std_logic;

SCL : inout std_logic;
SDA : inout std_logic
);
end component i2c_core;

-- commands for i2c_core
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
constant CMD_START : std_logic_vector(2 downto 0) := "010";
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";

-- signals for i2c_core
signal core_cmd : std_logic_vector(2 downto 0);
signal core_ack, core_busy, core_txd, core_rxd : std_logic;

-- signals for shift register
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
signal shift, ld : std_logic;

-- signals for state machine
signal go, host_ack : std_logic;
begin
-- hookup i2c core
u1: i2c_core port map (clk, nReset, clk_cnt, core_cmd, core_ack, core_busy, core_txd, core_rxd, SCL, SDA);

-- generate host-command-acknowledge
cmd_ack <= host_ack;

-- generate go-signal
go <= (read or write) and not host_ack;

-- assign Dout output to shift-register
Dout <= sr;

-- assign ack_out output to core_rxd (contains last received bit)
ack_out <= core_rxd;

-- generate shift register
shift_register: process(clk)
begin
if (clk'event and clk = '1') then
if (ld = '1') then
sr <= din;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd);
end if;
end if;
end process shift_register;

--
-- state machine
--
statemachine : block
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal state : states;
signal dcnt : unsigned(2 downto 0);
begin
--
-- command interpreter, translate complex commands into simpler I2C commands
--
nxt_state_decoder: process(clk, nReset, state)
variable nxt_state : states;
variable idcnt : unsigned(2 downto 0);
variable ihost_ack : std_logic;
variable icore_cmd : std_logic_vector(2 downto 0);
variable icore_txd : std_logic;
variable ishift, iload : std_logic;
begin
-- 8 databits (1byte) of data to shift-in/out
idcnt := dcnt;

-- no acknowledge (until command complete)
ihost_ack := '0';

icore_txd := core_txd;

-- keep current command to i2c_core
icore_cmd := core_cmd;

-- no shifting or loading of shift-register
ishift := '0';
iload := '0';

-- keep current state;
nxt_state := state;
case state is
when st_idle =>
if (go = '1') then
if (start = '1') then
nxt_state := st_start;
icore_cmd := CMD_START;
elsif (read = '1') then
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111";
else
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111";
iload := '1';
end if;
end if;

when st_start =>
if (core_ack = '1') then
if (read = '1') then
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111";
else
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111";
iload := '1';
end if;
end if;

when st_write =>
if (core_ack = '1') then
idcnt := dcnt -1; -- count down Data_counter
icore_txd := sr(7);
if (dcnt = 0) then
nxt_state := st_ack;
icore_cmd := CMD_READ;
else
ishift := '1';
-- icore_txd := sr(7);
end if;
end if;

when st_read =>
if (core_ack = '1') then
idcnt := dcnt -1; -- count down Data_counter
ishift := '1';
if (dcnt = 0) then
nxt_state := st_ack;
icore_cmd := CMD_WRITE;
icore_txd := ack_in;
end if;
end if;

when st_ack =>
if (core_ack = '1') then
-- generate command acknowledge signal
ihost_ack := '1';

-- Perform an additional shift, needed for 'read' (store last received bit in shift register)
ishift := '1';

-- check for stop; Should a STOP command be generated ?
if (stop = '1') then
nxt_state := st_stop;
icore_cmd := CMD_STOP;
else
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;
end if;

when st_stop =>
if (core_ack = '1') then
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;

when others => -- illegal states
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end case;

-- generate registers
if (nReset = '0') then
core_cmd <= CMD_NOP;
core_txd <= '0';

shift <= '0';
ld <= '0';

dcnt <= "111";
host_ack <= '0';

state <= st_idle;
elsif (clk'event and clk = '1') then
if (ena = '1') then
state <= nxt_state;

dcnt <= idcnt;
shift <= ishift;
ld <= iload;

core_cmd <= icore_cmd;
core_txd <= icore_txd;

host_ack <= ihost_ack;
end if;
end if;
end process nxt_state_decoder;

end block statemachine;

end architecture structural;


--
--
-- I2C Core
--
-- Translate simple commands into SCL/SDA transitions
-- Each command has 5 states, A/B/C/D/idle
--
-- start: SCL ~~~~~~~~~~\____
-- SDA ~~~~~~~~\______
-- x | A | B | C | D | i
--
-- repstart SCL ____/~~~~\___
-- SDA __/~~~\______
-- x | A | B | C | D | i
--
-- stop SCL ____/~~~~~~~~
-- SDA ==\____/~~~~~
-- x | A | B | C | D | i
--
--- write SCL ____/~~~~\____
-- SDA ==X=========X=
-- x | A | B | C | D | i
--
--- read SCL ____/~~~~\____
-- SDA XXXX=====XXXX
-- x | A | B | C | D | i
--

-- Timing: Normal mode Fast mode
-----------------------------------------------------------------
-- Fscl 100KHz 400KHz
-- Th_scl 4.0us 0.6us High period of SCL
-- Tl_scl 4.7us 1.3us Low period of SCL
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity i2c_core is
port (
clk : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0);

cmd : in std_logic_vector(2 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;

Din : in std_logic;
Dout : out std_logic;

SCL : inout std_logic;
SDA : inout std_logic
);
end entity i2c_core;

architecture structural of i2c_core is
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
constant CMD_START : std_logic_vector(2 downto 0) := "010";
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";

type cmds is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
signal state : cmds;
signal SDAo, SCLo : std_logic;
signal txd : std_logic;
signal clk_en, slave_wait :std_logic;
signal cnt : unsigned(7 downto 0) := clk_cnt;
begin
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
slave_wait <= '1' when ((SCLo = '1') and (SCL = '0')) else '0';

-- generate clk enable signal
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0');
clk_en <= '1'; --'0';
elsif (clk'event and clk = '1') then
if (cnt = 0) then
clk_en <= '1';
cnt <= clk_cnt;
else
if (slave_wait = '0') then
cnt <= cnt -1;
end if;
clk_en <= '0';
end if;
end if;
end process gen_clken;

-- generate statemachine
nxt_state_decoder : process (clk, nReset, state, cmd, SDA)
variable nxt_state : cmds;
variable icmd_ack, ibusy, store_sda : std_logic;
variable itxd : std_logic;
begin

nxt_state := state;

icmd_ack := '0'; -- default no acknowledge
ibusy := '1'; -- default busy

store_sda := '0';

itxd := txd;

case (state) is
-- idle
when idle =>
case cmd is
when CMD_START =>
nxt_state := start_a;
icmd_ack := '1'; -- command completed

when CMD_STOP =>
nxt_state := stop_a;
icmd_ack := '1'; -- command completed

when CMD_WRITE =>
nxt_state := wr_a;
icmd_ack := '1'; -- command completed
itxd := Din;

when CMD_READ =>
nxt_state := rd_a;
icmd_ack := '1'; -- command completed

when others =>
nxt_state := idle;
-- don't acknowledge NOP command icmd_ack := '1'; -- command completed
ibusy := '0';
end case;

-- start
when start_a =>
nxt_state := start_b;

when start_b =>
nxt_state := start_c;

when start_c =>
nxt_state := start_d;

when start_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle


-- stop
when stop_a =>
nxt_state := stop_b;

when stop_b =>
nxt_state := stop_c;

when stop_c =>
-- nxt_state := stop_d;

-- when stop_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

-- read
when rd_a =>
nxt_state := rd_b;

when rd_b =>
nxt_state := rd_c;

when rd_c =>
nxt_state := rd_d;
store_sda := '1';

when rd_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

-- write
when wr_a =>
nxt_state := wr_b;

when wr_b =>
nxt_state := wr_c;

when wr_c =>
nxt_state := wr_d;

when wr_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

end case;

-- generate regs
if (nReset = '0') then
state <= idle;
cmd_ack <= '0';
busy <= '0';
txd <= '0';
Dout <= '0';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
state <= nxt_state;
busy <= ibusy;

txd <= itxd;
if (store_sda = '1') then
Dout <= SDA;
end if;
end if;

cmd_ack <= icmd_ack and clk_en;
end if;
end process nxt_state_decoder;

--
-- convert states to SCL and SDA signals
--
output_decoder: process (clk, nReset, state)
variable iscl, isda : std_logic;
begin
case (state) is
when idle =>
iscl := SCLo; -- keep SCL in same state
isda := SDA; -- keep SDA in same state

-- start
when start_a =>
iscl := SCLo; -- keep SCL in same state (for repeated start)
isda := '1'; -- set SDA high

when start_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- keep SDA high

when start_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- sel SDA low

when start_d =>
iscl := '0'; -- set SCL low
isda := '0'; -- keep SDA low

-- stop
when stop_a =>
iscl := '0'; -- keep SCL disabled
isda := '0'; -- set SDA low

when stop_b =>
iscl := '1'; -- set SCL high
isda := '0'; -- keep SDA low

when stop_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- set SDA high

-- write
when wr_a =>
iscl := '0'; -- keep SCL low
-- isda := txd; -- set SDA
isda := Din;

when wr_b =>
iscl := '1'; -- set SCL high
-- isda := txd; -- set SDA
isda := Din;

when wr_c =>
iscl := '1'; -- keep SCL high
-- isda := txd; -- set SDA
isda := Din;

when wr_d =>
iscl := '0'; -- set SCL low
-- isda := txd; -- set SDA
isda := Din;

-- read
when rd_a =>
iscl := '0'; -- keep SCL low
isda := '1'; -- tri-state SDA

when rd_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- tri-state SDA

when rd_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- tri-state SDA

when rd_d =>
iscl := '0'; -- set SCL low
isda := '1'; -- tri-state SDA
end case;

-- generate registers
if (nReset = '0') then
SCLo <= '1';
SDAo <= '1';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
SCLo <= iscl;
SDAo <= isda;
end if;
end if;
end process output_decoder;

SCL <= '0' when (SCLo = '0') else 'Z'; -- since SCL is externally pulled-up convert a '1' to a 'Z'(tri-state)
SDA <= '0' when (SDAo = '0') else 'Z'; -- since SDA is externally pulled-up convert a '1' to a 'Z'(tri-state)
-- SCL <= SCLo;
-- SDA <= SDAo;

end architecture structural;

---------- Post added at 20:29 ---------- Previous post was at 20:25 ----------

21_1298377680.png














--
--
-- State machine for reading data from Dallas 1621
--
-- Testsystem for i2c controller
--
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

use work.i2c.all;

entity DS1621_interface is
port (
clk : in std_logic;
nReset : in std_logic;

Dout : out std_logic_vector(7 downto 0); -- data read from ds1621

error : out std_logic; -- no correct ack received

SCL : inout std_logic;
SDA : inout std_logic
);
end entity DS1621_interface;

architecture structural of DS1621_interface is
constant SLAVE_ADDR : std_logic_vector(6 downto 0) := "1001000";
constant CLK_CNT : unsigned(7 downto 0) := conv_unsigned(20, 8);

signal cmd_ack : std_logic;
signal D : std_logic_vector(7 downto 0);
signal lack, store_dout : std_logic;

signal start, read, write, ack, stop : std_logic;
signal i2c_dout : std_logic_vector(7 downto 0);

begin
-- hookup I2C controller
u1: simple_i2c port map (clk => clk, ena => '1', clk_cnt => clk_cnt, nReset => nReset,
read => read, write => write, start => start, stop => stop, ack_in => ack, cmd_ack => cmd_ack,
Din => D, Dout => i2c_dout, ack_out => lack, SCL => SCL, SDA => SDA);

init_statemachine : block
type states is (i1, i2, i3, i4, i5, t1, t2, t3, t4, t5);
signal state : states;
begin
nxt_state_decoder: process(clk, nReset, state)
variable nxt_state : states;
variable iD : std_logic_vector(7 downto 0);
variable ierr : std_logic;
variable istart, iread, iwrite, iack, istop : std_logic;
variable istore_dout : std_logic;
begin
nxt_state := state;
ierr := '0';
istore_dout := '0';

istart := start;
iread := read;
iwrite := write;
iack := ack;
istop := stop;
iD := D;

case (state) is
-- init DS1621
-- 1) send start condition
-- 2) send slave address + write
-- 3) check ack
-- 4) send "access config" command (0xAC)
-- 5) check ack
-- 6) send config register data (0x00)
-- 7) check ack
-- 8) send stop condition
-- 9) send start condition
-- 10) send slave address + write
-- 11) check ack
-- 12) send "start conversion" command (0xEE)
-- 13) check ack
-- 14) send stop condition

when i1 => -- send start condition, sent slave address + write
nxt_state := i2;
istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')

when i2 => -- send "access config" command
if (cmd_ack = '1') then
nxt_state := i3;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := x"AC";
end if;

when i3 => -- send config register data, sent stop condition
if (cmd_ack = '1') then
nxt_state := i4;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '1';
iD := x"00";
end if;

when i4 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state := i5;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
end if;

when i5 => -- send "start conversion" command + stop condition
if (cmd_ack = '1') then
nxt_state := t1;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '1';
iD := x"EE";
end if;
-- read temperature
-- 1) sent start condition
-- 2) sent slave address + write
-- 3) check ack
-- 4) sent "read temperature" command (0xAA)
-- 5) check ack
-- 6) sent start condition
-- 7) sent slave address + read
-- 8) check ack
-- 9) read msb
-- 10) send ack
-- 11) read lsb
-- 12) send nack
-- 13) send stop condition

when t1 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state := t2;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
end if;

when t2 => -- send read temperature command
if (cmd_ack = '1') then
nxt_state := t3;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := x"AA";
end if;

when t3 => -- send (repeated) start condition, send slave address + read
if (cmd_ack = '1') then
nxt_state := t4;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received, expected ACK
end if;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '1'); -- read from slave (R/W = '1')
end if;

when t4 => -- read MSB (hi-byte), send acknowledge
if (cmd_ack = '1') then
nxt_state := t5;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '1';
iwrite := '0';
iack := '0'; --ACK
istop := '0';
end if;

when t5 => -- read LSB (lo-byte), send acknowledge, sent stop
if (cmd_ack = '1') then
nxt_state := t1;

istart := '0';
iread := '1';
iwrite := '0';
iack := '1'; --NACK
istop := '1';

istore_dout := '1';
end if;
end case;

-- genregs
if (nReset = '0') then
state <= i1;
error <= '0';
store_dout <= '0';

start <= '0';
read <= '0';
write <= '0';
ack <= '0';
stop <= '0';
D <= (others => '0');
elsif (clk'event and clk = '1') then
state <= nxt_state;
error <= ierr;
store_dout <= istore_dout;

start <= istart;
read <= iread;
write <= iwrite;
ack <= iack;
stop <= istop;
D <= iD;
end if;
end process nxt_state_decoder;
end block init_statemachine;

-- store temp
gen_dout : process(clk)
begin
if (clk'event and clk = '1') then
if (store_dout = '1') then
Dout <= i2c_dout;
end if;
end if;
end process gen_dout;

end architecture structural;





--
-- Simple I2C controller
--
-- 1) No multimaster
-- 2) No slave mode
-- 3) No fifo's
--
-- notes:
-- Every command is acknowledged. Do not set a new command before previous is acknowledged.
-- Dout is available 1 clock cycle later as cmd_ack
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

package I2C is
component simple_i2c is
port (
clk : in std_logic;
ena : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0); -- 4x SCL

-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
Din : in std_logic_vector(7 downto 0);

-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
Dout : out std_logic_vector(7 downto 0);

-- i2c signals
SCL : inout std_logic;
SDA : inout std_logic
);
end component simple_i2c;
end package I2C;


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity simple_i2c is
port (
clk : in std_logic;
ena : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0); -- 4x SCL

-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
Din : in std_logic_vector(7 downto 0);

-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
Dout : out std_logic_vector(7 downto 0);

-- i2c signals
SCL : inout std_logic;
SDA : inout std_logic
);
end entity simple_i2c;

architecture structural of simple_i2c is
component i2c_core is
port (
clk : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0);

cmd : in std_logic_vector(2 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;

Din : in std_logic;
Dout : out std_logic;

SCL : inout std_logic;
SDA : inout std_logic
);
end component i2c_core;

-- commands for i2c_core
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
constant CMD_START : std_logic_vector(2 downto 0) := "010";
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";

-- signals for i2c_core
signal core_cmd : std_logic_vector(2 downto 0);
signal core_ack, core_busy, core_txd, core_rxd : std_logic;

-- signals for shift register
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
signal shift, ld : std_logic;

-- signals for state machine
signal go, host_ack : std_logic;
begin
-- hookup i2c core
u1: i2c_core port map (clk, nReset, clk_cnt, core_cmd, core_ack, core_busy, core_txd, core_rxd, SCL, SDA);

-- generate host-command-acknowledge
cmd_ack <= host_ack;

-- generate go-signal
go <= (read or write) and not host_ack;

-- assign Dout output to shift-register
Dout <= sr;

-- assign ack_out output to core_rxd (contains last received bit)
ack_out <= core_rxd;

-- generate shift register
shift_register: process(clk)
begin
if (clk'event and clk = '1') then
if (ld = '1') then
sr <= din;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd);
end if;
end if;
end process shift_register;

--
-- state machine
--
statemachine : block
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal state : states;
signal dcnt : unsigned(2 downto 0);
begin
--
-- command interpreter, translate complex commands into simpler I2C commands
--
nxt_state_decoder: process(clk, nReset, state)
variable nxt_state : states;
variable idcnt : unsigned(2 downto 0);
variable ihost_ack : std_logic;
variable icore_cmd : std_logic_vector(2 downto 0);
variable icore_txd : std_logic;
variable ishift, iload : std_logic;
begin
-- 8 databits (1byte) of data to shift-in/out
idcnt := dcnt;

-- no acknowledge (until command complete)
ihost_ack := '0';

icore_txd := core_txd;

-- keep current command to i2c_core
icore_cmd := core_cmd;

-- no shifting or loading of shift-register
ishift := '0';
iload := '0';

-- keep current state;
nxt_state := state;
case state is
when st_idle =>
if (go = '1') then
if (start = '1') then
nxt_state := st_start;
icore_cmd := CMD_START;
elsif (read = '1') then
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111";
else
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111";
iload := '1';
end if;
end if;

when st_start =>
if (core_ack = '1') then
if (read = '1') then
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111";
else
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111";
iload := '1';
end if;
end if;

when st_write =>
if (core_ack = '1') then
idcnt := dcnt -1; -- count down Data_counter
icore_txd := sr(7);
if (dcnt = 0) then
nxt_state := st_ack;
icore_cmd := CMD_READ;
else
ishift := '1';
-- icore_txd := sr(7);
end if;
end if;

when st_read =>
if (core_ack = '1') then
idcnt := dcnt -1; -- count down Data_counter
ishift := '1';
if (dcnt = 0) then
nxt_state := st_ack;
icore_cmd := CMD_WRITE;
icore_txd := ack_in;
end if;
end if;

when st_ack =>
if (core_ack = '1') then
-- generate command acknowledge signal
ihost_ack := '1';

-- Perform an additional shift, needed for 'read' (store last received bit in shift register)
ishift := '1';

-- check for stop; Should a STOP command be generated ?
if (stop = '1') then
nxt_state := st_stop;
icore_cmd := CMD_STOP;
else
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;
end if;

when st_stop =>
if (core_ack = '1') then
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;

when others => -- illegal states
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end case;

-- generate registers
if (nReset = '0') then
core_cmd <= CMD_NOP;
core_txd <= '0';

shift <= '0';
ld <= '0';

dcnt <= "111";
host_ack <= '0';

state <= st_idle;
elsif (clk'event and clk = '1') then
if (ena = '1') then
state <= nxt_state;

dcnt <= idcnt;
shift <= ishift;
ld <= iload;

core_cmd <= icore_cmd;
core_txd <= icore_txd;

host_ack <= ihost_ack;
end if;
end if;
end process nxt_state_decoder;

end block statemachine;

end architecture structural;


--
--
-- I2C Core
--
-- Translate simple commands into SCL/SDA transitions
-- Each command has 5 states, A/B/C/D/idle
--
-- start: SCL ~~~~~~~~~~\____
-- SDA ~~~~~~~~\______
-- x | A | B | C | D | i
--
-- repstart SCL ____/~~~~\___
-- SDA __/~~~\______
-- x | A | B | C | D | i
--
-- stop SCL ____/~~~~~~~~
-- SDA ==\____/~~~~~
-- x | A | B | C | D | i
--
--- write SCL ____/~~~~\____
-- SDA ==X=========X=
-- x | A | B | C | D | i
--
--- read SCL ____/~~~~\____
-- SDA XXXX=====XXXX
-- x | A | B | C | D | i
--

-- Timing: Normal mode Fast mode
-----------------------------------------------------------------
-- Fscl 100KHz 400KHz
-- Th_scl 4.0us 0.6us High period of SCL
-- Tl_scl 4.7us 1.3us Low period of SCL
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity i2c_core is
port (
clk : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0);

cmd : in std_logic_vector(2 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;

Din : in std_logic;
Dout : out std_logic;

SCL : inout std_logic;
SDA : inout std_logic
);
end entity i2c_core;

architecture structural of i2c_core is
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
constant CMD_START : std_logic_vector(2 downto 0) := "010";
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";

type cmds is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
signal state : cmds;
signal SDAo, SCLo : std_logic;
signal txd : std_logic;
signal clk_en, slave_wait :std_logic;
signal cnt : unsigned(7 downto 0) := clk_cnt;
begin
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
slave_wait <= '1' when ((SCLo = '1') and (SCL = '0')) else '0';

-- generate clk enable signal
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0');
clk_en <= '1'; --'0';
elsif (clk'event and clk = '1') then
if (cnt = 0) then
clk_en <= '1';
cnt <= clk_cnt;
else
if (slave_wait = '0') then
cnt <= cnt -1;
end if;
clk_en <= '0';
end if;
end if;
end process gen_clken;

-- generate statemachine
nxt_state_decoder : process (clk, nReset, state, cmd, SDA)
variable nxt_state : cmds;
variable icmd_ack, ibusy, store_sda : std_logic;
variable itxd : std_logic;
begin

nxt_state := state;

icmd_ack := '0'; -- default no acknowledge
ibusy := '1'; -- default busy

store_sda := '0';

itxd := txd;

case (state) is
-- idle
when idle =>
case cmd is
when CMD_START =>
nxt_state := start_a;
icmd_ack := '1'; -- command completed

when CMD_STOP =>
nxt_state := stop_a;
icmd_ack := '1'; -- command completed

when CMD_WRITE =>
nxt_state := wr_a;
icmd_ack := '1'; -- command completed
itxd := Din;

when CMD_READ =>
nxt_state := rd_a;
icmd_ack := '1'; -- command completed

when others =>
nxt_state := idle;
-- don't acknowledge NOP command icmd_ack := '1'; -- command completed
ibusy := '0';
end case;

-- start
when start_a =>
nxt_state := start_b;

when start_b =>
nxt_state := start_c;

when start_c =>
nxt_state := start_d;

when start_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle


-- stop
when stop_a =>
nxt_state := stop_b;

when stop_b =>
nxt_state := stop_c;

when stop_c =>
-- nxt_state := stop_d;

-- when stop_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

-- read
when rd_a =>
nxt_state := rd_b;

when rd_b =>
nxt_state := rd_c;

when rd_c =>
nxt_state := rd_d;
store_sda := '1';

when rd_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

-- write
when wr_a =>
nxt_state := wr_b;

when wr_b =>
nxt_state := wr_c;

when wr_c =>
nxt_state := wr_d;

when wr_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

end case;

-- generate regs
if (nReset = '0') then
state <= idle;
cmd_ack <= '0';
busy <= '0';
txd <= '0';
Dout <= '0';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
state <= nxt_state;
busy <= ibusy;

txd <= itxd;
if (store_sda = '1') then
Dout <= SDA;
end if;
end if;

cmd_ack <= icmd_ack and clk_en;
end if;
end process nxt_state_decoder;

--
-- convert states to SCL and SDA signals
--
output_decoder: process (clk, nReset, state)
variable iscl, isda : std_logic;
begin
case (state) is
when idle =>
iscl := SCLo; -- keep SCL in same state
isda := SDA; -- keep SDA in same state

-- start
when start_a =>
iscl := SCLo; -- keep SCL in same state (for repeated start)
isda := '1'; -- set SDA high

when start_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- keep SDA high

when start_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- sel SDA low

when start_d =>
iscl := '0'; -- set SCL low
isda := '0'; -- keep SDA low

-- stop
when stop_a =>
iscl := '0'; -- keep SCL disabled
isda := '0'; -- set SDA low

when stop_b =>
iscl := '1'; -- set SCL high
isda := '0'; -- keep SDA low

when stop_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- set SDA high

-- write
when wr_a =>
iscl := '0'; -- keep SCL low
-- isda := txd; -- set SDA
isda := Din;

when wr_b =>
iscl := '1'; -- set SCL high
-- isda := txd; -- set SDA
isda := Din;

when wr_c =>
iscl := '1'; -- keep SCL high
-- isda := txd; -- set SDA
isda := Din;

when wr_d =>
iscl := '0'; -- set SCL low
-- isda := txd; -- set SDA
isda := Din;

-- read
when rd_a =>
iscl := '0'; -- keep SCL low
isda := '1'; -- tri-state SDA

when rd_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- tri-state SDA

when rd_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- tri-state SDA

when rd_d =>
iscl := '0'; -- set SCL low
isda := '1'; -- tri-state SDA
end case;

-- generate registers
if (nReset = '0') then
SCLo <= '1';
SDAo <= '1';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
SCLo <= iscl;
SDAo <= isda;
end if;
end if;
end process output_decoder;

SCL <= '0' when (SCLo = '0') else 'Z'; -- since SCL is externally pulled-up convert a '1' to a 'Z'(tri-state)
SDA <= '0' when (SDAo = '0') else 'Z'; -- since SDA is externally pulled-up convert a '1' to a 'Z'(tri-state)
-- SCL <= SCLo;
-- SDA <= SDAo;

end architecture structural;




**This is the code and the screenshot.. I've tried adjusting the simulation duration still, no waveform can be seen..
Thank you!

---------- Post added at 20:33 ---------- Previous post was at 20:29 ----------

77_1298377926.png













--
--
-- State machine for reading data from Dallas 1621
--
-- Testsystem for i2c controller
--
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

use work.i2c.all;

entity DS1621_interface is
port (
clk : in std_logic;
nReset : in std_logic;

Dout : out std_logic_vector(7 downto 0); -- data read from ds1621

error : out std_logic; -- no correct ack received

SCL : inout std_logic;
SDA : inout std_logic
);
end entity DS1621_interface;

architecture structural of DS1621_interface is
constant SLAVE_ADDR : std_logic_vector(6 downto 0) := "1001000";
constant CLK_CNT : unsigned(7 downto 0) := conv_unsigned(20, 8);

signal cmd_ack : std_logic;
signal D : std_logic_vector(7 downto 0);
signal lack, store_dout : std_logic;

signal start, read, write, ack, stop : std_logic;
signal i2c_dout : std_logic_vector(7 downto 0);

begin
-- hookup I2C controller
u1: simple_i2c port map (clk => clk, ena => '1', clk_cnt => clk_cnt, nReset => nReset,
read => read, write => write, start => start, stop => stop, ack_in => ack, cmd_ack => cmd_ack,
Din => D, Dout => i2c_dout, ack_out => lack, SCL => SCL, SDA => SDA);

init_statemachine : block
type states is (i1, i2, i3, i4, i5, t1, t2, t3, t4, t5);
signal state : states;
begin
nxt_state_decoder: process(clk, nReset, state)
variable nxt_state : states;
variable iD : std_logic_vector(7 downto 0);
variable ierr : std_logic;
variable istart, iread, iwrite, iack, istop : std_logic;
variable istore_dout : std_logic;
begin
nxt_state := state;
ierr := '0';
istore_dout := '0';

istart := start;
iread := read;
iwrite := write;
iack := ack;
istop := stop;
iD := D;

case (state) is
-- init DS1621
-- 1) send start condition
-- 2) send slave address + write
-- 3) check ack
-- 4) send "access config" command (0xAC)
-- 5) check ack
-- 6) send config register data (0x00)
-- 7) check ack
-- 8) send stop condition
-- 9) send start condition
-- 10) send slave address + write
-- 11) check ack
-- 12) send "start conversion" command (0xEE)
-- 13) check ack
-- 14) send stop condition

when i1 => -- send start condition, sent slave address + write
nxt_state := i2;
istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')

when i2 => -- send "access config" command
if (cmd_ack = '1') then
nxt_state := i3;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := x"AC";
end if;

when i3 => -- send config register data, sent stop condition
if (cmd_ack = '1') then
nxt_state := i4;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '1';
iD := x"00";
end if;

when i4 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state := i5;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
end if;

when i5 => -- send "start conversion" command + stop condition
if (cmd_ack = '1') then
nxt_state := t1;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '1';
iD := x"EE";
end if;
-- read temperature
-- 1) sent start condition
-- 2) sent slave address + write
-- 3) check ack
-- 4) sent "read temperature" command (0xAA)
-- 5) check ack
-- 6) sent start condition
-- 7) sent slave address + read
-- 8) check ack
-- 9) read msb
-- 10) send ack
-- 11) read lsb
-- 12) send nack
-- 13) send stop condition

when t1 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state := t2;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
end if;

when t2 => -- send read temperature command
if (cmd_ack = '1') then
nxt_state := t3;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := x"AA";
end if;

when t3 => -- send (repeated) start condition, send slave address + read
if (cmd_ack = '1') then
nxt_state := t4;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received, expected ACK
end if;

istart := '1';
iread := '0';
iwrite := '1';
iack := '0';
istop := '0';
iD := (slave_addr & '1'); -- read from slave (R/W = '1')
end if;

when t4 => -- read MSB (hi-byte), send acknowledge
if (cmd_ack = '1') then
nxt_state := t5;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;

istart := '0';
iread := '1';
iwrite := '0';
iack := '0'; --ACK
istop := '0';
end if;

when t5 => -- read LSB (lo-byte), send acknowledge, sent stop
if (cmd_ack = '1') then
nxt_state := t1;

istart := '0';
iread := '1';
iwrite := '0';
iack := '1'; --NACK
istop := '1';

istore_dout := '1';
end if;
end case;

-- genregs
if (nReset = '0') then
state <= i1;
error <= '0';
store_dout <= '0';

start <= '0';
read <= '0';
write <= '0';
ack <= '0';
stop <= '0';
D <= (others => '0');
elsif (clk'event and clk = '1') then
state <= nxt_state;
error <= ierr;
store_dout <= istore_dout;

start <= istart;
read <= iread;
write <= iwrite;
ack <= iack;
stop <= istop;
D <= iD;
end if;
end process nxt_state_decoder;
end block init_statemachine;

-- store temp
gen_dout : process(clk)
begin
if (clk'event and clk = '1') then
if (store_dout = '1') then
Dout <= i2c_dout;
end if;
end if;
end process gen_dout;

end architecture structural;





--
-- Simple I2C controller
--
-- 1) No multimaster
-- 2) No slave mode
-- 3) No fifo's
--
-- notes:
-- Every command is acknowledged. Do not set a new command before previous is acknowledged.
-- Dout is available 1 clock cycle later as cmd_ack
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

package I2C is
component simple_i2c is
port (
clk : in std_logic;
ena : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0); -- 4x SCL

-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
Din : in std_logic_vector(7 downto 0);

-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
Dout : out std_logic_vector(7 downto 0);

-- i2c signals
SCL : inout std_logic;
SDA : inout std_logic
);
end component simple_i2c;
end package I2C;


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity simple_i2c is
port (
clk : in std_logic;
ena : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0); -- 4x SCL

-- input signals
start,
stop,
read,
write,
ack_in : std_logic;
Din : in std_logic_vector(7 downto 0);

-- output signals
cmd_ack : out std_logic;
ack_out : out std_logic;
Dout : out std_logic_vector(7 downto 0);

-- i2c signals
SCL : inout std_logic;
SDA : inout std_logic
);
end entity simple_i2c;

architecture structural of simple_i2c is
component i2c_core is
port (
clk : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0);

cmd : in std_logic_vector(2 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;

Din : in std_logic;
Dout : out std_logic;

SCL : inout std_logic;
SDA : inout std_logic
);
end component i2c_core;

-- commands for i2c_core
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
constant CMD_START : std_logic_vector(2 downto 0) := "010";
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";

-- signals for i2c_core
signal core_cmd : std_logic_vector(2 downto 0);
signal core_ack, core_busy, core_txd, core_rxd : std_logic;

-- signals for shift register
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
signal shift, ld : std_logic;

-- signals for state machine
signal go, host_ack : std_logic;
begin
-- hookup i2c core
u1: i2c_core port map (clk, nReset, clk_cnt, core_cmd, core_ack, core_busy, core_txd, core_rxd, SCL, SDA);

-- generate host-command-acknowledge
cmd_ack <= host_ack;

-- generate go-signal
go <= (read or write) and not host_ack;

-- assign Dout output to shift-register
Dout <= sr;

-- assign ack_out output to core_rxd (contains last received bit)
ack_out <= core_rxd;

-- generate shift register
shift_register: process(clk)
begin
if (clk'event and clk = '1') then
if (ld = '1') then
sr <= din;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rxd);
end if;
end if;
end process shift_register;

--
-- state machine
--
statemachine : block
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
signal state : states;
signal dcnt : unsigned(2 downto 0);
begin
--
-- command interpreter, translate complex commands into simpler I2C commands
--
nxt_state_decoder: process(clk, nReset, state)
variable nxt_state : states;
variable idcnt : unsigned(2 downto 0);
variable ihost_ack : std_logic;
variable icore_cmd : std_logic_vector(2 downto 0);
variable icore_txd : std_logic;
variable ishift, iload : std_logic;
begin
-- 8 databits (1byte) of data to shift-in/out
idcnt := dcnt;

-- no acknowledge (until command complete)
ihost_ack := '0';

icore_txd := core_txd;

-- keep current command to i2c_core
icore_cmd := core_cmd;

-- no shifting or loading of shift-register
ishift := '0';
iload := '0';

-- keep current state;
nxt_state := state;
case state is
when st_idle =>
if (go = '1') then
if (start = '1') then
nxt_state := st_start;
icore_cmd := CMD_START;
elsif (read = '1') then
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111";
else
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111";
iload := '1';
end if;
end if;

when st_start =>
if (core_ack = '1') then
if (read = '1') then
nxt_state := st_read;
icore_cmd := CMD_READ;
idcnt := "111";
else
nxt_state := st_write;
icore_cmd := CMD_WRITE;
idcnt := "111";
iload := '1';
end if;
end if;

when st_write =>
if (core_ack = '1') then
idcnt := dcnt -1; -- count down Data_counter
icore_txd := sr(7);
if (dcnt = 0) then
nxt_state := st_ack;
icore_cmd := CMD_READ;
else
ishift := '1';
-- icore_txd := sr(7);
end if;
end if;

when st_read =>
if (core_ack = '1') then
idcnt := dcnt -1; -- count down Data_counter
ishift := '1';
if (dcnt = 0) then
nxt_state := st_ack;
icore_cmd := CMD_WRITE;
icore_txd := ack_in;
end if;
end if;

when st_ack =>
if (core_ack = '1') then
-- generate command acknowledge signal
ihost_ack := '1';

-- Perform an additional shift, needed for 'read' (store last received bit in shift register)
ishift := '1';

-- check for stop; Should a STOP command be generated ?
if (stop = '1') then
nxt_state := st_stop;
icore_cmd := CMD_STOP;
else
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;
end if;

when st_stop =>
if (core_ack = '1') then
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end if;

when others => -- illegal states
nxt_state := st_idle;
icore_cmd := CMD_NOP;
end case;

-- generate registers
if (nReset = '0') then
core_cmd <= CMD_NOP;
core_txd <= '0';

shift <= '0';
ld <= '0';

dcnt <= "111";
host_ack <= '0';

state <= st_idle;
elsif (clk'event and clk = '1') then
if (ena = '1') then
state <= nxt_state;

dcnt <= idcnt;
shift <= ishift;
ld <= iload;

core_cmd <= icore_cmd;
core_txd <= icore_txd;

host_ack <= ihost_ack;
end if;
end if;
end process nxt_state_decoder;

end block statemachine;

end architecture structural;


--
--
-- I2C Core
--
-- Translate simple commands into SCL/SDA transitions
-- Each command has 5 states, A/B/C/D/idle
--
-- start: SCL ~~~~~~~~~~\____
-- SDA ~~~~~~~~\______
-- x | A | B | C | D | i
--
-- repstart SCL ____/~~~~\___
-- SDA __/~~~\______
-- x | A | B | C | D | i
--
-- stop SCL ____/~~~~~~~~
-- SDA ==\____/~~~~~
-- x | A | B | C | D | i
--
--- write SCL ____/~~~~\____
-- SDA ==X=========X=
-- x | A | B | C | D | i
--
--- read SCL ____/~~~~\____
-- SDA XXXX=====XXXX
-- x | A | B | C | D | i
--

-- Timing: Normal mode Fast mode
-----------------------------------------------------------------
-- Fscl 100KHz 400KHz
-- Th_scl 4.0us 0.6us High period of SCL
-- Tl_scl 4.7us 1.3us Low period of SCL
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
--

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity i2c_core is
port (
clk : in std_logic;
nReset : in std_logic;

clk_cnt : in unsigned(7 downto 0);

cmd : in std_logic_vector(2 downto 0);
cmd_ack : out std_logic;
busy : out std_logic;

Din : in std_logic;
Dout : out std_logic;

SCL : inout std_logic;
SDA : inout std_logic
);
end entity i2c_core;

architecture structural of i2c_core is
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
constant CMD_START : std_logic_vector(2 downto 0) := "010";
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";

type cmds is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
signal state : cmds;
signal SDAo, SCLo : std_logic;
signal txd : std_logic;
signal clk_en, slave_wait :std_logic;
signal cnt : unsigned(7 downto 0) := clk_cnt;
begin
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
slave_wait <= '1' when ((SCLo = '1') and (SCL = '0')) else '0';

-- generate clk enable signal
gen_clken: process(clk, nReset)
begin
if (nReset = '0') then
cnt <= (others => '0');
clk_en <= '1'; --'0';
elsif (clk'event and clk = '1') then
if (cnt = 0) then
clk_en <= '1';
cnt <= clk_cnt;
else
if (slave_wait = '0') then
cnt <= cnt -1;
end if;
clk_en <= '0';
end if;
end if;
end process gen_clken;

-- generate statemachine
nxt_state_decoder : process (clk, nReset, state, cmd, SDA)
variable nxt_state : cmds;
variable icmd_ack, ibusy, store_sda : std_logic;
variable itxd : std_logic;
begin

nxt_state := state;

icmd_ack := '0'; -- default no acknowledge
ibusy := '1'; -- default busy

store_sda := '0';

itxd := txd;

case (state) is
-- idle
when idle =>
case cmd is
when CMD_START =>
nxt_state := start_a;
icmd_ack := '1'; -- command completed

when CMD_STOP =>
nxt_state := stop_a;
icmd_ack := '1'; -- command completed

when CMD_WRITE =>
nxt_state := wr_a;
icmd_ack := '1'; -- command completed
itxd := Din;

when CMD_READ =>
nxt_state := rd_a;
icmd_ack := '1'; -- command completed

when others =>
nxt_state := idle;
-- don't acknowledge NOP command icmd_ack := '1'; -- command completed
ibusy := '0';
end case;

-- start
when start_a =>
nxt_state := start_b;

when start_b =>
nxt_state := start_c;

when start_c =>
nxt_state := start_d;

when start_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle


-- stop
when stop_a =>
nxt_state := stop_b;

when stop_b =>
nxt_state := stop_c;

when stop_c =>
-- nxt_state := stop_d;

-- when stop_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

-- read
when rd_a =>
nxt_state := rd_b;

when rd_b =>
nxt_state := rd_c;

when rd_c =>
nxt_state := rd_d;
store_sda := '1';

when rd_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

-- write
when wr_a =>
nxt_state := wr_b;

when wr_b =>
nxt_state := wr_c;

when wr_c =>
nxt_state := wr_d;

when wr_d =>
nxt_state := idle;
ibusy := '0'; -- not busy when idle

end case;

-- generate regs
if (nReset = '0') then
state <= idle;
cmd_ack <= '0';
busy <= '0';
txd <= '0';
Dout <= '0';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
state <= nxt_state;
busy <= ibusy;

txd <= itxd;
if (store_sda = '1') then
Dout <= SDA;
end if;
end if;

cmd_ack <= icmd_ack and clk_en;
end if;
end process nxt_state_decoder;

--
-- convert states to SCL and SDA signals
--
output_decoder: process (clk, nReset, state)
variable iscl, isda : std_logic;
begin
case (state) is
when idle =>
iscl := SCLo; -- keep SCL in same state
isda := SDA; -- keep SDA in same state

-- start
when start_a =>
iscl := SCLo; -- keep SCL in same state (for repeated start)
isda := '1'; -- set SDA high

when start_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- keep SDA high

when start_c =>
iscl := '1'; -- keep SCL high
isda := '0'; -- sel SDA low

when start_d =>
iscl := '0'; -- set SCL low
isda := '0'; -- keep SDA low

-- stop
when stop_a =>
iscl := '0'; -- keep SCL disabled
isda := '0'; -- set SDA low

when stop_b =>
iscl := '1'; -- set SCL high
isda := '0'; -- keep SDA low

when stop_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- set SDA high

-- write
when wr_a =>
iscl := '0'; -- keep SCL low
-- isda := txd; -- set SDA
isda := Din;

when wr_b =>
iscl := '1'; -- set SCL high
-- isda := txd; -- set SDA
isda := Din;

when wr_c =>
iscl := '1'; -- keep SCL high
-- isda := txd; -- set SDA
isda := Din;

when wr_d =>
iscl := '0'; -- set SCL low
-- isda := txd; -- set SDA
isda := Din;

-- read
when rd_a =>
iscl := '0'; -- keep SCL low
isda := '1'; -- tri-state SDA

when rd_b =>
iscl := '1'; -- set SCL high
isda := '1'; -- tri-state SDA

when rd_c =>
iscl := '1'; -- keep SCL high
isda := '1'; -- tri-state SDA

when rd_d =>
iscl := '0'; -- set SCL low
isda := '1'; -- tri-state SDA
end case;

-- generate registers
if (nReset = '0') then
SCLo <= '1';
SDAo <= '1';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
SCLo <= iscl;
SDAo <= isda;
end if;
end if;
end process output_decoder;

SCL <= '0' when (SCLo = '0') else 'Z'; -- since SCL is externally pulled-up convert a '1' to a 'Z'(tri-state)
SDA <= '0' when (SDAo = '0') else 'Z'; -- since SDA is externally pulled-up convert a '1' to a 'Z'(tri-state)
-- SCL <= SCLo;
-- SDA <= SDAo;

end architecture structural;


This is the code and the screenshot.. I've tried changing the simulation duration still, no waveform can be seen..
Thank you!
 

A couple of quick points...

Please use
Code:
 and
tags around your vhdl code. Makes it easier to read.

I only see 500 ns of simulation time in the screenshot, correct? For now it doesn't matter so much because it is loads of red & blue, but next time it might help if people see the entire simulation run. :) So, about that red & blue...

In the simulation I see clk is a nice red line, which is X, which is an undefined signal. That usually means that it is connected, and that it is an uninitialized value. So your testbench is not initializing the clk (and a bunch of other signals).

When you use ISE, then you can do from the menu:
New Source => VHDL or Verilog test fixture
then you can select for what module you want to create a test fixture
You then get a template for your testbench, that at least gets you some initial values.

Also, about SDA and SCL... I see those are Z, as in tristated high-Z state. What you probably want is to simulate it as if there were external pullup resistors. So in your testbench (NOT your main module) you have to add some pullup's to simulate those external resistors. So in the test fixture you just made, you add something like:

Code:
pullup(SDA); // simulate external pullup resistor
pullup(SCL); // simulate external pullup resistor

good luck!
 

Yes the clk signal is undriven in the code provided. There is no testbench code, how are you providing clk, rst, and other input signals?
You could try the The VHDL Test Bench :: Overview :: OpenCores system. Easy and has a generator to help you get started.

First thing you have to do is ensure all your input signals are being driven to the right initial value. This is usually done in a test bench of some kind. You will have to go through a reset cycle, of course with the clock running. These are my first steps when testing some RTL. Once I get the reset working, and output signals make sense, I start to try and access registers and work the external interfaces.

I could help you some with getting the testbench started, private message me.

Sckoarn
 

Thank you very much. We do need help in starting the test bench we're a little bit lost right now. So, really, thank you
 

daisyzari,
I just need to know which is the top entity and I can generate a test bench for you. I have problems reading "flat" code like what you posted. Plus you use positional assignments in port mapping, and that just makes things harder to read. If you could post up the code in a file, I could try getting things going a bit as well. And then I can just post up the test bench when I am done.

Sckoarn

P.S. Find Zip file of your design and test bench up and simulating.
P.SS Doc for test bench
 

Attachments

  • i2c.zip
    31.9 KB · Views: 82
  • VHDLtbusers.pdf
    347.6 KB · Views: 109
Last edited:

Skoarn,
Hi! We tried to simulate the code i2c.vhd together with the testbench file you provided however, we encountered errors. :( It says "Library unit STD_LOGIC_1164_additions is not available in library ieee_proposed".
Thank you so much for the help :)
 

daisyzari,

That is a compile problem which you should be able to figure out from my included build.bat file. I down loaded the zip file I posted and tested everything, it works on my side. (the testbench part and design loads and runs the stimuls_file, not sure about the DUT, as I could not drive it with any data)
Also, I attached to my previous post, the documentation for the test bench system.

Have fun.
Sckoarn
 

Sckoarn,

We want to ask if we are supposed to put the .bat file in certain folder for it to work because we tried to execute the file but the error is still there.

Thank you
 

daisyzari,
Sorry you are having so many problems. I am running on Windows 7 OS, using Modelsim PE student edition. The zip file should unziped in a directory. This puts everything you need in one directory. (not the way I usually do things, but his is quick and dirty) What I do is start a CMD shell and CD to the directory that contains the unzipped files. From there I run the build.bat file. (Note: Modelsim is in my search path) In fact my install of modelsim, is fresh on this particular computer. So, on two different computers, using two different modelsim versions, I get the same results.

Ok, you can fix this by changing some code. Everywhere that ieee_proposed is stated in a use statement, comment it out. Change all library statements that say "ieee_proposed." to say "work.", then compile everything into work. (remove the "-work ieee_proposed" option from the vcom command, first one in the bat file)

Or, you can compile everything into work, and remap the ieee_proposed library in the modelsim.ini file. This way you should not have to modify any code.

I will also look for some other solutions and post them up.

Sckoarn

---------- Post added at 16:07 ---------- Previous post was at 15:55 ----------

Well,
I just went through the remapping in the .ini file, it works just fine.

---------------------compile output
c:\work\projects\temp\i2c>build

c:\work\projects\temp\i2c>echo off
** Warning: [3] std_logic_1164_additions.vhdl(1012): (vcom-1246) Range 2 to 1 is
null.
** Warning: (vlib-34) Library already exists at "work".
** Warning: [9] i2c.vhd(658): (vcom-1013) Initial value of "cnt" depends on valu
e of signal "clk_cnt".

c:\work\projects\temp\i2c>vsim
Reading C:/work/Modeltech_pe_edu_10.0a/tcl/vsim/pref.tcl

--------------------------------simulation output.
# vsim work.ds1621_interface_ttb
# Loading std.standard
# Loading std.textio(body)
# Loading ieee.std_logic_1164(body)
# Loading ieee.std_logic_arith(body)
# Loading work.std_logic_1164_additions(body)
# Loading work.tb_pkg(body)
# Loading work.ds1621_interface_ttb(struct)
# Loading work.i2c
# Loading work.ds1621_interface(structural)
# Loading work.simple_i2c(structural)
# Loading work.i2c_core(structural)
# Loading work.ds1621_interface_tb(bhv)
add wave sim:/ds1621_interface_ttb/dut/*
run -all
# ** Failure: Test Finished with NO errors!!
# Time: 20025 ns Iteration: 1 Process: /ds1621_interface_ttb/tb/Read_file File: c:/work/projects/temp/i2c/ds1621_interface_tb_bhv.vhd
# Break in Process Read_file at c:/work/projects/temp/i2c/ds1621_interface_tb_bhv.vhd line 207

Sckoarn
 

Sckoarn,
I tried doing the first solution which is to change the code but there are still errors.. I'm not sure if I was able to do it right or not.. By the way, I'm using Xilinx ISE 9.2i. will this affect the results of the simulation?

I really appreciate the help.. Thank you!
 

daisyzari,
I have never used ISE for simulations. All of the test bench code I have given is behavioural and will not synth.

you could download the modelsim student simulator, it is easy to install and use. Check out this thread:
https://www.edaboard.com/threads/188340/

Sckoarn
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top