-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmaster_i2c.v
195 lines (164 loc) · 3.73 KB
/
master_i2c.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 23.12.2020 18:07:35
// Design Name:
// Module Name: i2c_master
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module master_i2c(input wire clk,
input wire reset,
input wire [6:0] addr,
input wire [7:0] data_in,
input wire enable,
input wire rw,
output reg [7:0] data_out,
output wire ready,
inout i2c_sda,
inout wire i2c_scl
);
// i2c master with 9 states as defined
localparam idle=0;
localparam start=1;
localparam address=2;
localparam read_ack=3;
localparam write_data=4;
localparam write_ack=5;
localparam read_data=6;
localparam read_ack2=7;
localparam stop=8;
localparam DIVIDE_BY = 4;
reg [7:0] state; //reg to store next state
reg [7:0] saved_addr;
reg [7:0] saved_data;
reg [7:0] counter;
reg [7:0] counter2 = 0;
reg i2c_sda_enable;
reg sda_out;
reg i2c_scl_enable = 0;
reg i2c_clk = 1;
assign ready = ((reset == 0) && (state == idle)) ? 1 : 0;
assign i2c_scl = (i2c_scl_enable == 0 ) ? 1 : i2c_clk;
assign i2c_sda = (i2c_sda_enable == 1) ? sda_out : 'bz;
//Generating i2c clock
always @(posedge clk) begin
if (counter2 == (DIVIDE_BY/2) - 1) begin
i2c_clk <= ~i2c_clk;
counter2 <= 0;
end
else counter2 <= counter2 + 1;
end
//i2c_scl enable setup
always @(negedge i2c_clk, posedge reset) begin
if(reset == 1) begin
i2c_scl_enable <= 0;
end else begin
if ((state == idle) || (state == start) || (state == stop)) begin
i2c_scl_enable <= 0;
end else begin
i2c_scl_enable <= 1;
end
end
end
//i2c FSM of 9 states
always @(posedge i2c_clk, posedge reset) begin
if(reset == 1) begin
state <= idle;
end
else begin
case(state)
//Initial state
idle: begin
if (enable) begin
state <= start;
saved_addr <= {addr, rw};//addr of 7 bits + 1 acknowledge bit
saved_data <= data_in;
end
else state <= idle;
end
start: begin
counter <= 7;
state <= address;
end
address: begin
if (counter == 0) begin
state <= read_ack;
end else counter <= counter - 1;
end
read_ack: begin
if (i2c_sda == 0) begin
counter <= 7;
if(saved_addr[0] == 0) state <= write_data;
else state <= read_data;
end else state <= stop;
end
write_data: begin
if(counter == 0) begin
state <= read_ack2;
end else counter <= counter - 1;
end
read_ack2: begin
if ((i2c_sda == 0) && (enable == 1)) state <= idle;
else state <= stop;
end
read_data: begin
data_out[counter] <= i2c_sda;
if (counter == 0) state <= write_ack;
else counter <= counter - 1;
end
write_ack: begin
state <= stop;
end
stop: begin
state <= idle;
end
endcase
end
end
always @(negedge i2c_clk, posedge reset) begin
if(reset == 1) begin
i2c_sda_enable <= 1;
sda_out <= 1;
end else begin
case(state)
start: begin
i2c_sda_enable <= 1;
sda_out <= 0;
end
address: begin
sda_out <= saved_addr[counter];
end
read_ack: begin
i2c_sda_enable <= 0;
end
write_data: begin
i2c_sda_enable <= 1;
sda_out <= saved_data[counter];
end
write_ack: begin
i2c_sda_enable <= 1;
sda_out <= 0;
end
read_data: begin
i2c_sda_enable <= 0;
end
stop: begin
i2c_sda_enable <= 1;
sda_out <= 1;
end
endcase
end
end
endmodule