i2cs_rx.vhd


1
------------------------------------------------------------------------------
2
-- i2c slave receiver
3
------------------------------------------------------------------------------
4
-- Intended target: Xilinx CoolRunner-II CPLD  (XC2C64A)
5
-- Development tools: XILINX ISE 7.1i webpack
6
-- Author:  DMITRY PETROV
7
-- Notes:
8
-- Date:     11-09-2005
9
-- Revision: 1.0
10
------------------------------------------------------------------------------
11
-- This code implements i2c slave which is able to receive a data byte.
12
 
13
-- i2c message has 3 parts:
14
-- <Device Address> 22h
15
-- <Sub Address> 00h
16
-- <Data byte> XX 
17
-- If Device and Sub Addresses are matched the data byte will be accepted.
18
19
-- Because of SCL line used as clock for i2c state machine, slow SCL changes 
20
-- will make noise and invalid data reception. 
21
22
-- To avoid noise of slow SCL - usualy used an external CLOCK, for 
23
-- clocking all modules but it will take some amount of CPLD's macrocells.
24
25
-- Another way is to use an SCHMITT TRIGGER on SCL and SDA. 
26
-- Forexample XILINX CoolRunner-II CPLD, has SCHMITT TRIGGER on it's I/O.
27
-- By default this function is deactivated, PLEASE ACTIVATE IT !
28
29
-- If your PLD have no SCHMITT TRIGGER function, you may use solution wich 
30
-- require 2 resistors and aditional output pin. 
31
-- Here's an old Xilinx app note about it: 
32
-- http://www.xilinx.com/xcell/xl19/xl19-34.pdf 
33
-- ===========================================================================
34
-- DISCLAIMER: This code is FREEWARE which is provided on an “as is” basis, 
35
-- YOU MAY USE IT ON YOUR OWN RISK, WITHOUT ANY WARRANTY. 
36
-- ===========================================================================d
37
38
library IEEE;
39
use IEEE.STD_LOGIC_1164.ALL;
40
use IEEE.STD_LOGIC_ARITH.ALL;
41
use IEEE.STD_LOGIC_UNSIGNED.ALL;
42
43
------------------------------------------------------------------------------
44
entity i2cs_rx is
45
  generic(
46
    WR       : std_logic:='0';
47
    DADDR    : std_logic_vector(6 downto 0); --:= "0010001";       -- 11h (22h) device address
48
    ADDR    : std_logic_vector(7 downto 0)  --:= "00000000"       -- 00h      sub address    
49
  );
50
  port(
51
    RST    : in std_logic;
52
    SCL    : in std_logic;
53
    SDA    : inout std_logic;
54
    DOUT     : out std_logic_vector(7 downto 0)         -- Recepted over i2c data byte
55
  );
56
  --SCHMITT TRIGGER activation (folowing 3 strings should be uncommented)
57
  --attribute SCHMITT_TRIGGER: string; 
58
  --attribute SCHMITT_TRIGGER of SCL: signal is "true"; 
59
  --attribute SCHMITT_TRIGGER of SDA: signal is "true";
60
end i2cs_rx;
61
62
------------------------------------------------------------------------------
63
architecture Behavioral of i2cs_rx is
64
  signal DOUT_S: std_logic_vector(7 downto 0);
65
  signal SDA_IN, START, START_RST, STOP, ACTIVE, ACK  : std_logic;
66
  signal SHIFTREG  : std_logic_vector(8 downto 0);
67
  signal STATE : std_logic_vector(1 downto 0);    -- 00 - iddle state  
68
                                      -- 01 - DADDR  compare
69
                                      -- 10 - ADDR compare
70
                                      -- 11 - DATA read
71
begin
72
73
------------------------------------------------------------------------------
74
-- start condition detection, method 1 ( good noise tolerance )
75
76
   process (SDA_IN, START_RST)
77
   begin
78
      if (START_RST = '1') then
79
         START <= '0';    
80
      elsif (SDA_IN'event and SDA_IN = '0') then
81
         START <= scl;    
82
      end if;
83
   end process;
84
85
   process (SCL, START, STOP)
86
   begin
87
    if (SCL'event and SCL = '0') then
88
         START_RST <= START;    
89
      end if;
90
   end process;
91
92
------------------------------------------------------------------------------
93
-- start condition detection, method 2 ( simple - but week against noise )
94
--process (RST, SCL, SDA_IN)
95
--begin
96
--  if RST = '0' or SCL = '0' then
97
--    START <= '0';
98
--  elsif SCL = '1' and SDA_IN = '0' and SDA_IN'event then
99
--    START <= '1';
100
--  end if;
101
--end process;
102
103
------------------------------------------------------------------------------
104
-- stop condition detection
105
process (RST, SCL, SDA_IN, START)
106
begin
107
  if RST = '0' or SCL = '0' or START='1' then
108
    STOP <= '0';
109
  elsif SCL = '1' and SDA_IN = '1' and SDA_IN'event then
110
    STOP <= '1';
111
  end if;
112
end process;
113
114
------------------------------------------------------------------------------
115
-- "active communication" signal 
116
process (RST, STOP, START)
117
begin
118
  if RST = '0' or STOP = '1' then   --or (SHIFTREG="000000001" and ACK = '0' and SCL='1' and SCL'event) 
119
    ACTIVE <= '0';
120
  elsif START = '0' and START'event then
121
    ACTIVE <= '1';
122
  end if;
123
end process;
124
125
------------------------------------------------------------------------------
126
-- RX data shifter
127
process (RST, ACTIVE, ACK, SCL, SDA_IN)
128
begin 
129
if RST = '0' or ACTIVE = '0' then
130
  SHIFTREG <= "000000001";  
131
elsif SCL'event and SCL = '1' then
132
  if ACK = '1' then
133
    SHIFTREG <= "000000001";
134
  else
135
    SHIFTREG(8 downto 0) <= SHIFTREG(7 downto 0) & SDA_IN;
136
  end if;
137
end if;                
138
end process;
139
140
------------------------------------------------------------------------------
141
-- I2C data read
142
process (RST, STATE, ACK, SHIFTREG)
143
begin
144
if RST = '0' then
145
  DOUT_S <= "00000000";
146
elsif STATE="11" and ACK='1' and ACK'event then 
147
  DOUT_S <= SHIFTREG(7 downto 0);
148
end if;
149
end process; 
150
151
------------------------------------------------------------------------------
152
-- ACK
153
process (RST, SCL, SHIFTREG, STATE, ACTIVE)
154
begin
155
if RST = '0' or ACTIVE = '0' then
156
  ACK <= '0';
157
  STATE <= "00";
158
elsif SCL='0' and SCL'event then 
159
  if SHIFTREG(8) = '1' and STATE/="11" then
160
    STATE <= STATE + 1;
161
    if ((STATE="00" and SHIFTREG(7 downto 0) = DADDR & WR) or (STATE="01" and SHIFTREG(7 downto 0) = ADDR) or STATE="10") then 
162
      ACK <= '1';
163
    else
164
      STATE <= "11";
165
    end if;
166
  else
167
     ACK <= '0';
168
  end if;
169
end if;
170
end process;
171
172
------------------------------------------------------------------------------
173
-- ACK responce
174
SDA_IN <= SDA;
175
SDA <= '0' when ACK = '1' else 'Z';
176
177
------------------------------------------------------------------------------
178
DOUT(7 downto 0) <= DOUT_S(7 downto 0);
179
180
end Behavioral;
181
------------------------------------------------------------------------------