Skip to content

Commit d4c2c02

Browse files
I2C: A couple of fixes around SCL stretching is handled (#248)
This commit fixes a couple of bugs related to SCL stretching. First off, in the `I2CBitController` I adjusted how we sample SCL to detect stretching so we're not errantly sampling. Then in the `I2CCore` I added a mechanism to handle the SCL stretch timeouts when we see them. Before we lacked this and that meant if that was seen, we were wedged. The rest of the changes were to test cases in order to mimic the behavior observed that brought the problems to our attention. Fixes #246 Fixes #247
1 parent e5f3844 commit d4c2c02

File tree

7 files changed

+368
-111
lines changed

7 files changed

+368
-111
lines changed

hdl/ip/bsv/I2C/I2CBitController.bsv

+10-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ interface I2CBitController;
4848
interface Put#(Event) send;
4949
interface Get#(Event) receive;
5050

51+
// way of indicating when there is no bus activity
52+
method Bool busy();
53+
5154
// clock stretching information sent sideband from the state machine events
5255
method Bool scl_stretch_seen();
5356
method Bool scl_stretch_timeout();
@@ -155,14 +158,14 @@ module mkI2CBitController #(
155158
// After the delay we know SCL is being stretched if we aren't the ones
156159
// holding it low.
157160
(* fire_when_enabled *)
158-
rule do_sample_scl_stretch(scl_stretch_sample_strobe && scl_in == 0);
159-
scl_stretching <= scl_out_en == 0;
161+
rule do_sample_scl_stretch(scl_stretch_sample_strobe);
162+
scl_stretching <= scl_out_en == 0 && scl_in == 0;
160163
scl_stretch_sample_delay <= False;
161164
endrule
162165

163166
// If SCL is high then no one is holding it
164167
(* fire_when_enabled *)
165-
rule do_clear_scl_stretch(scl_in == 1);
168+
rule do_clear_scl_stretch(scl_in == 1 && !scl_stretch_sample_strobe);
166169
scl_stretching <= False;
167170
endrule
168171

@@ -251,6 +254,8 @@ module mkI2CBitController #(
251254
(* fire_when_enabled *)
252255
rule do_scl_stretch_timeout(scl_stretch_timeout_cntr);
253256
state <= AwaitStart;
257+
scl_active <= False;
258+
sda_out_en <= 0;
254259
scl_stretch_timeout_r <= True;
255260
incoming_events.clear();
256261
endrule
@@ -416,6 +421,8 @@ module mkI2CBitController #(
416421
endinterface
417422
interface Get receive = toGet(outgoing_events);
418423

424+
method busy = state != AwaitStart;
425+
419426
method scl_stretch_seen = scl_stretch_seen_r;
420427
method scl_stretch_timeout = scl_stretch_timeout_r;
421428
endmodule

hdl/ip/bsv/I2C/I2CCore.bsv

+42-29
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export Pins(..);
1313
export I2CCore(..);
1414
export mkI2CCore;
1515

16+
import ConfigReg::*;
1617
import DefaultValue::*;
1718
import DReg::*;
1819
import FIFO::*;
@@ -105,40 +106,57 @@ module mkI2CCore#(Integer core_clk_freq,
105106
Reg#(Bool) in_random_read <- mkReg(False);
106107
Reg#(Bool) in_write_ack_poll <- mkReg(False);
107108
Reg#(Bool) write_acked <- mkReg(False);
108-
109+
ConfigReg#(Bool) state_cleared <- mkConfigReg(False);
110+
Reg#(Bool) clearing_state <- mkReg(False);
111+
PulseWire clear_state <- mkPulseWire;
109112
PulseWire next_send_data <- mkPulseWire;
110113

111-
// relabel this net for brevity
112-
let timed_out = bit_ctrl.scl_stretch_timeout;
113-
114114
(* fire_when_enabled, no_implicit_conditions *)
115115
rule do_valid_command;
116116
valid_command <= isValid(cur_command);
117117
endrule
118118

119119
// when the bit controller has timed out, clear core state
120120
(* fire_when_enabled *)
121-
rule do_handle_stretch_timeout(timed_out);
122-
next_command.clear();
123-
error_r <= tagged Invalid;
124-
state_r <= Idle;
121+
rule do_clearing_state_reg;
122+
clearing_state <= (bit_ctrl.scl_stretch_timeout && !state_cleared) || clear_state;
125123
endrule
126124

127125
(* fire_when_enabled *)
128-
rule do_register_command(state_r == Idle && !valid_command && !timed_out);
129-
cur_command <= tagged Valid next_command.first;
130-
error_r <= tagged Invalid;
131-
state_r <= SendStart;
126+
rule do_handle_stretch_timeout(clearing_state);
127+
next_command.deq();
128+
bytes_done <= 0;
129+
in_random_read <= False;
130+
in_write_ack_poll <= False;
131+
write_acked <= False;
132+
cur_command <= tagged Invalid;
133+
state_r <= Idle;
132134
endrule
133135

134136
(* fire_when_enabled *)
135-
rule do_send_start (state_r == SendStart && valid_command && !timed_out);
137+
rule do_state_cleared_reg;
138+
if (clearing_state) begin
139+
state_cleared <= True;
140+
end else if (valid_command && bit_ctrl.busy()) begin
141+
state_cleared <= False;
142+
end
143+
endrule
144+
145+
(* fire_when_enabled *)
146+
rule do_register_command(state_r == Idle && !valid_command && !clearing_state);
147+
cur_command <= tagged Valid next_command.first;
148+
error_r <= tagged Invalid;
149+
state_r <= SendStart;
150+
endrule
151+
152+
(* fire_when_enabled *)
153+
rule do_send_start (state_r == SendStart && valid_command && !clearing_state);
136154
bit_ctrl.send.put(tagged Start);
137155
state_r <= SendAddr;
138156
endrule
139157

140158
(* fire_when_enabled *)
141-
rule do_send_addr (state_r == SendAddr && valid_command && !timed_out);
159+
rule do_send_addr (state_r == SendAddr && valid_command && !clearing_state);
142160
let cmd = fromMaybe(?, cur_command);
143161
let is_read = (cmd.op == Read) || in_random_read;
144162
let addr_byte = {cmd.i2c_addr, pack(is_read)};
@@ -149,21 +167,22 @@ module mkI2CCore#(Integer core_clk_freq,
149167
(* fire_when_enabled *)
150168
rule do_await_addr_ack (state_r == AwaitAddrAck
151169
&& valid_command
152-
&& !timed_out);
170+
&& !clearing_state);
153171
let ack_nack <- bit_ctrl.receive.get();
154172
let cmd = fromMaybe(?, cur_command);
155173

