1 |
2 |
dimamali |
---------------------------------------------------------------------
|
2 |
|
|
---- ----
|
3 |
|
|
---- WISHBONE revB2 I2C Master Core; bit-controller ----
|
4 |
|
|
---- ----
|
5 |
|
|
---- ----
|
6 |
|
|
---- Author: Richard Herveille ----
|
7 |
|
|
---- richard@asics.ws ----
|
8 |
|
|
---- www.asics.ws ----
|
9 |
|
|
---- ----
|
10 |
|
|
---- Downloaded from: http://www.opencores.org/projects/i2c/ ----
|
11 |
|
|
---- ----
|
12 |
|
|
---------------------------------------------------------------------
|
13 |
|
|
---- ----
|
14 |
|
|
---- Copyright (C) 2000 Richard Herveille ----
|
15 |
|
|
---- richard@asics.ws ----
|
16 |
|
|
---- ----
|
17 |
|
|
---- This source file may be used and distributed without ----
|
18 |
|
|
---- restriction provided that this copyright statement is not ----
|
19 |
|
|
---- removed from the file and that any derivative work contains ----
|
20 |
|
|
---- the original copyright notice and the associated disclaimer.----
|
21 |
|
|
---- ----
|
22 |
|
|
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ----
|
23 |
|
|
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ----
|
24 |
|
|
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ----
|
25 |
|
|
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ----
|
26 |
|
|
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ----
|
27 |
|
|
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ----
|
28 |
|
|
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ----
|
29 |
|
|
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ----
|
30 |
|
|
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ----
|
31 |
|
|
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ----
|
32 |
|
|
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ----
|
33 |
|
|
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ----
|
34 |
|
|
---- POSSIBILITY OF SUCH DAMAGE. ----
|
35 |
|
|
---- ----
|
36 |
|
|
---------------------------------------------------------------------
|
37 |
|
|
|
38 |
|
|
-- CVS Log
|
39 |
|
|
--
|
40 |
|
|
-- $Id: i2c_master_bit_ctrl.vhd,v 1.14 2006/10/11 12:10:13 rherveille Exp $
|
41 |
|
|
--
|
42 |
|
|
-- $Date: 2006/10/11 12:10:13 $
|
43 |
|
|
-- $Revision: 1.14 $
|
44 |
|
|
-- $Author: rherveille $
|
45 |
|
|
-- $Locker: $
|
46 |
|
|
-- $State: Exp $
|
47 |
|
|
--
|
48 |
|
|
-- Change History:
|
49 |
|
|
-- $Log: i2c_master_bit_ctrl.vhd,v $
|
50 |
|
|
-- Revision 1.14 2006/10/11 12:10:13 rherveille
|
51 |
|
|
-- Added missing semicolons ';' on endif
|
52 |
|
|
--
|
53 |
|
|
-- Revision 1.13 2006/10/06 10:48:24 rherveille
|
54 |
|
|
-- fixed short scl high pulse after clock stretch
|
55 |
|
|
--
|
56 |
|
|
-- Revision 1.12 2004/05/07 11:53:31 rherveille
|
57 |
|
|
-- Fixed previous fix :) Made a variable vs signal mistake.
|
58 |
|
|
--
|
59 |
|
|
-- Revision 1.11 2004/05/07 11:04:00 rherveille
|
60 |
|
|
-- Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit.
|
61 |
|
|
--
|
62 |
|
|
-- Revision 1.10 2004/02/27 07:49:43 rherveille
|
63 |
|
|
-- Fixed a bug in the arbitration-lost signal generation. VHDL version only.
|
64 |
|
|
--
|
65 |
|
|
-- Revision 1.9 2003/08/12 14:48:37 rherveille
|
66 |
|
|
-- Forgot an 'end if' :-/
|
67 |
|
|
--
|
68 |
|
|
-- Revision 1.8 2003/08/09 07:01:13 rherveille
|
69 |
|
|
-- Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line.
|
70 |
|
|
-- Fixed a potential bug in the byte controller's host-acknowledge generation.
|
71 |
|
|
--
|
72 |
|
|
-- Revision 1.7 2003/02/05 00:06:02 rherveille
|
73 |
|
|
-- Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles.
|
74 |
|
|
--
|
75 |
|
|
-- Revision 1.6 2003/02/01 02:03:06 rherveille
|
76 |
|
|
-- Fixed a few 'arbitration lost' bugs. VHDL version only.
|
77 |
|
|
--
|
78 |
|
|
-- Revision 1.5 2002/12/26 16:05:47 rherveille
|
79 |
|
|
-- Core is now a Multimaster I2C controller.
|
80 |
|
|
--
|
81 |
|
|
-- Revision 1.4 2002/11/30 22:24:37 rherveille
|
82 |
|
|
-- Cleaned up code
|
83 |
|
|
--
|
84 |
|
|
-- Revision 1.3 2002/10/30 18:09:53 rherveille
|
85 |
|
|
-- Fixed some reported minor start/stop generation timing issuess.
|
86 |
|
|
--
|
87 |
|
|
-- Revision 1.2 2002/06/15 07:37:04 rherveille
|
88 |
|
|
-- Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment.
|
89 |
|
|
--
|
90 |
|
|
-- Revision 1.1 2001/11/05 12:02:33 rherveille
|
91 |
|
|
-- Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version.
|
92 |
|
|
-- Code updated, is now up-to-date to doc. rev.0.4.
|
93 |
|
|
-- Added headers.
|
94 |
|
|
--
|
95 |
|
|
-- Modified by Jan Andersson (jan@gaisler.com):
|
96 |
|
|
-- * Added two start states to fulfill Set-up time for
|
97 |
|
|
-- repeated START condition.
|
98 |
|
|
-- * Modified synchronization of SCL and SDA. START and STOP detection
|
99 |
|
|
-- is now performed after a two stage synchronizer and is also
|
100 |
|
|
-- filtered.
|
101 |
|
|
-- * Changed evaluation order of 'slave_wait', 'en' and 'cnt' in
|
102 |
|
|
-- generation of clk_en signal to prevent clk_en assertion when
|
103 |
|
|
-- slave_wait is asserted.
|
104 |
|
|
-- * Needed to differentiate between slave clock stretching and master
|
105 |
|
|
-- clock synchronization.
|
106 |
|
|
-- * Added register s_state which contains the next state in case
|
107 |
|
|
-- of clock synchronization
|
108 |
|
|
--
|
109 |
|
|
-------------------------------------
|
110 |
|
|
-- Bit controller section
|
111 |
|
|
------------------------------------
|
112 |
|
|
--
|
113 |
|
|
-- Translate simple commands into SCL/SDA transitions
|
114 |
|
|
-- Each command has 5 states, A/B/C/D/idle
|
115 |
|
|
--
|
116 |
|
|
-- start: SCL ~~~~~~~~~~~~~~\____
|
117 |
|
|
-- SDA XX/~~~~~~~\______
|
118 |
|
|
-- x | A | B | C | D | i
|
119 |
|
|
--
|
120 |
|
|
-- repstart SCL ______/~~~~~~~\___
|
121 |
|
|
-- SDA __/~~~~~~~\______
|
122 |
|
|
-- x | A | B | C | D | i
|
123 |
|
|
--
|
124 |
|
|
-- stop SCL _______/~~~~~~~~~~~
|
125 |
|
|
-- SDA ==\___________/~~~~~
|
126 |
|
|
-- x | A | B | C | D | i
|
127 |
|
|
--
|
128 |
|
|
--- write SCL ______/~~~~~~~\____
|
129 |
|
|
-- SDA XXX===============XX
|
130 |
|
|
-- x | A | B | C | D | i
|
131 |
|
|
--
|
132 |
|
|
--- read SCL ______/~~~~~~~\____
|
133 |
|
|
-- SDA XXXXXXX=XXXXXXXXXXX
|
134 |
|
|
-- x | A | B | C | D | i
|
135 |
|
|
--
|
136 |
|
|
|
137 |
|
|
-- Timing: Normal mode Fast mode
|
138 |
|
|
-----------------------------------------------------------------
|
139 |
|
|
-- Fscl 100KHz 400KHz
|
140 |
|
|
-- Th_scl 4.0us 0.6us High period of SCL
|
141 |
|
|
-- Tl_scl 4.7us 1.3us Low period of SCL
|
142 |
|
|
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition
|
143 |
|
|
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon
|
144 |
|
|
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition
|
145 |
|
|
--
|
146 |
|
|
|
147 |
|
|
library ieee;
|
148 |
|
|
use ieee.std_logic_1164.all;
|
149 |
|
|
library grlib;
|
150 |
|
|
use grlib.stdlib.all;
|
151 |
|
|
|
152 |
|
|
entity i2c_master_bit_ctrl is
|
153 |
|
|
port (
|
154 |
|
|
clk : in std_logic;
|
155 |
|
|
rst : in std_logic;
|
156 |
|
|
nReset : in std_logic;
|
157 |
|
|
ena : in std_logic; -- core enable signal
|
158 |
|
|
|
159 |
|
|
clk_cnt : in std_logic_vector(15 downto 0); -- clock prescale value
|
160 |
|
|
|
161 |
|
|
cmd : in std_logic_vector(3 downto 0);
|
162 |
|
|
cmd_ack : out std_logic; -- command completed
|
163 |
|
|
busy : out std_logic; -- i2c bus busy
|
164 |
|
|
al : out std_logic; -- arbitration lost
|
165 |
|
|
|
166 |
|
|
din : in std_logic;
|
167 |
|
|
dout : out std_logic;
|
168 |
|
|
|
169 |
|
|
-- i2c lines
|
170 |
|
|
scl_i : in std_logic; -- i2c clock line input
|
171 |
|
|
scl_o : out std_logic; -- i2c clock line output
|
172 |
|
|
scl_oen : out std_logic; -- i2c clock line output enable, active low
|
173 |
|
|
sda_i : in std_logic; -- i2c data line input
|
174 |
|
|
sda_o : out std_logic; -- i2c data line output
|
175 |
|
|
sda_oen : out std_logic -- i2c data line output enable, active low
|
176 |
|
|
);
|
177 |
|
|
end entity i2c_master_bit_ctrl;
|
178 |
|
|
|
179 |
|
|
architecture structural of i2c_master_bit_ctrl is
|
180 |
|
|
constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000";
|
181 |
|
|
constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001";
|
182 |
|
|
constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010";
|
183 |
|
|
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100";
|
184 |
|
|
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000";
|
185 |
|
|
|
186 |
|
|
type states is (idle, start_a, start_b, start_c, start_d, start_e, start_f, start_g,
|
187 |
|
|
stop_a, stop_b, stop_c, stop_d, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d);
|
188 |
|
|
signal c_state, s_state : states;
|
189 |
|
|
|
190 |
|
|
signal iscl_oen, isda_oen : std_logic; -- internal I2C lines
|
191 |
|
|
signal disda_oen : std_logic; -- delayed isda_oen
|
192 |
|
|
signal sda_chk : std_logic; -- check SDA status (multi-master arbitration)
|
193 |
|
|
signal dscl_oen : std_logic_vector(1 downto 0); -- delayed scl_oen signal
|
194 |
|
|
signal sSCL, sSDA : std_logic_vector(5 downto 0); -- synchronized SCL and SDA inputs
|
195 |
|
|
signal clk_en, slave_wait : std_logic; -- clock generation signals
|
196 |
|
|
signal ial : std_logic; -- internal arbitration lost signal
|
197 |
|
|
signal cnt : std_logic_vector(15 downto 0); -- clock divider counter (synthesis)
|
198 |
|
|
signal csync : std_logic; -- Need to synchronize clock with other master
|
199 |
|
|
signal slvw_dis : std_logic; -- Slave wait disable;
|
200 |
|
|
|
201 |
|
|
begin
|
202 |
|
|
-- whenever the slave is not ready it can delay the cycle by pulling SCL low
|
203 |
|
|
-- delay scl_oen
|
204 |
|
|
process (clk)
|
205 |
|
|
begin
|
206 |
|
|
if (clk'event and clk = '1') then
|
207 |
|
|
-- Keep SCL output enable values
|
208 |
|
|
dscl_oen <= dscl_oen(0) & iscl_oen;
|
209 |
|
|
-- Disable slave stretch detection when other device drives SCL
|
210 |
|
|
-- H->L (only a master should to this).
|
211 |
|
|
slvw_dis <= (slvw_dis or csync) and dscl_oen(0);
|
212 |
|
|
end if;
|
213 |
|
|
end process;
|
214 |
|
|
-- SCL forced low after master tried to assert, slave is stretching clock
|
215 |
|
|
slave_wait <= dscl_oen(1) and not sSCL(1) and not (slvw_dis or sSCL(4));
|
216 |
|
|
-- SCL HIGH time cut short, master clock synchronization
|
217 |
|
|
csync <= dscl_oen(1) and not sSCL(1) and andv(sSCL(4 downto 2));
|
218 |
|
|
|
219 |
|
|
-- generate clk enable signal
|
220 |
|
|
gen_clken: process(clk, nReset)
|
221 |
|
|
begin
|
222 |
|
|
if (nReset = '0') then
|
223 |
|
|
cnt <= (others => '0');
|
224 |
|
|
clk_en <= '1';
|
225 |
|
|
elsif (clk'event and clk = '1') then
|
226 |
|
|
if (rst = '1') then
|
227 |
|
|
cnt <= (others => '0');
|
228 |
|
|
clk_en <= '1';
|
229 |
|
|
elsif (ena = '0' or csync = '1') then
|
230 |
|
|
cnt <= clk_cnt;
|
231 |
|
|
clk_en <= '1';
|
232 |
|
|
elsif (slave_wait = '1') then
|
233 |
|
|
cnt <= cnt;
|
234 |
|
|
clk_en <= '0';
|
235 |
|
|
elsif (cnt = X"0000") then
|
236 |
|
|
cnt <= clk_cnt;
|
237 |
|
|
clk_en <= '1';
|
238 |
|
|
else
|
239 |
|
|
cnt <= cnt -1;
|
240 |
|
|
clk_en <= '0';
|
241 |
|
|
end if;
|
242 |
|
|
end if;
|
243 |
|
|
end process gen_clken;
|
244 |
|
|
|
245 |
|
|
|
246 |
|
|
-- generate bus status controller
|
247 |
|
|
bus_status_ctrl: block
|
248 |
|
|
--signal dSCL, dSDA : std_logic; -- delayes sSCL and sSDA
|
249 |
|
|
signal sta_condition : std_logic; -- start detected
|
250 |
|
|
signal sto_condition : std_logic; -- stop detected
|
251 |
|
|
signal cmd_stop : std_logic; -- STOP command
|
252 |
|
|
signal ibusy : std_logic; -- internal busy signal
|
253 |
|
|
begin
|
254 |
|
|
-- synchronize SCL and SDA inputs
|
255 |
|
|
synch_scl_sda: process(clk, nReset)
|
256 |
|
|
begin
|
257 |
|
|
if (nReset = '0') then
|
258 |
|
|
sSCL <= (others => '1');
|
259 |
|
|
sSDA <= (others => '1');
|
260 |
|
|
elsif (clk'event and clk = '1') then
|
261 |
|
|
if (rst = '1') then
|
262 |
|
|
sSCL <= (others => '1');
|
263 |
|
|
sSDA <= (others => '1');
|
264 |
|
|
else
|
265 |
|
|
sSCL <= sSCL(4 downto 0) & scl_i;
|
266 |
|
|
sSDA <= sSDA(4 downto 0) & sda_i;
|
267 |
|
|
end if;
|
268 |
|
|
end if;
|
269 |
|
|
end process synch_SCL_SDA;
|
270 |
|
|
|
271 |
|
|
-- detect start condition => detect falling edge on SDA while SCL is high
|
272 |
|
|
-- detect stop condition => detect rising edge on SDA while SCL is high
|
273 |
|
|
detect_sta_sto: process(clk, nReset)
|
274 |
|
|
begin
|
275 |
|
|
if (nReset = '0') then
|
276 |
|
|
sta_condition <= '0';
|
277 |
|
|
sto_condition <= '0';
|
278 |
|
|
elsif (clk'event and clk = '1') then
|
279 |
|
|
if (rst = '1') then
|
280 |
|
|
sta_condition <= '0';
|
281 |
|
|
sto_condition <= '0';
|
282 |
|
|
else
|
283 |
|
|
if sSCL(5 downto 2) = "1111" and sSDA(5 downto 2) = "1100" then
|
284 |
|
|
sta_condition <= '1';
|
285 |
|
|
else
|
286 |
|
|
sta_condition <= '0';
|
287 |
|
|
end if;
|
288 |
|
|
if sSCL(5 downto 2) = "1111" and sSDA(5 downto 2) = "0011" then
|
289 |
|
|
sto_condition <= '1';
|
290 |
|
|
else
|
291 |
|
|
sto_condition <= '0';
|
292 |
|
|
end if;
|
293 |
|
|
end if;
|
294 |
|
|
end if;
|
295 |
|
|
end process detect_sta_sto;
|
296 |
|
|
|
297 |
|
|
-- generate i2c-bus busy signal
|
298 |
|
|
gen_busy: process(clk, nReset)
|
299 |
|
|
begin
|
300 |
|
|
if (nReset = '0') then
|
301 |
|
|
ibusy <= '0';
|
302 |
|
|
elsif (clk'event and clk = '1') then
|
303 |
|
|
if (rst = '1') then
|
304 |
|
|
ibusy <= '0';
|
305 |
|
|
else
|
306 |
|
|
ibusy <= (sta_condition or ibusy) and not sto_condition;
|
307 |
|
|
end if;
|
308 |
|
|
end if;
|
309 |
|
|
end process gen_busy;
|
310 |
|
|
busy <= ibusy;
|
311 |
|
|
|
312 |
|
|
|
313 |
|
|
-- generate arbitration lost signal
|
314 |
|
|
-- aribitration lost when:
|
315 |
|
|
-- 1) master drives SDA high, but the i2c bus is low
|
316 |
|
|
-- 2) stop detected while not requested (detect during 'idle' state)
|
317 |
|
|
gen_al: process(clk, nReset)
|
318 |
|
|
begin
|
319 |
|
|
if (nReset = '0') then
|
320 |
|
|
cmd_stop <= '0';
|
321 |
|
|
ial <= '0';
|
322 |
|
|
disda_oen <= '1';
|
323 |
|
|
elsif (clk'event and clk = '1') then
|
324 |
|
|
if (rst = '1') then
|
325 |
|
|
cmd_stop <= '0';
|
326 |
|
|
ial <= '0';
|
327 |
|
|
disda_oen <= '1';
|
328 |
|
|
else
|
329 |
|
|
if (clk_en = '1') then
|
330 |
|
|
if (cmd = I2C_CMD_STOP) then
|
331 |
|
|
cmd_stop <= '1';
|
332 |
|
|
else
|
333 |
|
|
cmd_stop <= '0';
|
334 |
|
|
end if;
|
335 |
|
|
end if;
|
336 |
|
|
|
337 |
|
|
if (c_state = idle) then
|
338 |
|
|
ial <= (sda_chk and not sSDA(1) and disda_oen);
|
339 |
|
|
else
|
340 |
|
|
ial <= (sda_chk and not sSDA(1) and disda_oen) or
|
341 |
|
|
(sto_condition and not cmd_stop);
|
342 |
|
|
end if;
|
343 |
|
|
disda_oen <= isda_oen;
|
344 |
|
|
end if;
|
345 |
|
|
end if;
|
346 |
|
|
end process gen_al;
|
347 |
|
|
al <= ial;
|
348 |
|
|
|
349 |
|
|
-- generate dout signal, store dout on rising edge of SCL
|
350 |
|
|
gen_dout: process(clk)
|
351 |
|
|
begin
|
352 |
|
|
if (clk'event and clk = '1') then
|
353 |
|
|
if sSCL(3 downto 2) = "01" then
|
354 |
|
|
dout <= sSDA(2);
|
355 |
|
|
end if;
|
356 |
|
|
end if;
|
357 |
|
|
end process gen_dout;
|
358 |
|
|
end block bus_status_ctrl;
|
359 |
|
|
|
360 |
|
|
|
361 |
|
|
-- generate statemachine
|
362 |
|
|
nxt_state_decoder : process (clk, nReset, c_state, cmd)
|
363 |
|
|
begin
|
364 |
|
|
if (nReset = '0') then
|
365 |
|
|
c_state <= idle;
|
366 |
|
|
s_state <= idle;
|
367 |
|
|
cmd_ack <= '0';
|
368 |
|
|
iscl_oen <= '1';
|
369 |
|
|
isda_oen <= '1';
|
370 |
|
|
sda_chk <= '0';
|
371 |
|
|
elsif (clk'event and clk = '1') then
|
372 |
|
|
if (rst = '1' or ial = '1') then
|
373 |
|
|
c_state <= idle;
|
374 |
|
|
cmd_ack <= '0';
|
375 |
|
|
iscl_oen <= '1';
|
376 |
|
|
isda_oen <= '1';
|
377 |
|
|
sda_chk <= '0';
|
378 |
|
|
elsif csync = '1' then
|
379 |
|
|
c_state <= s_state;
|
380 |
|
|
else
|
381 |
|
|
|
382 |
|
|
cmd_ack <= '0'; -- default no acknowledge
|
383 |
|
|
|
384 |
|
|
-- csync is always '0' here, but including it in the expression
|
385 |
|
|
-- appears to let some compilers optimize the design more...
|
386 |
|
|
if (clk_en or csync) = '1' then
|
387 |
|
|
|
388 |
|
|
case (c_state) is
|
389 |
|
|
-- idle
|
390 |
|
|
when idle =>
|
391 |
|
|
case cmd is
|
392 |
|
|
when I2C_CMD_START => c_state <= start_a;
|
393 |
|
|
s_state <= start_g;
|
394 |
|
|
when I2C_CMD_STOP => c_state <= stop_a;
|
395 |
|
|
s_state <= stop_d;
|
396 |
|
|
when I2C_CMD_WRITE => c_state <= wr_a;
|
397 |
|
|
s_state <= wr_d;
|
398 |
|
|
when I2C_CMD_READ => c_state <= rd_a;
|
399 |
|
|
s_state <= rd_d;
|
400 |
|
|
when others => c_state <= idle; -- NOP command
|
401 |
|
|
s_state <= idle;
|
402 |
|
|
end case;
|
403 |
|
|
|
404 |
|
|
iscl_oen <= iscl_oen; -- keep SCL in same state
|
405 |
|
|
isda_oen <= isda_oen; -- keep SDA in same state
|
406 |
|
|
sda_chk <= '0'; -- don't check SDA
|
407 |
|
|
|
408 |
|
|
-- start
|
409 |
|
|
when start_a =>
|
410 |
|
|
c_state <= start_b;
|
411 |
|
|
iscl_oen <= iscl_oen; -- keep SCL in same state (for repeated start)
|
412 |
|
|
isda_oen <= '1'; -- set SDA high
|
413 |
|
|
sda_chk <= '0'; -- don't check SDA
|
414 |
|
|
|
415 |
|
|
when start_b =>
|
416 |
|
|
c_state <= start_c;
|
417 |
|
|
iscl_oen <= '1'; -- set SCL high
|
418 |
|
|
isda_oen <= '1'; -- keep SDA high
|
419 |
|
|
sda_chk <= '0'; -- don't check SDA
|
420 |
|
|
|
421 |
|
|
when start_c =>
|
422 |
|
|
c_state <= start_d;
|
423 |
|
|
iscl_oen <= '1'; -- set SCL high
|
424 |
|
|
isda_oen <= '1'; -- keep SDA high
|
425 |
|
|
sda_chk <= '0'; -- don't check SDA
|
426 |
|
|
|
427 |
|
|
when start_d =>
|
428 |
|
|
c_state <= start_e;
|
429 |
|
|
iscl_oen <= '1'; -- set SCL high
|
430 |
|
|
isda_oen <= '1'; -- keep SDA high
|
431 |
|
|
sda_chk <= '0'; -- don't check SDA
|
432 |
|
|
|
433 |
|
|
when start_e =>
|
434 |
|
|
c_state <= start_f;
|
435 |
|
|
iscl_oen <= '1'; -- keep SCL high
|
436 |
|
|
isda_oen <= '0'; -- set SDA low
|
437 |
|
|
sda_chk <= '0'; -- don't check SDA
|
438 |
|
|
|
439 |
|
|
when start_f =>
|
440 |
|
|
c_state <= start_g;
|
441 |
|
|
iscl_oen <= '1'; -- keep SCL high
|
442 |
|
|
isda_oen <= '0'; -- keep SDA low
|
443 |
|
|
sda_chk <= '0'; -- don't check SDA
|
444 |
|
|
|
445 |
|
|
when start_g =>
|
446 |
|
|
c_state <= idle;
|
447 |
|
|
cmd_ack <= '1'; -- command completed
|
448 |
|
|
iscl_oen <= '0'; -- set SCL low
|
449 |
|
|
isda_oen <= '0'; -- keep SDA low
|
450 |
|
|
sda_chk <= '0'; -- don't check SDA
|
451 |
|
|
|
452 |
|
|
-- stop
|
453 |
|
|
when stop_a =>
|
454 |
|
|
c_state <= stop_b;
|
455 |
|
|
iscl_oen <= '0'; -- keep SCL low
|
456 |
|
|
isda_oen <= '0'; -- set SDA low
|
457 |
|
|
sda_chk <= '0'; -- don't check SDA
|
458 |
|
|
|
459 |
|
|
when stop_b =>
|
460 |
|
|
c_state <= stop_c;
|
461 |
|
|
iscl_oen <= '1'; -- set SCL high
|
462 |
|
|
isda_oen <= '0'; -- keep SDA low
|
463 |
|
|
sda_chk <= '0'; -- don't check SDA
|
464 |
|
|
|
465 |
|
|
when stop_c =>
|
466 |
|
|
c_state <= stop_d;
|
467 |
|
|
iscl_oen <= '1'; -- keep SCL high
|
468 |
|
|
isda_oen <= '0'; -- keep SDA low
|
469 |
|
|
sda_chk <= '0'; -- don't check SDA
|
470 |
|
|
|
471 |
|
|
when stop_d =>
|
472 |
|
|
c_state <= idle;
|
473 |
|
|
cmd_ack <= '1'; -- command completed
|
474 |
|
|
iscl_oen <= '1'; -- keep SCL high
|
475 |
|
|
isda_oen <= '1'; -- set SDA high
|
476 |
|
|
sda_chk <= '0'; -- don't check SDA
|
477 |
|
|
|
478 |
|
|
-- read
|
479 |
|
|
when rd_a =>
|
480 |
|
|
c_state <= rd_b;
|
481 |
|
|
iscl_oen <= '0'; -- keep SCL low
|
482 |
|
|
isda_oen <= '1'; -- tri-state SDA
|
483 |
|
|
sda_chk <= '0'; -- don't check SDA
|
484 |
|
|
|
485 |
|
|
when rd_b =>
|
486 |
|
|
c_state <= rd_c;
|
487 |
|
|
iscl_oen <= '1'; -- set SCL high
|
488 |
|
|
isda_oen <= '1'; -- tri-state SDA
|
489 |
|
|
sda_chk <= '0'; -- don't check SDA
|
490 |
|
|
|
491 |
|
|
when rd_c =>
|
492 |
|
|
c_state <= rd_d;
|
493 |
|
|
iscl_oen <= '1'; -- keep SCL high
|
494 |
|
|
isda_oen <= '1'; -- tri-state SDA
|
495 |
|
|
sda_chk <= '0'; -- don't check SDA
|
496 |
|
|
|
497 |
|
|
when rd_d =>
|
498 |
|
|
c_state <= idle;
|
499 |
|
|
cmd_ack <= '1'; -- command completed
|
500 |
|
|
iscl_oen <= '0'; -- set SCL low
|
501 |
|
|
isda_oen <= '1'; -- tri-state SDA
|
502 |
|
|
sda_chk <= '0'; -- don't check SDA
|
503 |
|
|
|
504 |
|
|
-- write
|
505 |
|
|
when wr_a =>
|
506 |
|
|
c_state <= wr_b;
|
507 |
|
|
iscl_oen <= '0'; -- keep SCL low
|
508 |
|
|
isda_oen <= din; -- set SDA
|
509 |
|
|
sda_chk <= '0'; -- don't check SDA (SCL low)
|
510 |
|
|
|
511 |
|
|
when wr_b =>
|
512 |
|
|
c_state <= wr_c;
|
513 |
|
|
iscl_oen <= '1'; -- set SCL high
|
514 |
|
|
isda_oen <= din; -- keep SDA
|
515 |
|
|
sda_chk <= '1'; -- check SDA
|
516 |
|
|
|
517 |
|
|
when wr_c =>
|
518 |
|
|
c_state <= wr_d;
|
519 |
|
|
iscl_oen <= '1'; -- keep SCL high
|
520 |
|
|
isda_oen <= din; -- keep SDA
|
521 |
|
|
sda_chk <= '1'; -- check SDA
|
522 |
|
|
|
523 |
|
|
when wr_d =>
|
524 |
|
|
c_state <= idle;
|
525 |
|
|
cmd_ack <= '1'; -- command completed
|
526 |
|
|
iscl_oen <= '0'; -- set SCL low
|
527 |
|
|
isda_oen <= din; -- keep SDA
|
528 |
|
|
sda_chk <= '0'; -- don't check SDA (SCL low)
|
529 |
|
|
|
530 |
|
|
when others =>
|
531 |
|
|
|
532 |
|
|
end case;
|
533 |
|
|
end if;
|
534 |
|
|
end if;
|
535 |
|
|
end if;
|
536 |
|
|
end process nxt_state_decoder;
|
537 |
|
|
|
538 |
|
|
|
539 |
|
|
-- assign outputs
|
540 |
|
|
scl_o <= '0';
|
541 |
|
|
scl_oen <= iscl_oen;
|
542 |
|
|
sda_o <= '0';
|
543 |
|
|
sda_oen <= isda_oen;
|
544 |
|
|
end architecture structural;
|
545 |
|
|
|