LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY i2c_slave IS
GENERIC (
WR_OP_MODE: STD_LOGIC :='1'
);
PORT (
----------I2C Bus--------
scl : IN STD_LOGIC ;----I2C bus clk
sda : INOUT STD_LOGIC ;
---------sys clk----add
sys_clk : IN std_logic;
reset : IN STD_LOGIC ;
---------Logic Out-------
i2c_addr : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
i2c_data_out : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
wrd : OUT STD_LOGIC ; ---0 write 1 read
wrd_en : OUT STD_LOGIC ;---1 active
i2c_scl_out : OUT STD_LOGIC ;----falling edge
---------Logic In-------
i2c_data_in : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
--------dv_id in--------
dv_id_in : IN STD_LOGIC_VECTOR(3 DOWNTO 0)
);
END i2c_slave;
ARCHITECTURE beh OF i2c_slave IS
CONSTANT RESET_ACTIVE : STD_LOGIC := '0';
CONSTANT IDLE : STD_LOGIC_VECTOR :="0001"; ----Grad code
CONSTANT HEADER : STD_LOGIC_VECTOR :="0011"; CONSTANT ACK_HEADER : STD_LOGIC_VECTOR :="0010"; CONSTANT RCV_REG_ADDR : STD_LOGIC_VECTOR :="0110"; CONSTANT ACK_REG_ADDR : STD_LOGIC_VECTOR :="0111"; CONSTANT RCV_DATA : STD_LOGIC_VECTOR :="0101"; CONSTANT ACK_DATA : STD_LOGIC_VECTOR :="0100"; CONSTANT XMIT_DATA : STD_LOGIC_VECTOR :="1010"; CONSTANT WAIT_ACK : STD_LOGIC_VECTOR :="1011";
----bit counter constant
CONSTANT CNT_DONE : STD_LOGIC_VECTOR :="0111";
---i2c signal
SIGNAL sda_in : STD_LOGIC ;
SIGNAL detect_start,detect_stop : STD_LOGIC;
sIGNAL state : STD_LOGIC_VECTOR(3 DOWNTO 0); ----bit counter 0 to 7
SIGNAL bit_cnt : STD_LOGIC_VECTOR(3 DOWNTO 0); SIGNAL bit_cnt_ld,bit_cnt_en : STD_LOGIC ;
SIGNAL addr_match : STD_LOGIC ;
---header data
SIGNAL i2c_header : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL i2c_header_en : STD_LOGIC;
---shift data
SIGNAL i2c_shift_data : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL i2c_shift_en : STD_LOGIC ;
---addr
SIGNAL addr_flag : STD_LOGIC ;
SIGNAL addr_reg : STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL get_data_flag : STD_LOGIC ;
----slave_sda
SIGNAL slave_sda : STD_LOGIC ;
SIGNAL sda_dir : STD_LOGIC ;
---load data
SIGNAL load_data_reg_tem : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL load_data_flag,load_data_flag_dl : STD_LOGIC ; SIGNAL load_data_en : STD_LOGIC ;
SIGNAL shift_out : STD_LOGIC ;
--wrd_en
SIGNAL wrd_en_reg,wrd_en_reg_dl : STD_LOGIC;
signal scl_reg : std_logic;
signal scl_reg_shift : std_logic_vector(5 downto 0);
BEGIN
------------jitter -----------------
gen_scl_reg : PROCESS (sys_clk,reset) IS
BEGIN
IF (reset=RESET_ACTIVE) THEN
scl_reg<='1';
scl_reg_shift<=(others=>'1');
ELSIF (sys_clk'EVENT AND sys_clk='1') THEN
scl_reg_shift<=scl_reg_shift(4 downto 0)&scl;
if scl_reg_shift(5 downto 0)="111111" then
scl_reg<='1';
elsif scl_reg_shift(5 downto 0)="000000" then
scl_reg<='0';
else
scl_reg<=scl_reg;
end if;
END IF;
END PROCESS gen_scl_reg;
--************************Get Out**************************
i2c_addr<=addr_reg;
i2c_data_out<=i2c_shift_data;
wrd<=i2c_header(0);
--wrd_en<=wrd_en_reg AND wrd_en_reg_dl; wrd_en<=wrd_en_reg;
i2c_scl_out<=scl_reg;
gen_sda : PROCESS (sda_dir,slave_sda,sda) IS BEGIN
IF (sda_dir='1') THEN
sda<=slave_sda;
ELSE
sda_in<=sda;
sda<='Z';
END IF;
END PROCESS gen_sda;
wrd_en_reg<=get_data_flag OR load_data_flag;
-- ************************ START/STOP Detect Process ************************
-- This process detects the start and stop conditions. -- by using SDA as a clock
-------------------------------------
start_det : PROCESS (sda_in,reset) IS
BEGIN
IF (reset=RESET_ACTIVE OR state=HEADER) THEN
detect_start<='0';
--ELSIF (sda'EVENT AND sda='0') THEN
ELSIF (sda'EVENT AND sda='0') THEN---change by lq 3.5
IF (scl_reg='1') THEN ---or scl='1'??
detect_start<='1';
ELSE
detect_start<='0';
END IF;
END IF;
END PROCESS start_det;
stop_det : PROCESS (sda_in,reset,detect_start) IS BEGIN
IF (reset=RESET_ACTIVE OR detect_start='1') THEN
detect_stop<='0';
ELSIF (sda'EVENT AND sda/='0') THEN----
IF (scl_reg='1') THEN ---or scl='1'??
detect_stop<='1';
ELSE
detect_stop<='0';
END IF;
END IF;
END PROCESS stop_det;
--******************I2C Header Process**************** --i2c_header_en<='1' WHEN (detect_start='1' OR state=HEADER) ELSE '0';
i2c_header_en<='1' WHEN (state=HEADER) ELSE '0';
gen_i2cheader : PROCESS (reset,scl_reg,detect_stop) IS BEGIN
IF (reset=RESET_ACTIVE OR detect_stop='1') THEN
i2c_header<=( OTHERS =>'0');----------------?????
ELSIF (scl_reg'EVENT AND scl_reg='1') THEN -----rising_edge
IF (i2c_header_en='1') THEN
i2c_header<=i2c_header(6 DOWNTO 0)&sda_in;
END IF;
END IF;
END PROCESS gen_i2cheader;
--******************Bit Counter Process******************
gen_bit_cnter : PROCESS (reset,scl_reg) IS
BEGIN
IF (reset=RESET_ACTIVE) THEN
bit_cnt<=( OTHERS =>'0');
ELSIF (scl_reg'EVENT AND scl_reg='0') THEN -----falling_edge
IF (bit_cnt_ld='1') THEN
bit_cnt<=( OTHERS =>'0');
ELSIF (bit_cnt_en='1') THEN
bit_cnt<=bit_cnt+1;
ELSE
bit_cnt<=( OTHERS =>'0');
END IF;
END IF;
END PROCESS gen_bit_cnter;
bit_cnt_ld<='1' WHEN (state=IDLE) OR (state=ACK_HEADER) OR (state=ACK_REG_ADDR)
OR (state=ACK_DATA) OR (state=WAIT_ACK) OR (detect_start='1')
ELSE '0';
bit_cnt_en<='1' WHEN (state=HEADER) OR (state=RCV_REG_ADDR) OR (state=RCV_DATA)
OR (state=XMIT_DATA) ELSE '0';
--*******************Addr Match Process****************** addr_match<='1' WHEN i2c_header(7 DOWNTO 1)=("110"&dv_id_in) ELSE '0';
--******************Shift data Process******************* get_shift_data : PROCESS (reset,scl_reg) IS
BEGIN
IF (reset=RESET_ACTIVE) THEN
i2c_shift_data<=(OTHERS =>'0');
ELSIF (scl_reg'EVENT AND scl_reg='1') THEN---change by lq
IF (i2c_shift_en='1') THEN
i2c_shift_data<=i2c_shift_data(6 DOWNTO 0)&sda_in;
END IF;
END IF;
END PROCESS get_shift_data;
i2c_shift_en<='1' WHEN (state=RCV_REG_ADDR) OR (state=RCV_DATA) ELSE '0';
--******************Get addr Process****************** addr_flag<='1' WHEN state=ACK_REG_ADDR ELSE '0'; get_addr_reg : PROCESS (reset,scl_reg) IS
BEGIN
IF (reset=RESET_ACTIVE) THEN
addr_reg<=(OTHERS =>'0');
ELSIF (scl_reg'EVENT AND scl_reg='0') THEN
IF (addr_flag='1') THEN
addr_reg<=i2c_shift_data;
END IF;
END IF;
END PROCESS get_addr_reg;
get_data_flag<='1' WHEN state=ACK_DATA ELSE '0'; --******************Load Data Process**************** gen_load : PROCESS (scl_reg,reset) IS
BEGIN
IF (reset=RESET_ACTIVE) THEN
load_data_reg_tem<=( OTHERS =>'0');
ELSIF (scl_reg'EVENT AND scl_reg='0') THEN
IF (load_data_flag='1') THEN
load_data_reg_tem<=i2c_data_in;
ELSIF (load_data_en='1') THEN
load_data_reg_tem<=load_data_reg_tem(6 DOWNTO 0)&load_data_reg_tem(7);
END IF;
END IF;
END PROCESS gen_load;
--shift_out<=load_data_reg_tem(7) WHEN ((load_data_en='1') AND (load_data_flag_dl/='1'))
ELSE i2c_data_in(7);
shift_out<=load_data_reg_tem(7) ;-- WHEN ((load_data_en='1') AND (load_data_flag_dl/='1'))
ELSE '0';
load_data_en<='1' WHEN (state=XMIT_DATA) ELSE '0';
load_data_flag<='1' WHEN ((state=ACK_HEADER) AND (i2c_header(0)='1') AND
(addr_match='1')) ELSE '0';
get_load_flag_dl : PROCESS (reset,scl_reg) IS BEGIN
IF (reset=RESET_ACTIVE) THEN
load_data_flag_dl<='0';
ELSIF (scl_reg'EVENT AND scl_reg='0') THEN
load_data_flag_dl<=load_data_flag;
END IF;
END PROCESS get_load_flag_dl;
--***************Shift out Process********************** slave_sda<='0' WHEN ((state=ACK_HEADER) AND (addr_match='1')) OR
(state=ACK_REG_ADDR) OR (state=ACK_DATA)
ELSE shift_out WHEN (state=XMIT_DATA)
ELSE '1';
sda_dir<='1' WHEN ((state=ACK_HEADER) AND (addr_match='1')) OR
(state=ACK_REG_ADDR) OR (state=ACK_DATA)
OR (state=XMIT_DATA) ELSE '0';
-- ************** Main State Machine Process ************
state_machine : PROCESS (scl_reg,reset,detect_stop) IS BEGIN
IF (reset=RESET_ACTIVE OR detect_stop='1') THEN
state <= IDLE;
ELSIF (scl_reg'EVENT AND scl_reg='0') THEN
CASE (state) IS
---------------IDLE STATE--------
WHEN IDLE => IF (detect_start='1') THEN
state<=HEADER;
END IF;
---------------HEADER STATE-------
WHEN HEADER =>IF (bit_cnt=CNT_DONE) THEN
state<=ACK_HEADER;
END IF;
---------------ACK_HEADER STATE---
WHEN ACK_HEADER => IF (addr_match='1') THEN
IF (i2c_header(0)='0') THEN---write
state<=RCV_REG_ADDR;
ELSE ----read
state<=XMIT_DATA;
END IF;
ELSE
state<=IDLE;
END IF;
--------------- RCV_REG_ADDR STATE---
WHEN RCV_REG_ADDR => IF (detect_start='1') THEN
state<=HEADER;
ELSIF (bit_cnt=CNT_DONE) THEN
state<=ACK_REG_ADDR;
END IF;
----------------ACK_REG_ADDR STATE--------
WHEN ACK_REG_ADDR => state<=RCV_DATA;
--------------- RCV_DATA STATE--------
WHEN RCV_DATA => IF (detect_start='1') THEN
state<=HEADER;
ELSIF (bit_cnt=CNT_DONE) THEN
state<=ACK_DATA;
END IF;
--------------- ACK_DATA STATE-------
WHEN ACK_DATA => IF (WR_OP_MODE='1') THEN
state<=RCV_REG_ADDR;
ELSE
state<=RCV_DATA;
END IF;
--------------- XMIT_DATA STATE------
WHEN XMIT_DATA => IF (detect_start='1') THEN
state<=HEADER;
ELSIF (bit_cnt=CNT_DONE) THEN
state<=WAIT_ACK;
END IF;
--------------- WAIT_ACK STATE-------
WHEN WAIT_ACK => IF (sda_in='0') THEN
state<= XMIT_DATA;
ELSE
state<= IDLE;
END IF;
WHEN OTHERS => state<= IDLE;
-- i2c_header_en<='0';
END CASE;
END IF;
END PROCESS state_machine;
END beh;