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 | ------------------------------------------------------------------------------
|