blob: 16e7555f87e28a4973d78c435f4c47029fca71f0 [file] [log] [blame]
Sylvain Munautbd83e532020-09-15 22:11:29 +02001/*
2 * i2c_master.v
3 *
4 * vim: ts=4 sw=4
5 *
6 * Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
7 * SPDX-License-Identifier: CERN-OHL-P-2.0
8 */
9
10`default_nettype none
11
12module i2c_master #(
13 parameter integer DW = 3
14)(
15 // IOs
16 output reg scl_oe,
17 output reg sda_oe,
18 input wire sda_i,
19
20 // Control
21 input wire [7:0] data_in,
22 input wire ack_in,
23 input wire [1:0] cmd,
24 input wire stb,
25
26 output wire [7:0] data_out,
27 output wire ack_out,
28
29 output wire ready,
30
31 // Clock / Reset
32 input wire clk,
33 input wire rst
34);
35
36 // Commands
37 localparam [2:0] CMD_START = 3'b00;
38 localparam [2:0] CMD_STOP = 3'b01;
39 localparam [2:0] CMD_WRITE = 3'b10;
40 localparam [2:0] CMD_READ = 3'b11;
41
42 // FSM states
43 localparam
44 ST_IDLE = 0,
45 ST_LOWER_SCL = 1,
46 ST_LOW_CYCLE = 2,
47 ST_RISE_SCL = 3,
48 ST_HIGH_CYCLE = 4;
49
50
51 // Signals
52 // -------
53
54 reg [2:0] state;
55 reg [2:0] state_nxt;
56
57 reg [1:0] cmd_cur;
58
59 reg [DW:0] cyc_cnt;
60 wire cyc_now;
61
62 reg [3:0] bit_cnt;
63 wire bit_last;
64
65 reg [8:0] data_reg;
66
67
68 // State Machine
69 // -------------
70
71 always @(posedge clk)
72 if (rst)
73 state <= ST_IDLE;
74 else
75 state <= state_nxt;
76
77 always @(*)
78 begin
79 // Default is to stay put
80 state_nxt = state;
81
82 // Act depending on current state
83 case (state)
84 ST_IDLE:
85 if (stb)
86 state_nxt = ST_LOW_CYCLE;
87
88 ST_LOW_CYCLE:
89 if (cyc_now)
90 state_nxt = ST_RISE_SCL;
91
92 ST_RISE_SCL:
93 if (cyc_now)
94 state_nxt = ST_HIGH_CYCLE;
95
96 ST_HIGH_CYCLE:
97 if (cyc_now)
98 state_nxt = (cmd_cur == 2'b01) ? ST_IDLE : ST_LOWER_SCL;
99
100 ST_LOWER_SCL:
101 if (cyc_now)
102 state_nxt = bit_last ? ST_IDLE : ST_LOW_CYCLE;
103 endcase
104 end
105
106 // Misc control
107 // ------------
108
109 always @(posedge clk)
110 if (stb)
111 cmd_cur <= cmd;
112
113
114 // Baud Rate generator
115 // -------------------
116
117 always @(posedge clk)
118 if (state == ST_IDLE)
119 cyc_cnt <= 0;
120 else
121 cyc_cnt <= cyc_cnt[DW] ? 0 : (cyc_cnt + 1);
122
123 assign cyc_now = cyc_cnt[DW];
124
125
126 // Bit count
127 // ---------
128
129 always @(posedge clk)
130 if ((state == ST_LOWER_SCL) && cyc_now)
131 bit_cnt <= bit_cnt + 1;
132 else if (stb)
133 case (cmd)
134 2'b00: bit_cnt <= 4'h8; // START
135 2'b01: bit_cnt <= 4'h8; // STOP
136 2'b10: bit_cnt <= 4'h0; // Write
137 2'b11: bit_cnt <= 4'h0; // Read
138 default: bit_cnt <= 4'hx;
139 endcase
140
141 assign bit_last = bit_cnt[3];
142
143
144 // Data register
145 // -------------
146
147 always @(posedge clk)
148 if ((state == ST_HIGH_CYCLE) && cyc_now)
149 data_reg <= { data_reg[7:0], sda_i };
150 else if (stb)
151 // Only handle Write / Read. START & STOP is handled in IO mux
152 data_reg <= cmd[0] ? { 8'b11111111, ack_in } : { data_in, 1'b1 };
153
154
155 // IO
156 // --
157
158 always @(posedge clk)
159 if (rst)
160 scl_oe <= 1'b0;
161 else if (cyc_now) begin
162 if (state == ST_LOWER_SCL)
163 scl_oe <= 1'b1;
164 else if (state == ST_RISE_SCL)
165 scl_oe <= 1'b0;
166 end
167
168 always @(posedge clk)
169 if (rst)
170 sda_oe <= 1'b0;
171 else if (cyc_now) begin
172 if (~cmd_cur[1]) begin
173 if (state == ST_LOW_CYCLE)
174 sda_oe <= cmd_cur[0];
175 else if (state == ST_HIGH_CYCLE)
176 sda_oe <= ~cmd_cur[0];
177 end else begin
178 if (state == ST_LOW_CYCLE)
179 sda_oe <= ~data_reg[8];
180 end
181 end
182
183
184 // User IF
185 // -------
186
187 assign data_out = data_reg[8:1];
188 assign ack_out = data_reg[0];
189
190 assign ready = (state == ST_IDLE);
191
192endmodule