156174
case (ack_nack) matches
157175
tagged Ack: begin
158-
// Begin a Read
159176
if (cmd.op == Read || in_random_read) begin
177+
// begin a Read
160178
bytes_done <= 1;
161179
bit_ctrl.send.put(tagged Read (cmd.num_bytes == 1));
162180
state_r <= Reading;
163181
end else if (in_write_ack_poll) begin
164182
write_acked <= True;
165183
state_r <= Stop;
166184
end else begin
185+
// begin a Write
167186
bit_ctrl.send.put(tagged Write cmd.reg_addr);
168187
state_r <= AwaitWriteAck;
169188
end
@@ -180,7 +199,7 @@ module mkI2CCore#(Integer core_clk_freq,
180199
endrule
181200

182201
(* fire_when_enabled *)
183-
rule do_writing (state_r == Writing && valid_command && !timed_out);
202+
rule do_writing (state_r == Writing && valid_command && !clearing_state);
184203
bit_ctrl.send.put(tagged Write tx_data);
185204
next_send_data.send();
186205
state_r <= AwaitWriteAck;
@@ -189,7 +208,7 @@ module mkI2CCore#(Integer core_clk_freq,
189208
(* fire_when_enabled *)
190209
rule do_await_writing_ack (state_r == AwaitWriteAck
191210
&& valid_command
192-
&& !timed_out);
211+
&& !clearing_state);
193212
let ack_nack <- bit_ctrl.receive.get();
194213
let cmd = fromMaybe(?, cur_command);
195214

@@ -215,7 +234,7 @@ module mkI2CCore#(Integer core_clk_freq,
215234
endrule
216235

217236
(* fire_when_enabled *)
218-
rule do_reading (state_r == Reading && valid_command && !timed_out);
237+
rule do_reading (state_r == Reading && valid_command && !clearing_state);
219238
let rdata <- bit_ctrl.receive.get();
220239
let cmd = fromMaybe(?, cur_command);
221240

@@ -233,14 +252,14 @@ module mkI2CCore#(Integer core_clk_freq,
233252
endcase
234253
endrule
235254

