--
|
--
|
-- Simple I2C controller
|
-- Simple I2C controller
|
--
|
--
|
-- 1) No multimaster
|
-- 1) No multimaster
|
-- 2) No slave mode
|
-- 2) No slave mode
|
-- 3) No fifo's
|
-- 3) No fifo's
|
--
|
--
|
-- notes:
|
-- notes:
|
-- Every command is acknowledged. Do not set a new command before previous is acknowledged.
|
-- Every command is acknowledged. Do not set a new command before previous is acknowledged.
|
-- Dout is available 1 clock cycle later as cmd_ack
|
-- Dout is available 1 clock cycle later as cmd_ack
|
--
|
--
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
|
|
package I2C is
|
package I2C is
|
component simple_i2c is
|
component simple_i2c is
|
port (
|
port (
|
clk : in std_logic;
|
clk : in std_logic;
|
ena : in std_logic;
|
ena : in std_logic;
|
nReset : in std_logic;
|
nReset : in std_logic;
|
|
|
clk_cnt : in unsigned(7 downto 0); -- 4x SCL
|
clk_cnt : in unsigned(7 downto 0); -- 4x SCL
|
|
|
-- input signals
|
-- input signals
|
start,
|
start,
|
stop,
|
stop,
|
read,
|
read,
|
write,
|
write,
|
ack_in : std_logic;
|
ack_in : std_logic;
|
Din : in std_logic_vector(7 downto 0);
|
Din : in std_logic_vector(7 downto 0);
|
|
|
-- output signals
|
-- output signals
|
cmd_ack : out std_logic;
|
cmd_ack : out std_logic;
|
ack_out : out std_logic;
|
ack_out : out std_logic;
|
Dout : out std_logic_vector(7 downto 0);
|
Dout : out std_logic_vector(7 downto 0);
|
|
|
-- i2c signals
|
-- i2c signals
|
SCL : inout std_logic;
|
SCL : inout std_logic;
|
SDA : inout std_logic
|
SDA : inout std_logic
|
);
|
);
|
end component simple_i2c;
|
end component simple_i2c;
|
end package I2C;
|
end package I2C;
|
|
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
|
|
entity simple_i2c is
|
entity simple_i2c is
|
port (
|
port (
|
clk : in std_logic;
|
clk : in std_logic;
|
ena : in std_logic;
|
ena : in std_logic;
|
nReset : in std_logic;
|
nReset : in std_logic;
|
|
|
clk_cnt : in unsigned(7 downto 0); -- 4x SCL
|
clk_cnt : in unsigned(7 downto 0); -- 4x SCL
|
|
|
-- input signals
|
-- input signals
|
start,
|
start,
|
stop,
|
stop,
|
read,
|
read,
|
write,
|
write,
|
ack_in : std_logic;
|
ack_in : std_logic;
|
Din : in std_logic_vector(7 downto 0);
|
Din : in std_logic_vector(7 downto 0);
|
|
|
-- output signals
|
-- output signals
|
cmd_ack : out std_logic;
|
cmd_ack : out std_logic;
|
ack_out : out std_logic;
|
ack_out : out std_logic;
|
Dout : out std_logic_vector(7 downto 0);
|
Dout : out std_logic_vector(7 downto 0);
|
|
|
-- i2c signals
|
-- i2c signals
|
SCL : inout std_logic;
|
SCL : inout std_logic;
|
SDA : inout std_logic
|
SDA : inout std_logic
|
);
|
);
|
end entity simple_i2c;
|
end entity simple_i2c;
|
|
|
architecture structural of simple_i2c is
|
architecture structural of simple_i2c is
|
component i2c_core is
|
component i2c_core is
|
port (
|
port (
|
clk : in std_logic;
|
clk : in std_logic;
|
nReset : in std_logic;
|
nReset : in std_logic;
|
|
|
clk_cnt : in unsigned(7 downto 0);
|
clk_cnt : in unsigned(7 downto 0);
|
|
|
cmd : in std_logic_vector(2 downto 0);
|
cmd : in std_logic_vector(2 downto 0);
|
cmd_ack : out std_logic;
|
cmd_ack : out std_logic;
|
busy : out std_logic;
|
busy : out std_logic;
|
|
|
Din : in std_logic;
|
Din : in std_logic;
|
Dout : out std_logic;
|
Dout : out std_logic;
|
|
|
SCL : inout std_logic;
|
SCL : inout std_logic;
|
SDA : inout std_logic
|
SDA : inout std_logic
|
);
|
);
|
end component i2c_core;
|
end component i2c_core;
|
|
|
-- commands for i2c_core
|
-- commands for i2c_core
|
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
|
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
|
constant CMD_START : std_logic_vector(2 downto 0) := "010";
|
constant CMD_START : std_logic_vector(2 downto 0) := "010";
|
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
|
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
|
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
|
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
|
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";
|
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";
|
|
|
-- signals for i2c_core
|
-- signals for i2c_core
|
signal core_cmd : std_logic_vector(2 downto 0);
|
signal core_cmd : std_logic_vector(2 downto 0);
|
signal core_ack, core_busy, core_txd, core_rxd : std_logic;
|
signal core_ack, core_busy, core_txd, core_rxd : std_logic;
|
|
|
-- signals for shift register
|
-- signals for shift register
|
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
|
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register
|
signal shift, ld : std_logic;
|
signal shift, ld : std_logic;
|
|
|
-- signals for state machine
|
-- signals for state machine
|
signal go, host_ack : std_logic;
|
signal go, host_ack : std_logic;
|
begin
|
begin
|
-- hookup i2c core
|
-- hookup i2c core
|
u1: i2c_core port map (clk, nReset, clk_cnt, core_cmd, core_ack, core_busy, core_txd, core_rxd, SCL, SDA);
|
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
|
-- generate host-command-acknowledge
|
cmd_ack <= host_ack;
|
cmd_ack <= host_ack;
|
|
|
-- generate go-signal
|
-- generate go-signal
|
go <= (read or write) and not host_ack;
|
go <= (read or write) and not host_ack;
|
|
|
-- assign Dout output to shift-register
|
-- assign Dout output to shift-register
|
Dout <= sr;
|
Dout <= sr;
|
|
|
-- assign ack_out output to core_rxd (contains last received bit)
|
-- assign ack_out output to core_rxd (contains last received bit)
|
ack_out <= core_rxd;
|
ack_out <= core_rxd;
|
|
|
-- generate shift register
|
-- generate shift register
|
shift_register: process(clk)
|
shift_register: process(clk)
|
begin
|
begin
|
if (clk'event and clk = '1') then
|
if (clk'event and clk = '1') then
|
if (ld = '1') then
|
if (ld = '1') then
|
sr <= din;
|
sr <= din;
|
elsif (shift = '1') then
|
elsif (shift = '1') then
|
sr <= (sr(6 downto 0) & core_rxd);
|
sr <= (sr(6 downto 0) & core_rxd);
|
end if;
|
end if;
|
end if;
|
end if;
|
end process shift_register;
|
end process shift_register;
|
|
|
--
|
--
|
-- state machine
|
-- state machine
|
--
|
--
|
statemachine : block
|
statemachine : block
|
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
|
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop);
|
signal state : states;
|
signal state : states;
|
signal dcnt : unsigned(2 downto 0);
|
signal dcnt : unsigned(2 downto 0);
|
begin
|
begin
|
--
|
--
|
-- command interpreter, translate complex commands into simpler I2C commands
|
-- command interpreter, translate complex commands into simpler I2C commands
|
--
|
--
|
nxt_state_decoder: process(clk, nReset, state)
|
nxt_state_decoder: process(clk, nReset, state)
|
variable nxt_state : states;
|
variable nxt_state : states;
|
variable idcnt : unsigned(2 downto 0);
|
variable idcnt : unsigned(2 downto 0);
|
variable ihost_ack : std_logic;
|
variable ihost_ack : std_logic;
|
variable icore_cmd : std_logic_vector(2 downto 0);
|
variable icore_cmd : std_logic_vector(2 downto 0);
|
variable icore_txd : std_logic;
|
variable icore_txd : std_logic;
|
variable ishift, iload : std_logic;
|
variable ishift, iload : std_logic;
|
begin
|
begin
|
-- 8 databits (1byte) of data to shift-in/out
|
-- 8 databits (1byte) of data to shift-in/out
|
idcnt := dcnt;
|
idcnt := dcnt;
|
|
|
-- no acknowledge (until command complete)
|
-- no acknowledge (until command complete)
|
ihost_ack := '0';
|
ihost_ack := '0';
|
|
|
icore_txd := core_txd;
|
icore_txd := core_txd;
|
|
|
-- keep current command to i2c_core
|
-- keep current command to i2c_core
|
icore_cmd := core_cmd;
|
icore_cmd := core_cmd;
|
|
|
-- no shifting or loading of shift-register
|
-- no shifting or loading of shift-register
|
ishift := '0';
|
ishift := '0';
|
iload := '0';
|
iload := '0';
|
|
|
-- keep current state;
|
-- keep current state;
|
nxt_state := state;
|
nxt_state := state;
|
case state is
|
case state is
|
when st_idle =>
|
when st_idle =>
|
if (go = '1') then
|
if (go = '1') then
|
if (start = '1') then
|
if (start = '1') then
|
nxt_state := st_start;
|
nxt_state := st_start;
|
icore_cmd := CMD_START;
|
icore_cmd := CMD_START;
|
elsif (read = '1') then
|
elsif (read = '1') then
|
nxt_state := st_read;
|
nxt_state := st_read;
|
icore_cmd := CMD_READ;
|
icore_cmd := CMD_READ;
|
idcnt := "111";
|
idcnt := "111";
|
else
|
else
|
nxt_state := st_write;
|
nxt_state := st_write;
|
icore_cmd := CMD_WRITE;
|
icore_cmd := CMD_WRITE;
|
idcnt := "111";
|
idcnt := "111";
|
iload := '1';
|
iload := '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when st_start =>
|
when st_start =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
if (read = '1') then
|
if (read = '1') then
|
nxt_state := st_read;
|
nxt_state := st_read;
|
icore_cmd := CMD_READ;
|
icore_cmd := CMD_READ;
|
idcnt := "111";
|
idcnt := "111";
|
else
|
else
|
nxt_state := st_write;
|
nxt_state := st_write;
|
icore_cmd := CMD_WRITE;
|
icore_cmd := CMD_WRITE;
|
idcnt := "111";
|
idcnt := "111";
|
iload := '1';
|
iload := '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when st_write =>
|
when st_write =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
idcnt := dcnt -1; -- count down Data_counter
|
idcnt := dcnt -1; -- count down Data_counter
|
icore_txd := sr(7);
|
icore_txd := sr(7);
|
if (dcnt = 0) then
|
if (dcnt = 0) then
|
nxt_state := st_ack;
|
nxt_state := st_ack;
|
icore_cmd := CMD_READ;
|
icore_cmd := CMD_READ;
|
else
|
else
|
ishift := '1';
|
ishift := '1';
|
-- icore_txd := sr(7);
|
-- icore_txd := sr(7);
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when st_read =>
|
when st_read =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
idcnt := dcnt -1; -- count down Data_counter
|
idcnt := dcnt -1; -- count down Data_counter
|
ishift := '1';
|
ishift := '1';
|
if (dcnt = 0) then
|
if (dcnt = 0) then
|
nxt_state := st_ack;
|
nxt_state := st_ack;
|
icore_cmd := CMD_WRITE;
|
icore_cmd := CMD_WRITE;
|
icore_txd := ack_in;
|
icore_txd := ack_in;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when st_ack =>
|
when st_ack =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
-- generate command acknowledge signal
|
-- generate command acknowledge signal
|
ihost_ack := '1';
|
ihost_ack := '1';
|
|
|
-- Perform an additional shift, needed for 'read' (store last received bit in shift register)
|
-- Perform an additional shift, needed for 'read' (store last received bit in shift register)
|
ishift := '1';
|
ishift := '1';
|
|
|
-- check for stop; Should a STOP command be generated ?
|
-- check for stop; Should a STOP command be generated ?
|
if (stop = '1') then
|
if (stop = '1') then
|
nxt_state := st_stop;
|
nxt_state := st_stop;
|
icore_cmd := CMD_STOP;
|
icore_cmd := CMD_STOP;
|
else
|
else
|
nxt_state := st_idle;
|
nxt_state := st_idle;
|
icore_cmd := CMD_NOP;
|
icore_cmd := CMD_NOP;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
when st_stop =>
|
when st_stop =>
|
if (core_ack = '1') then
|
if (core_ack = '1') then
|
nxt_state := st_idle;
|
nxt_state := st_idle;
|
icore_cmd := CMD_NOP;
|
icore_cmd := CMD_NOP;
|
end if;
|
end if;
|
|
|
when others => -- illegal states
|
when others => -- illegal states
|
nxt_state := st_idle;
|
nxt_state := st_idle;
|
icore_cmd := CMD_NOP;
|
icore_cmd := CMD_NOP;
|
end case;
|
end case;
|
|
|
-- generate registers
|
-- generate registers
|
if (nReset = '0') then
|
if (nReset = '0') then
|
core_cmd <= CMD_NOP;
|
core_cmd <= CMD_NOP;
|
core_txd <= '0';
|
core_txd <= '0';
|
|
|
shift <= '0';
|
shift <= '0';
|
ld <= '0';
|
ld <= '0';
|
|
|
dcnt <= "111";
|
dcnt <= "111";
|
host_ack <= '0';
|
host_ack <= '0';
|
|
|
state <= st_idle;
|
state <= st_idle;
|
elsif (clk'event and clk = '1') then
|
elsif (clk'event and clk = '1') then
|
if (ena = '1') then
|
if (ena = '1') then
|
state <= nxt_state;
|
state <= nxt_state;
|
|
|
dcnt <= idcnt;
|
dcnt <= idcnt;
|
shift <= ishift;
|
shift <= ishift;
|
ld <= iload;
|
ld <= iload;
|
|
|
core_cmd <= icore_cmd;
|
core_cmd <= icore_cmd;
|
core_txd <= icore_txd;
|
core_txd <= icore_txd;
|
|
|
host_ack <= ihost_ack;
|
host_ack <= ihost_ack;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process nxt_state_decoder;
|
end process nxt_state_decoder;
|
|
|
end block statemachine;
|
end block statemachine;
|
|
|
end architecture structural;
|
end architecture structural;
|
|
|
|
|
--
|
--
|
--
|
--
|
-- I2C Core
|
-- I2C Core
|
--
|
--
|
-- Translate simple commands into SCL/SDA transitions
|
-- Translate simple commands into SCL/SDA transitions
|
-- Each command has 5 states, A/B/C/D/idle
|
-- Each command has 5 states, A/B/C/D/idle
|
--
|
--
|
-- start: SCL ~~~~~~~~~~\____
|
-- start: SCL ~~~~~~~~~~\____
|
-- SDA ~~~~~~~~\______
|
-- SDA ~~~~~~~~\______
|
-- x | A | B | C | D | i
|
-- x | A | B | C | D | i
|
--
|
--
|
-- repstart SCL ____/~~~~\___
|
-- repstart SCL ____/~~~~\___
|
-- SDA __/~~~\______
|
-- SDA __/~~~\______
|
-- x | A | B | C | D | i
|
-- x | A | B | C | D | i
|
--
|
--
|
-- stop SCL ____/~~~~~~~~
|
-- stop SCL ____/~~~~~~~~
|
-- SDA ==\____/~~~~~
|
-- SDA ==\____/~~~~~
|
-- x | A | B | C | D | i
|
-- x | A | B | C | D | i
|
--
|
--
|
--- write SCL ____/~~~~\____
|
--- write SCL ____/~~~~\____
|
-- SDA ==X=========X=
|
-- SDA ==X=========X=
|
-- x | A | B | C | D | i
|
-- x | A | B | C | D | i
|
--
|
--
|
--- read SCL ____/~~~~\____
|
--- read SCL ____/~~~~\____
|
-- SDA XXXX=====XXXX
|
-- SDA XXXX=====XXXX
|
-- x | A | B | C | D | i
|
-- x | A | B | C | D | i
|
--
|
--
|
|
|
-- Timing: Normal mode Fast mode
|
-- Timing: Normal mode Fast mode
|
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
-- Fscl 100KHz 400KHz
|
-- Fscl 100KHz 400KHz
|
-- Th_scl 4.0us 0.6us High period of SCL
|
-- Th_scl 4.0us 0.6us High period of SCL
|
-- Tl_scl 4.7us 1.3us Low 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:sta 4.7us 0.6us setup time for a repeated start condition
|
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
|
-- 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
|
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
|
--
|
--
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
|
|
entity i2c_core is
|
entity i2c_core is
|
port (
|
port (
|
clk : in std_logic;
|
clk : in std_logic;
|
nReset : in std_logic;
|
nReset : in std_logic;
|
|
|
clk_cnt : in unsigned(7 downto 0);
|
clk_cnt : in unsigned(7 downto 0);
|
|
|
cmd : in std_logic_vector(2 downto 0);
|
cmd : in std_logic_vector(2 downto 0);
|
cmd_ack : out std_logic;
|
cmd_ack : out std_logic;
|
busy : out std_logic;
|
busy : out std_logic;
|
|
|
Din : in std_logic;
|
Din : in std_logic;
|
Dout : out std_logic;
|
Dout : out std_logic;
|
|
|
SCL : inout std_logic;
|
SCL : inout std_logic;
|
SDA : inout std_logic
|
SDA : inout std_logic
|
);
|
);
|
end entity i2c_core;
|
end entity i2c_core;
|
|
|
architecture structural of i2c_core is
|
architecture structural of i2c_core is
|
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
|
constant CMD_NOP : std_logic_vector(2 downto 0) := "000";
|
constant CMD_START : std_logic_vector(2 downto 0) := "010";
|
constant CMD_START : std_logic_vector(2 downto 0) := "010";
|
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
|
constant CMD_STOP : std_logic_vector(2 downto 0) := "011";
|
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
|
constant CMD_READ : std_logic_vector(2 downto 0) := "100";
|
constant CMD_WRITE : std_logic_vector(2 downto 0) := "101";
|
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);
|
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 state : cmds;
|
signal SDAo, SCLo : std_logic;
|
signal SDAo, SCLo : std_logic;
|
signal txd : std_logic;
|
signal txd : std_logic;
|
signal clk_en, slave_wait :std_logic;
|
signal clk_en, slave_wait :std_logic;
|
signal cnt : unsigned(7 downto 0) := clk_cnt;
|
signal cnt : unsigned(7 downto 0) := clk_cnt;
|
begin
|
begin
|
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
|
-- 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';
|
slave_wait <= '1' when ((SCLo = '1') and (SCL = '0')) else '0';
|
|
|
-- generate clk enable signal
|
-- generate clk enable signal
|
gen_clken: process(clk, nReset)
|
gen_clken: process(clk, nReset)
|
begin
|
begin
|
if (nReset = '0') then
|
if (nReset = '0') then
|
cnt <= (others => '0');
|
cnt <= (others => '0');
|
clk_en <= '1'; --'0';
|
clk_en <= '1'; --'0';
|
elsif (clk'event and clk = '1') then
|
elsif (clk'event and clk = '1') then
|
if (cnt = 0) then
|
if (cnt = 0) then
|
clk_en <= '1';
|
clk_en <= '1';
|
cnt <= clk_cnt;
|
cnt <= clk_cnt;
|
else
|
else
|
if (slave_wait = '0') then
|
if (slave_wait = '0') then
|
cnt <= cnt -1;
|
cnt <= cnt -1;
|
end if;
|
end if;
|
clk_en <= '0';
|
clk_en <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process gen_clken;
|
end process gen_clken;
|
|
|
-- generate statemachine
|
-- generate statemachine
|
nxt_state_decoder : process (clk, nReset, state, cmd, SDA)
|
nxt_state_decoder : process (clk, nReset, state, cmd, SDA)
|
variable nxt_state : cmds;
|
variable nxt_state : cmds;
|
variable icmd_ack, ibusy, store_sda : std_logic;
|
variable icmd_ack, ibusy, store_sda : std_logic;
|
variable itxd : std_logic;
|
variable itxd : std_logic;
|
begin
|
begin
|
|
|
nxt_state := state;
|
nxt_state := state;
|
|
|
icmd_ack := '0'; -- default no acknowledge
|
icmd_ack := '0'; -- default no acknowledge
|
ibusy := '1'; -- default busy
|
ibusy := '1'; -- default busy
|
|
|
store_sda := '0';
|
store_sda := '0';
|
|
|
itxd := txd;
|
itxd := txd;
|
|
|
case (state) is
|
case (state) is
|
-- idle
|
-- idle
|
when idle =>
|
when idle =>
|
case cmd is
|
case cmd is
|
when CMD_START =>
|
when CMD_START =>
|
nxt_state := start_a;
|
nxt_state := start_a;
|
icmd_ack := '1'; -- command completed
|
icmd_ack := '1'; -- command completed
|
|
|
when CMD_STOP =>
|
when CMD_STOP =>
|
nxt_state := stop_a;
|
nxt_state := stop_a;
|
icmd_ack := '1'; -- command completed
|
icmd_ack := '1'; -- command completed
|
|
|
when CMD_WRITE =>
|
when CMD_WRITE =>
|
nxt_state := wr_a;
|
nxt_state := wr_a;
|
icmd_ack := '1'; -- command completed
|
icmd_ack := '1'; -- command completed
|
itxd := Din;
|
itxd := Din;
|
|
|
when CMD_READ =>
|
when CMD_READ =>
|
nxt_state := rd_a;
|
nxt_state := rd_a;
|
icmd_ack := '1'; -- command completed
|
icmd_ack := '1'; -- command completed
|
|
|
when others =>
|
when others =>
|
nxt_state := idle;
|
nxt_state := idle;
|
-- don't acknowledge NOP command icmd_ack := '1'; -- command completed
|
-- don't acknowledge NOP command icmd_ack := '1'; -- command completed
|
ibusy := '0';
|
ibusy := '0';
|
end case;
|
end case;
|
|
|
-- start
|
-- start
|
when start_a =>
|
when start_a =>
|
nxt_state := start_b;
|
nxt_state := start_b;
|
|
|
when start_b =>
|
when start_b =>
|
nxt_state := start_c;
|
nxt_state := start_c;
|
|
|
when start_c =>
|
when start_c =>
|
nxt_state := start_d;
|
nxt_state := start_d;
|
|
|
when start_d =>
|
when start_d =>
|
nxt_state := idle;
|
nxt_state := idle;
|
ibusy := '0'; -- not busy when idle
|
ibusy := '0'; -- not busy when idle
|
|
|
|
|
-- stop
|
-- stop
|
when stop_a =>
|
when stop_a =>
|
nxt_state := stop_b;
|
nxt_state := stop_b;
|
|
|
when stop_b =>
|
when stop_b =>
|
nxt_state := stop_c;
|
nxt_state := stop_c;
|
|
|
when stop_c =>
|
when stop_c =>
|
-- nxt_state := stop_d;
|
-- nxt_state := stop_d;
|
|
|
-- when stop_d =>
|
-- when stop_d =>
|
nxt_state := idle;
|
nxt_state := idle;
|
ibusy := '0'; -- not busy when idle
|
ibusy := '0'; -- not busy when idle
|
|
|
-- read
|
-- read
|
when rd_a =>
|
when rd_a =>
|
nxt_state := rd_b;
|
nxt_state := rd_b;
|
|
|
when rd_b =>
|
when rd_b =>
|
nxt_state := rd_c;
|
nxt_state := rd_c;
|
|
|
when rd_c =>
|
when rd_c =>
|
nxt_state := rd_d;
|
nxt_state := rd_d;
|
store_sda := '1';
|
store_sda := '1';
|
|
|
when rd_d =>
|
when rd_d =>
|
nxt_state := idle;
|
nxt_state := idle;
|
ibusy := '0'; -- not busy when idle
|
ibusy := '0'; -- not busy when idle
|
|
|
-- write
|
-- write
|
when wr_a =>
|
when wr_a =>
|
nxt_state := wr_b;
|
nxt_state := wr_b;
|
|
|
when wr_b =>
|
when wr_b =>
|
nxt_state := wr_c;
|
nxt_state := wr_c;
|
|
|
when wr_c =>
|
when wr_c =>
|
nxt_state := wr_d;
|
nxt_state := wr_d;
|
|
|
when wr_d =>
|
when wr_d =>
|
nxt_state := idle;
|
nxt_state := idle;
|
ibusy := '0'; -- not busy when idle
|
ibusy := '0'; -- not busy when idle
|
|
|
end case;
|
end case;
|
|
|
-- generate regs
|
-- generate regs
|
if (nReset = '0') then
|
if (nReset = '0') then
|
state <= idle;
|
state <= idle;
|
cmd_ack <= '0';
|
cmd_ack <= '0';
|
busy <= '0';
|
busy <= '0';
|
txd <= '0';
|
txd <= '0';
|
Dout <= '0';
|
Dout <= '0';
|
elsif (clk'event and clk = '1') then
|
elsif (clk'event and clk = '1') then
|
if (clk_en = '1') then
|
if (clk_en = '1') then
|
state <= nxt_state;
|
state <= nxt_state;
|
busy <= ibusy;
|
busy <= ibusy;
|
|
|
txd <= itxd;
|
txd <= itxd;
|
if (store_sda = '1') then
|
if (store_sda = '1') then
|
Dout <= SDA;
|
Dout <= SDA;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
cmd_ack <= icmd_ack and clk_en;
|
cmd_ack <= icmd_ack and clk_en;
|
end if;
|
end if;
|
end process nxt_state_decoder;
|
end process nxt_state_decoder;
|
|
|
--
|
--
|
-- convert states to SCL and SDA signals
|
-- convert states to SCL and SDA signals
|
--
|
--
|
output_decoder: process (clk, nReset, state)
|
output_decoder: process (clk, nReset, state)
|
variable iscl, isda : std_logic;
|
variable iscl, isda : std_logic;
|
begin
|
begin
|
case (state) is
|
case (state) is
|
when idle =>
|
when idle =>
|
iscl := SCLo; -- keep SCL in same state
|
iscl := SCLo; -- keep SCL in same state
|
isda := SDA; -- keep SDA in same state
|
isda := SDA; -- keep SDA in same state
|
|
|
-- start
|
-- start
|
when start_a =>
|
when start_a =>
|
iscl := SCLo; -- keep SCL in same state (for repeated start)
|
iscl := SCLo; -- keep SCL in same state (for repeated start)
|
isda := '1'; -- set SDA high
|
isda := '1'; -- set SDA high
|
|
|
when start_b =>
|
when start_b =>
|
iscl := '1'; -- set SCL high
|
iscl := '1'; -- set SCL high
|
isda := '1'; -- keep SDA high
|
isda := '1'; -- keep SDA high
|
|
|
when start_c =>
|
when start_c =>
|
iscl := '1'; -- keep SCL high
|
iscl := '1'; -- keep SCL high
|
isda := '0'; -- sel SDA low
|
isda := '0'; -- sel SDA low
|
|
|
when start_d =>
|
when start_d =>
|
iscl := '0'; -- set SCL low
|
iscl := '0'; -- set SCL low
|
isda := '0'; -- keep SDA low
|
isda := '0'; -- keep SDA low
|
|
|
-- stop
|
-- stop
|
when stop_a =>
|
when stop_a =>
|
iscl := '0'; -- keep SCL disabled
|
iscl := '0'; -- keep SCL disabled
|
isda := '0'; -- set SDA low
|
isda := '0'; -- set SDA low
|
|
|
when stop_b =>
|
when stop_b =>
|
iscl := '1'; -- set SCL high
|
iscl := '1'; -- set SCL high
|
isda := '0'; -- keep SDA low
|
isda := '0'; -- keep SDA low
|
|
|
when stop_c =>
|
when stop_c =>
|
iscl := '1'; -- keep SCL high
|
iscl := '1'; -- keep SCL high
|
isda := '1'; -- set SDA high
|
isda := '1'; -- set SDA high
|
|
|
-- write
|
-- write
|
when wr_a =>
|
when wr_a =>
|
iscl := '0'; -- keep SCL low
|
iscl := '0'; -- keep SCL low
|
-- isda := txd; -- set SDA
|
-- isda := txd; -- set SDA
|
isda := Din;
|
isda := Din;
|
|
|
when wr_b =>
|
when wr_b =>
|
iscl := '1'; -- set SCL high
|
iscl := '1'; -- set SCL high
|
-- isda := txd; -- set SDA
|
-- isda := txd; -- set SDA
|
isda := Din;
|
isda := Din;
|
|
|
when wr_c =>
|
when wr_c =>
|
iscl := '1'; -- keep SCL high
|
iscl := '1'; -- keep SCL high
|
-- isda := txd; -- set SDA
|
-- isda := txd; -- set SDA
|
isda := Din;
|
isda := Din;
|
|
|
when wr_d =>
|
when wr_d =>
|
iscl := '0'; -- set SCL low
|
iscl := '0'; -- set SCL low
|
-- isda := txd; -- set SDA
|
-- isda := txd; -- set SDA
|
isda := Din;
|
isda := Din;
|
|
|
-- read
|
-- read
|
when rd_a =>
|
when rd_a =>
|
iscl := '0'; -- keep SCL low
|
iscl := '0'; -- keep SCL low
|
isda := '1'; -- tri-state SDA
|
isda := '1'; -- tri-state SDA
|
|
|
when rd_b =>
|
when rd_b =>
|
iscl := '1'; -- set SCL high
|
iscl := '1'; -- set SCL high
|
isda := '1'; -- tri-state SDA
|
isda := '1'; -- tri-state SDA
|
|
|
when rd_c =>
|
when rd_c =>
|
iscl := '1'; -- keep SCL high
|
iscl := '1'; -- keep SCL high
|
isda := '1'; -- tri-state SDA
|
isda := '1'; -- tri-state SDA
|
|
|
when rd_d =>
|
when rd_d =>
|
iscl := '0'; -- set SCL low
|
iscl := '0'; -- set SCL low
|
isda := '1'; -- tri-state SDA
|
isda := '1'; -- tri-state SDA
|
end case;
|
end case;
|
|
|
-- generate registers
|
-- generate registers
|
if (nReset = '0') then
|
if (nReset = '0') then
|
SCLo <= '1';
|
SCLo <= '1';
|
SDAo <= '1';
|
SDAo <= '1';
|
elsif (clk'event and clk = '1') then
|
elsif (clk'event and clk = '1') then
|
if (clk_en = '1') then
|
if (clk_en = '1') then
|
SCLo <= iscl;
|
SCLo <= iscl;
|
SDAo <= isda;
|
SDAo <= isda;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process output_decoder;
|
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)
|
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)
|
SDA <= '0' when (SDAo = '0') else 'Z'; -- since SDA is externally pulled-up convert a '1' to a 'Z'(tri-state)
|
-- SCL <= SCLo;
|
-- SCL <= SCLo;
|
-- SDA <= SDAo;
|
-- SDA <= SDAo;
|
|
|
end architecture structural;
|
end architecture structural;
|
|
|
|
|
|
|
|
|
|
|