1 |
2 |
ayersg |
`timescale 1ns / 1ps
|
2 |
|
|
/*
|
3 |
|
|
* File : I2C_Phy.v
|
4 |
|
|
* Project : University of Utah, XUM Project MIPS32 core
|
5 |
|
|
* Creator(s) : Grant Ayers (ayers@cs.utah.edu)
|
6 |
|
|
*
|
7 |
|
|
* Modification History:
|
8 |
|
|
* Rev Date Initials Description of Change
|
9 |
|
|
* 1.0 25-Jun-2012 GEA Initial design.
|
10 |
|
|
*
|
11 |
|
|
* Standards/Formatting:
|
12 |
|
|
* Verilog 2001, 4 soft tab, wide column.
|
13 |
|
|
*
|
14 |
|
|
* Description:
|
15 |
|
|
* I2C Master controller made for a single-master I2C bus.
|
16 |
|
|
* Uses a FIFO to store transmit and receive data, and is made
|
17 |
|
|
* to be generic enough to use with a wide variety of I2C slave devices.
|
18 |
|
|
* A Read command sends a bus address byte then receives a requested number
|
19 |
|
|
* of bytes, while a Write command writes all bytes that are presently in
|
20 |
|
|
* the FIFO.
|
21 |
|
|
*/
|
22 |
|
|
|
23 |
|
|
module I2C_Phy(
|
24 |
|
|
input clock,
|
25 |
|
|
input reset,
|
26 |
|
|
input Read,
|
27 |
|
|
input Write,
|
28 |
|
|
input ReadCountSet,
|
29 |
|
|
input EnQ,
|
30 |
|
|
input DeQ,
|
31 |
|
|
input Clear,
|
32 |
|
|
input [7:0] DataIn,
|
33 |
|
|
output reg [7:0] DataOut,
|
34 |
|
|
output Ack,
|
35 |
|
|
output reg Nack,
|
36 |
|
|
output Fifo_Empty,
|
37 |
|
|
output Fifo_Full,
|
38 |
|
|
inout i2c_scl,
|
39 |
|
|
inout i2c_sda
|
40 |
|
|
);
|
41 |
|
|
|
42 |
|
|
localparam [5:0] IDLE=0, ENQ=1, DEQ=2, START=3, ADDR6=4, ADDR5=5, ADDR4=6, ADDR3=7, ADDR2=8,
|
43 |
|
|
ADDR1=9, ADDR0=10, RWBIT=11, A_DEQ=12, A_ACK=13, WDWAIT=14, WDATA7=15,
|
44 |
|
|
WDATA6=16, WDATA5=17, WDATA4=18, WDATA3=19, WDATA2=20, WDATA1=21, WDATA0=22,
|
45 |
|
|
W_DEQ=23, W_ACK=24, RDATA7=25, RDATA6=26, RDATA5=27, RDATA4=28, RDATA3=29,
|
46 |
|
|
RDATA2=30, RDATA1=31, RDATA0=32, R_ENQ=33, R_ACKW=34, R_ACK=35, NACK=36,
|
47 |
|
|
STOPW=37, STOP=38, BUSW=39, CLEAR=40, RNSET=41;
|
48 |
|
|
|
49 |
|
|
// FIFO signals
|
50 |
|
|
wire Fifo_Clear, Fifo_EnQ, Fifo_DeQ;
|
51 |
|
|
wire [7:0] Fifo_In, Fifo_Out;
|
52 |
|
|
|
53 |
|
|
wire scl, scl_tick_90;
|
54 |
|
|
reg [5:0] state;
|
55 |
|
|
reg [7:0] Rx_Data;
|
56 |
|
|
reg sda;
|
57 |
|
|
reg [7:0] Rx_Todo, Rx_Remain;
|
58 |
|
|
|
59 |
|
|
// The I2C bus is high-impedance instead of a driven 1.
|
60 |
|
|
assign i2c_sda = (sda) ? 1'bz : 1'b0;
|
61 |
|
|
assign i2c_scl = (scl | (state == IDLE)) ? 1'bz : 1'b0;
|
62 |
|
|
|
63 |
|
|
// Control logic : 4-way handshaking
|
64 |
|
|
assign Ack = (state == BUSW);
|
65 |
|
|
|
66 |
|
|
always @(posedge clock) begin
|
67 |
|
|
Rx_Todo <= (reset) ? 8'h00 : ((state == RNSET) ? DataIn : Rx_Todo);
|
68 |
|
|
Rx_Remain <= (reset) ? 8'h00 : ((state == IDLE) ? Rx_Todo : ((state == R_ENQ) ? Rx_Remain - 1 : Rx_Remain));
|
69 |
|
|
end
|
70 |
|
|
|
71 |
|
|
always @(posedge clock) begin
|
72 |
|
|
DataOut <= (reset) ? 8'h00 : ((state == DEQ) ? Fifo_Out : DataOut);
|
73 |
|
|
end
|
74 |
|
|
|
75 |
|
|
always @(posedge clock) begin
|
76 |
|
|
Nack <= (reset | (state == START)) ? 0 : ((state == NACK) ? 1 : Nack);
|
77 |
|
|
end
|
78 |
|
|
|
79 |
|
|
assign Fifo_EnQ = (state == ENQ) || (state == R_ENQ);
|
80 |
|
|
assign Fifo_DeQ = (state == DEQ) || (state == A_DEQ) || (state == W_DEQ);
|
81 |
|
|
assign Fifo_In = (state == R_ENQ) ? Rx_Data : DataIn;
|
82 |
|
|
assign Fifo_Clear = (state == CLEAR);
|
83 |
|
|
|
84 |
|
|
// Main state machine
|
85 |
|
|
always @(posedge clock) begin
|
86 |
|
|
if (reset) begin
|
87 |
|
|
state <= IDLE;
|
88 |
|
|
end
|
89 |
|
|
else begin
|
90 |
|
|
case (state)
|
91 |
|
|
IDLE: begin
|
92 |
|
|
if (EnQ) state <= ENQ;
|
93 |
|
|
else if (DeQ) state <= DEQ;
|
94 |
|
|
else if (Clear) state <= CLEAR;
|
95 |
|
|
else if (ReadCountSet) state <= RNSET;
|
96 |
|
|
else if ((Read | Write) & scl & scl_tick_90) state <= START;
|
97 |
|
|
else state <= IDLE;
|
98 |
|
|
end
|
99 |
|
|
ENQ: state <= BUSW;
|
100 |
|
|
DEQ: state <= BUSW;
|
101 |
|
|
CLEAR: state <= BUSW;
|
102 |
|
|
RNSET: state <= BUSW;
|
103 |
|
|
START: state <= (~scl & scl_tick_90) ? ADDR6 : START;
|
104 |
|
|
ADDR6: state <= (~scl & scl_tick_90) ? ADDR5 : ADDR6;
|
105 |
|
|
ADDR5: state <= (~scl & scl_tick_90) ? ADDR4 : ADDR5;
|
106 |
|
|
ADDR4: state <= (~scl & scl_tick_90) ? ADDR3 : ADDR4;
|
107 |
|
|
ADDR3: state <= (~scl & scl_tick_90) ? ADDR2 : ADDR3;
|
108 |
|
|
ADDR2: state <= (~scl & scl_tick_90) ? ADDR1 : ADDR2;
|
109 |
|
|
ADDR1: state <= (~scl & scl_tick_90) ? ADDR0 : ADDR1;
|
110 |
|
|
ADDR0: state <= (~scl & scl_tick_90) ? RWBIT : ADDR0;
|
111 |
|
|
RWBIT: state <= (~scl & scl_tick_90) ? A_DEQ : RWBIT;
|
112 |
|
|
A_DEQ: state <= A_ACK;
|
113 |
|
|
A_ACK: state <= ( scl & scl_tick_90) ? ((i2c_sda) ? NACK : ((Read) ? RDATA7 : WDWAIT)) : A_ACK;
|
114 |
|
|
|
115 |
|
|
// Writes
|
116 |
|
|
WDWAIT: state <= (~scl & scl_tick_90) ? WDATA7 : WDWAIT;
|
117 |
|
|
WDATA7: state <= (~scl & scl_tick_90) ? WDATA6 : WDATA7;
|
118 |
|
|
WDATA6: state <= (~scl & scl_tick_90) ? WDATA5 : WDATA6;
|
119 |
|
|
WDATA5: state <= (~scl & scl_tick_90) ? WDATA4 : WDATA5;
|
120 |
|
|
WDATA4: state <= (~scl & scl_tick_90) ? WDATA3 : WDATA4;
|
121 |
|
|
WDATA3: state <= (~scl & scl_tick_90) ? WDATA2 : WDATA3;
|
122 |
|
|
WDATA2: state <= (~scl & scl_tick_90) ? WDATA1 : WDATA2;
|
123 |
|
|
WDATA1: state <= (~scl & scl_tick_90) ? WDATA0 : WDATA1;
|
124 |
|
|
WDATA0: state <= (~scl & scl_tick_90) ? W_DEQ : WDATA0;
|
125 |
|
|
W_DEQ: state <= W_ACK;
|
126 |
|
|
W_ACK: state <= ( scl & scl_tick_90) ? ((i2c_sda) ? NACK : ((Fifo_Empty) ? STOPW : WDWAIT)) : W_ACK;
|
127 |
|
|
|
128 |
|
|
// Reads
|
129 |
|
|
RDATA7: state <= ( scl & scl_tick_90) ? RDATA6 : RDATA7;
|
130 |
|
|
RDATA6: state <= ( scl & scl_tick_90) ? RDATA5 : RDATA6;
|
131 |
|
|
RDATA5: state <= ( scl & scl_tick_90) ? RDATA4 : RDATA5;
|
132 |
|
|
RDATA4: state <= ( scl & scl_tick_90) ? RDATA3 : RDATA4;
|
133 |
|
|
RDATA3: state <= ( scl & scl_tick_90) ? RDATA2 : RDATA3;
|
134 |
|
|
RDATA2: state <= ( scl & scl_tick_90) ? RDATA1 : RDATA2;
|
135 |
|
|
RDATA1: state <= ( scl & scl_tick_90) ? RDATA0 : RDATA1;
|
136 |
|
|
RDATA0: state <= ( scl & scl_tick_90) ? R_ENQ : RDATA0;
|
137 |
|
|
R_ENQ: state <= R_ACKW;
|
138 |
|
|
R_ACKW: state <= (~scl & scl_tick_90) ? R_ACK : R_ACKW;
|
139 |
|
|
R_ACK: state <= (~scl & scl_tick_90) ? ((Rx_Remain != 8'h00) ? RDATA7 : STOP) : R_ACK;
|
140 |
|
|
|
141 |
|
|
// Termination
|
142 |
|
|
NACK: state <= STOPW;
|
143 |
|
|
STOPW: state <= (~scl & scl_tick_90) ? STOP : STOPW;
|
144 |
|
|
STOP: state <= ( scl & scl_tick_90) ? BUSW : STOP;
|
145 |
|
|
BUSW: state <= (Read | Write | EnQ | DeQ) ? BUSW : IDLE;
|
146 |
|
|
default: state <= 6'bxxxxxx;
|
147 |
|
|
endcase
|
148 |
|
|
end
|
149 |
|
|
end
|
150 |
|
|
|
151 |
|
|
// Incoming data capture
|
152 |
|
|
always @(posedge clock) begin
|
153 |
|
|
if (reset) begin
|
154 |
|
|
Rx_Data <= 8'h00;
|
155 |
|
|
end
|
156 |
|
|
else begin
|
157 |
|
|
Rx_Data[7] <= ((state == RDATA7) & scl & scl_tick_90) ? i2c_sda : Rx_Data[7];
|
158 |
|
|
Rx_Data[6] <= ((state == RDATA6) & scl & scl_tick_90) ? i2c_sda : Rx_Data[6];
|
159 |
|
|
Rx_Data[5] <= ((state == RDATA5) & scl & scl_tick_90) ? i2c_sda : Rx_Data[5];
|
160 |
|
|
Rx_Data[4] <= ((state == RDATA4) & scl & scl_tick_90) ? i2c_sda : Rx_Data[4];
|
161 |
|
|
Rx_Data[3] <= ((state == RDATA3) & scl & scl_tick_90) ? i2c_sda : Rx_Data[3];
|
162 |
|
|
Rx_Data[2] <= ((state == RDATA2) & scl & scl_tick_90) ? i2c_sda : Rx_Data[2];
|
163 |
|
|
Rx_Data[1] <= ((state == RDATA1) & scl & scl_tick_90) ? i2c_sda : Rx_Data[1];
|
164 |
|
|
Rx_Data[0] <= ((state == RDATA0) & scl & scl_tick_90) ? i2c_sda : Rx_Data[0];
|
165 |
|
|
end
|
166 |
|
|
end
|
167 |
|
|
|
168 |
|
|
// I2C data line assignment
|
169 |
|
|
always @(*) begin
|
170 |
|
|
case (state)
|
171 |
|
|
IDLE: sda <= 1;
|
172 |
|
|
ENQ: sda <= 1;
|
173 |
|
|
DEQ: sda <= 1;
|
174 |
|
|
CLEAR: sda <= 1;
|
175 |
|
|
START: sda <= 0;
|
176 |
|
|
ADDR6: sda <= Fifo_Out[6];
|
177 |
|
|
ADDR5: sda <= Fifo_Out[5];
|
178 |
|
|
ADDR4: sda <= Fifo_Out[4];
|
179 |
|
|
ADDR3: sda <= Fifo_Out[3];
|
180 |
|
|
ADDR2: sda <= Fifo_Out[2];
|
181 |
|
|
ADDR1: sda <= Fifo_Out[1];
|
182 |
|
|
ADDR0: sda <= Fifo_Out[0];
|
183 |
|
|
RWBIT: sda <= Read; // 0 is write, 1 is read
|
184 |
|
|
A_DEQ: sda <= 1;
|
185 |
|
|
A_ACK: sda <= 1;
|
186 |
|
|
WDWAIT: sda <= 1;
|
187 |
|
|
WDATA7: sda <= Fifo_Out[7];
|
188 |
|
|
WDATA6: sda <= Fifo_Out[6];
|
189 |
|
|
WDATA5: sda <= Fifo_Out[5];
|
190 |
|
|
WDATA4: sda <= Fifo_Out[4];
|
191 |
|
|
WDATA3: sda <= Fifo_Out[3];
|
192 |
|
|
WDATA2: sda <= Fifo_Out[2];
|
193 |
|
|
WDATA1: sda <= Fifo_Out[1];
|
194 |
|
|
WDATA0: sda <= Fifo_Out[0];
|
195 |
|
|
W_DEQ: sda <= 1;
|
196 |
|
|
W_ACK: sda <= 1;
|
197 |
|
|
RDATA7: sda <= 1;
|
198 |
|
|
RDATA6: sda <= 1;
|
199 |
|
|
RDATA5: sda <= 1;
|
200 |
|
|
RDATA4: sda <= 1;
|
201 |
|
|
RDATA3: sda <= 1;
|
202 |
|
|
RDATA2: sda <= 1;
|
203 |
|
|
RDATA1: sda <= 1;
|
204 |
|
|
RDATA0: sda <= 1;
|
205 |
|
|
R_ENQ: sda <= 1;
|
206 |
|
|
R_ACKW: sda <= 1;
|
207 |
|
|
R_ACK: sda <= (Rx_Remain == 8'h00); // Low for more data, high for done
|
208 |
|
|
NACK: sda <= 1;
|
209 |
|
|
STOPW: sda <= 1;
|
210 |
|
|
STOP: sda <= 0;
|
211 |
|
|
BUSW: sda <= 1;
|
212 |
|
|
default: sda <= 1;
|
213 |
|
|
endcase
|
214 |
|
|
end
|
215 |
|
|
|
216 |
|
|
// I2C Clock Generation
|
217 |
|
|
I2C_Clock I2C_Clock (
|
218 |
|
|
.clock (clock),
|
219 |
|
|
.reset (reset),
|
220 |
|
|
.scl (scl),
|
221 |
|
|
.scl_tick_90 (scl_tick_90)
|
222 |
|
|
);
|
223 |
|
|
|
224 |
|
|
FIFO_Clear FIFO (
|
225 |
|
|
.clock (clock),
|
226 |
|
|
.reset (reset),
|
227 |
|
|
.clear (Fifo_Clear),
|
228 |
|
|
.enQ (Fifo_EnQ),
|
229 |
|
|
.deQ (Fifo_DeQ),
|
230 |
|
|
.data_in (Fifo_In),
|
231 |
|
|
.data_out (Fifo_Out),
|
232 |
|
|
.empty (Fifo_Empty),
|
233 |
|
|
.full (Fifo_Full)
|
234 |
|
|
);
|
235 |
|
|
|
236 |
|
|
endmodule
|