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

Subversion Repositories i2c

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/trunk/tst_ds1621.vhd
0,0 → 1,283
--
--
-- 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;
 
 
/trunk/I2C.VHD
0,0 → 1,620
--
-- 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;
 
 
 
 

powered by: WebSVN 2.1.0

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