236-
rule do_next_read (state_r == NextRead && valid_command && !timed_out);
255+
rule do_next_read (state_r == NextRead && valid_command && !clearing_state);
237256
let cmd = fromMaybe(?, cur_command);
238257
bit_ctrl.send.put(tagged Read (cmd.num_bytes == bytes_done));
239258
state_r <= Reading;
240259
endrule
241260

242261
(* fire_when_enabled *)
243-
rule do_stop (state_r == Stop && valid_command && !timed_out);
262+
rule do_stop (state_r == Stop && valid_command && !clearing_state);
244263
bit_ctrl.send.put(tagged Stop);
245264

246265
let cmd = fromMaybe(?, cur_command);
@@ -253,14 +272,8 @@ module mkI2CCore#(Integer core_clk_freq,
253272
endrule
254273

255274
(* fire_when_enabled *)
256-
rule do_done (state_r == Done && valid_command && !timed_out);
257-
next_command.deq();
258-
bytes_done <= 0;
259-
in_random_read <= False;
260-
in_write_ack_poll <= False;
261-
write_acked <= False;
262-
cur_command <= tagged Invalid;
263-
state_r <= Idle;
275+
rule do_done (state_r == Done && valid_command && !clearing_state && !bit_ctrl.busy());
276+
clear_state.send();
264277
endrule
265278

266279
interface pins = bit_ctrl.pins;

hdl/ip/bsv/I2C/test/I2CBitControllerTests.bsv

+2-3
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ module mkBench (Bench);
8989
Reg#(Vector#(3,Bit#(8))) prev_written_bytes <- mkReg(replicate(0));
9090
Reg#(UInt#(2)) bytes_done <- mkReg(0);
9191
Reg#(Bool) is_last_byte <- mkReg(False);
92-
Reg#(Bool) stretch_timeout <- mkReg(False);
9392

9493
FSM write_seq <- mkFSMWithPred(seq
9594
dut.send.put(tagged Start);
@@ -120,7 +119,7 @@ module mkBench (Bench);
120119

121120
dut.send.put(tagged Stop);
122121
check_peripheral_event(periph, tagged ReceivedStop, "Expected to receive STOP");
123-
endseq, command_r.op == Write && !stretch_timeout);
122+
endseq, command_r.op == Write && !dut.scl_stretch_timeout);
124123

125124
FSM read_seq <- mkFSMWithPred(seq
126125
dut.send.put(tagged Start);
@@ -153,7 +152,7 @@ module mkBench (Bench);
153152

154153
dut.send.put(tagged Stop);
155154
check_peripheral_event(periph, tagged ReceivedStop, "Expected to receive STOP");
156-
endseq, command_r.op == Read && !stretch_timeout);
155+
endseq, command_r.op == Read && !dut.scl_stretch_timeout);
157156

158157
FSM rnd_read_seq <- mkFSMWithPred(seq
159158
dut.send.put(tagged Start);

hdl/ip/bsv/I2C/test/I2CCoreTests.bsv

+3-3
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ module mkBench (Bench);
135135
endaction
136136
endseq
137137
check_peripheral_event(periph, tagged ReceivedStop, "Expected to receive STOP");
138-
endseq, command_r.op == Write);
138+
endseq, command_r.op == Write && !dut.scl_stretch_timeout);
139139

140140
FSM read_seq <- mkFSMWithPred(seq
141141
dut.send_command.put(command_r);
@@ -156,7 +156,7 @@ module mkBench (Bench);
156156
check_peripheral_event(periph, tagged ReceivedNack, "Expected to receive NACK to end the Read");
157157
check_peripheral_event(periph, tagged ReceivedStop, "Expected to receive STOP");
158158
bytes_done <= 0;
159-
endseq, command_r.op == Read);
159+
endseq, command_r.op == Read && !dut.scl_stretch_timeout);
160160

161161
FSM rand_read_seq <- mkFSMWithPred(seq
162162
dut.send_command.put(command_r);
@@ -181,7 +181,7 @@ module mkBench (Bench);
181181
check_peripheral_event(periph, tagged ReceivedNack, "Expected to receive NACK to end the Read");
182182
check_peripheral_event(periph, tagged ReceivedStop, "Expected to receive STOP");
183183
bytes_done <= 0;
184-
endseq, command_r.op == RandomRead);
184+
endseq, command_r.op == RandomRead && !dut.scl_stretch_timeout);
185185

186186
rule do_handle_stretch_timeout(dut.scl_stretch_timeout);
187187
write_seq.abort();

0 commit comments

Comments
 (0)