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.

I2C VHDL reading from slave

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
We were able to write a data to our slave which is an EEPROM atmel 24C04 but we can't seem to read from it.

Please help

Thank You.. :smile:

This is our code
Code:
--
--
-- State machine for reading data from EEPROM
--
-- Testsystem for i2c controller
--
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

use work.i2c.all;

entity I2C_TOP is
port (
clk : in std_logic;
nReset : in std_logic;
-- data from EEPROM
Dprom : out std_logic_vector(7 downto 0); -- out from interface; in to i2c

error : out std_logic; -- no correct ack received

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



architecture structural of I2C_TOP is

constant SLAVE_ADDR : std_logic_vector(6 downto 0) := "1010001";
constant PROM_HBYT : std_logic_vector(7 downto 0) := x"01";
constant PROM_LBYT : std_logic_vector(7 downto 0) := x"AB";
constant PROM_HBYT_R : std_logic_vector(7 downto 0) := x"00";
constant PROM_LBYT_R : std_logic_vector(7 downto 0) := x"FF";
constant CLK_CNT : unsigned(7 downto 0) := conv_unsigned(100, 8); --28 binary

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

signal start, RDRF, TDRE, ack, stop : std_logic;
signal i2c_dout : std_logic_vector(7 downto 0);

begin
-- instantiate to i2c_statemachine
u1: i2c_statemachine port map (clk => clk, ena => '1', clk_cnt => clk_cnt, nReset => nReset,
RDRF => RDRF, TDRE => TDRE, start => start, stop => stop, ack_in => ack, cmd_ack => cmd_ack,
Din => D, Dout => i2c_dout, ack_out => lack, SCL => SCL, SDA => SDA);


interface : block -- grouping,organizing

type states_w is (i1, i2, i3, i4, i5);
type states_r is (t1, t2, t3, t4, t5, t6, t7);
type states_all is (a1, a2);

signal state_write : states_w;
signal state_read : states_r;
signal state_all : states_all;

begin
state_decoder: process(clk, nReset, state_write, state_read, state_all)

variable nxt_state_w : states_w;
variable nxt_state_r : states_r;
variable nxt_state_all : states_all;

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_w := state_write;
nxt_state_r := state_read;
nxt_state_all := state_all;

ierr := '0';


istart := start;
iread := RDRF;
iwrite := TDRE;
iack := ack;
istop := stop;
iD := D;
case (state_all) is

when a1 => --write
case (state_write) is

when i1 => -- send start condition, sent slave address + write

istart := '1';
iread := '0';
iwrite := '1';
iack := '0'; -- means acknowledged
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
istop := '1';
nxt_state_w := i2;


when i2 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state_w := i3;
-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received, acknowledge is always 0
end if;

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

-- send PROM highbit
when i3 =>  
if (cmd_ack = '1') then
nxt_state_w := 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 := '0';
iD := PROM_HBYT;

end if;

 -- send PROM lowbit
 
when i4 =>
if (cmd_ack = '1') then
nxt_state_w := i5;
-- 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 := PROM_LBYT;
end if;

when i5 => 
if (cmd_ack = '1') then
nxt_state_all :=a2;
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"55";

end if; 

 


end case;


when a2 => -- read

case(state_read) is

when t1 =>	-- send start condition, sent slave address + write
if (cmd_ack = '1') then
nxt_state_r := 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 := '1';
iD := (slave_addr & '0'); -- write to slave (R/W = '0')
end if;

when t2 => -- send start condition, sent slave address + write
if (cmd_ack = '1') then

-- 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')
nxt_state_r := t3;

end if;

when t3 => -- send PROM highbit 
if (cmd_ack = '1') then

-- 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 := PROM_HBYT_R;
nxt_state_r := t4;
end if;

when t4 => -- send PROM lowbit
if (cmd_ack = '1') then

-- 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 := PROM_LBYT_R;
nxt_state_r := t5;
end if;

when t5 => -- send (repeated) start condition, send slave address + read
if (cmd_ack = '1') then

-- 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')
nxt_state_r := t6;
end if;

when t6 => -- read MSB (hi-byte), send acknowledge
if (cmd_ack = '1') then

-- 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 := '1'; --NACK
istop := '1';
nxt_state_r := t7;
end if;

when t7 => -- read MSB (hi-byte), send acknowledge
if (cmd_ack = '1') then

-- check aknowledge bit
if (lack = '1') then
ierr := '1'; -- no acknowledge received from last command, expected ACK
end if;


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

end case;
end case;

-- genregs
if (nReset = '0') then
state_all <= a1;
state_write <=i1;
state_read <=t1;
error <= '0';


start <= '0';
RDRF <= '0';
TDRE <= '0';
ack <= '0';
stop <= '0';
D <= (others => '0');
elsif (clk'event and clk = '1') then
state_all <= nxt_state_all;
state_write <= nxt_state_w;
state_read <= nxt_state_r;
error <= ierr;


start <= istart;
RDRF <= iread;
TDRE <= iwrite;
ack <= iack;
stop <= istop;
D <= iD;
end if;

end process state_decoder;
end block interface;


end architecture structural;






--Note: 8bits per data + 1 bit extra new command after 9th bit

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


--for easier access
package I2C is
component i2c_statemachine 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,
RDRF,
TDRE,
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 i2c_statemachine;
end package I2C;



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

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

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

-- input signals
start,
stop,
RDRF, -- signal for read
TDRE, -- Transmit Data Register Empty; '1' = empty means start writing
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 i2c_statemachine;


architecture structural of i2c_statemachine is

component i2c_base is
port (
clk : in std_logic;
nReset : in std_logic;

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

cmd_act : in std_logic_vector(2 downto 0); --command for action
act_ack : out std_logic; --acknowledgement for action


Din : in std_logic;
Dout : out std_logic;

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

--important actions/commands for i2c base
constant act_no_op : std_logic_vector(2 downto 0) := "000";
constant act_start: std_logic_vector(2 downto 0) := "010";
constant act_write : std_logic_vector(2 downto 0) := "011";
constant act_read : std_logic_vector(2 downto 0) := "100";
constant act_idle : std_logic_vector(2 downto 0) := "101";-- SDA is high when idle
constant act_stop : std_logic_vector(2 downto 0) := "110";



-- signals for i2c_controller_base
signal core_cmd : std_logic_vector(2 downto 0);
signal core_ack, core_trans, core_rcve : std_logic;

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

-- signals for state machine
signal en_act, master_ack : std_logic;


begin

-- instantiation to i2c_base

u1: i2c_base port map (clk, nReset, clk_cnt, core_cmd, core_ack, core_trans, core_rcve, SCL, SDA);

-- generate command-acknowledge on
cmd_ack <= master_ack;





-- assign ack_out output to core_rcve: should  be equal to zero 
ack_out <= core_rcve;



-- generate data register with+shift register
data_reg : block

--signals for data register
signal dr: std_logic_vector(7 downto 0);

begin 

data_register: process(clk)

variable iempty :std_logic_vector(7 downto 0):= "00000000";

begin
if (clk'event and clk = '1') then
if (TDRE = '1') then
dr <=iempty; 
dr <= Din;
end if;
if (load = '1') then
sr <= dr;
elsif (shift = '1') then
sr <= (sr(6 downto 0) & core_rcve); --last rcved bit :research
end if;
end if;
-- shift-register to Dout
Dout <= sr;
end process data_register;
end block data_reg;

-- grouping of state machine using black statement

statuscontrol_reg : block 

type states is (st_no_op, st_start, st_read, st_write, st_ack, st_stop);
signal state : states;
signal dcnt : unsigned(2 downto 0);

begin
-- enable before startup
en_act <= (RDRF or TDRE) and not master_ack;


status_control: process(clk, nReset, state)
variable nxt_state : states;
variable idcnt : unsigned(2 downto 0);
variable imaster_ack : std_logic; --host acknowledge 
variable icore_cmd : std_logic_vector(2 downto 0);
variable icore_trans : std_logic;
variable ishift, iload : std_logic;

begin
-- 8 databits (1byte) of data to shift-in/out
idcnt := dcnt;

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

icore_trans := core_trans;


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_no_op =>
if (en_act = '1') then
if (start = '1') then

nxt_state := st_start;
icore_cmd := act_start;

elsif (RDRF = '1') then

nxt_state := st_read;
icore_cmd := act_read;
idcnt := "111";

else

nxt_state := st_write;

icore_cmd := act_write;
idcnt := "111";
iload := '1';

end if;
end if;

when st_start =>
if (core_ack = '1') then
if (RDRF = '1') then
nxt_state := st_read;
icore_cmd := act_read;
idcnt := "111";
else
nxt_state := st_write;
icore_cmd := act_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_trans := sr(7);
if (dcnt = 0) then
nxt_state := st_ack;
icore_cmd := act_idle;
else
ishift := '1';
-- icore_trans := 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 := act_idle;
icore_trans := ack_in;
end if;
end if;

when st_ack =>
if (core_ack = '1') then
-- generate command acknowledge signal
imaster_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 := act_stop;
else
nxt_state := st_no_op;
icore_cmd := act_no_op;
end if;
end if;

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

when others => -- illegal states
nxt_state := st_no_op;
icore_cmd := act_no_op;
end case;

-- generate registers
if (nReset = '0') then
core_cmd <= act_no_op;
core_trans <= '0';

shift <= '0';
load <= '0';

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

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

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

core_cmd <= icore_cmd;
core_trans <= icore_trans;

master_ack <= imaster_ack;
end if;
end if;
end process status_control;

end block statuscontrol_reg;

end architecture structural;





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

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

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

cmd_act : in std_logic_vector(2 downto 0); --command for action
act_ack : out std_logic; --acknowledgement for action


Din : in std_logic;
Dout : out std_logic;

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

architecture structural of i2c_base is
--important actions/commands
constant act_no_op : std_logic_vector(2 downto 0) := "000";
constant act_start: std_logic_vector(2 downto 0) := "010";
constant act_write : std_logic_vector(2 downto 0) := "011";
constant act_read : std_logic_vector(2 downto 0) := "100";
constant act_idle : std_logic_vector(2 downto 0) := "101"; -- when idle sda is high
constant act_stop : std_logic_vector(2 downto 0) := "110";


type action is (no_op, idle_a, idle_b, idle_c, idle_d, start_a, start_b, start_c, start_d, start_e, start_f, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
signal state : action;
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';


-- 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; -- loading of clk_cnt when clk_en is disabled
else
if (slave_wait = '0') then
cnt <= cnt -1;
end if;
clk_en <= '0';
end if;
end if;

end process gen_clken;

-- statemachine for i2c_base


state_decoder : process (clk, nReset, state, cmd_act, SDA)
variable nxt_state : action;
variable iact_ack : std_logic;
variable itxd : std_logic;

		

begin



nxt_state := state;

iact_ack := '0'; -- default no acknowledge




itxd := txd;

case (state) is
-- no operation
when no_op =>
case (cmd_act) is
when act_start =>
nxt_state := start_a;
iact_ack := '1'; -- command completed



when act_stop =>
nxt_state := stop_a;
iact_ack := '1'; -- command completed



when act_write =>
nxt_state := wr_a;
iact_ack := '1'; -- command completed
itxd := Din;


when act_read =>
nxt_state := rd_a;
iact_ack := '1'; -- command completed



when act_idle=>
nxt_state := idle_a;
iact_ack := '1';



when others =>
nxt_state := no_op;


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 := start_e;

when start_e =>
nxt_state := start_f;

when start_f =>

nxt_state := no_op;
				
	



-- 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 := no_op;
				



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

when rd_b =>
nxt_state := rd_c;

when rd_c =>
nxt_state := rd_d;


when rd_d =>

nxt_state := no_op;

			

-- 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 := no_op;
				

			

--idle
when idle_a =>
nxt_state := idle_b;

when idle_b =>
nxt_state := idle_c;

when idle_c =>
nxt_state := idle_d;

when idle_d =>
nxt_state := no_op;





end case;

-- Resetting
if (nReset = '0') then
state <= no_op;


act_ack <= '0';
txd <= '0';
Dout <= '0';
elsif (clk'event and clk = '1') then
if (clk_en = '1') then
state <= nxt_state;


txd <= itxd;

end if;

act_ack <= iact_ack and clk_en;--go back '0'
end if;
end process state_decoder;





--
-- convert states to SCL and SDA signals
--
output_decoder: process (clk, nReset, state)
variable iscl, isda : std_logic;
begin
case (state) is
--idle with spike

when no_op =>
iscl := SCLo; -- keep SCL in same state
isda := SDAo; -- keep SDA in same state

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

when idle_b =>
iscl := '1'; -- set SCL high

isda := '0';

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

when idle_d =>
iscl := '0'; -- set SCL low
isda := '1';

-- 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 := '1'; -- sel SDA low

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

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

when start_f =>
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;


Ignore the comments. It's quite confusing because i fail to change some of it when i edited some of the codes. :razz:
 

The design can't be checked, because it's incomplete. Generally, you would want to post an archive of source files rather than > 1000 lines in a code window.

I've no idea, if the problem can be identified easily. I guess, it's more promising that you'll check it with a VHDL simulator, e.g. Modelsim. You can also add a 24C04 simulation model to your testbench to check overall operation.

I won't be surprized, if a trivial error in some place of the code is causing the problem. But there's no alternative to figuring it out step-by-step, I think.

It's just everydays HDL programming...
 

no.. the above code is the complete code.. :D
 

no.. the above code is the complete code..
It can be hardly complete without the definition of instantiated components, isn't it?
 

And if you put a scope, logic analyzer, chip scope on it? Can you see where it fails during a read?

For example, have you verified that you are sending the correct slave address for that read, and do you see the ACK for that?

The "it fails during a read" that is not much information to go on to help you be able to find the problem. It can be an electrical problem (scope it), it can be a stupid typo in the slave address, it can be the huge chunk of VHDL up there that I didn't all read, etc...

This is in actual hardwae, right? If yes, did the read/write work in simulation?
 

daisyzaridaisyzari: where you able to read from the I2C?
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top