Skip to content

Commit

Permalink
Merge pull request #83 from QuinnWang/patch-1
Browse files Browse the repository at this point in the history
make sure the expected delay to happen
  • Loading branch information
shuchitak authored Nov 7, 2024
2 parents 034ee3c + 469339e commit 5897cf4
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 22 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ lib_i2c change log

UNRELEASED
----------

* FIXED: In case of clock stretching, ensure that the required delay happens
between the slave releasing SCL and the master driving data on SDA.
* FIXED: Drive data on SDA in open drain mode.

6.3.1
Expand Down
19 changes: 10 additions & 9 deletions lib_i2c/src/i2c_master.xc
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ static const unsigned inline compute_bus_off_ticks(
static void release_clock_and_wait(
port p_scl,
unsigned &fall_time,
unsigned delay)
unsigned delay,
static const unsigned kbits_per_second)
{
p_scl when pinseq(1) :> void;

Expand All @@ -68,7 +69,8 @@ static void release_clock_and_wait(
// executing then the clock needs to be adjusted
const int wake_up_ticks = 10;
if (time > fall_time + delay + wake_up_ticks) {
fall_time = time - delay - wake_up_ticks;
fall_time = time - compute_low_period_ticks(kbits_per_second) - wake_up_ticks;
tmr when timerafter(fall_time + delay) :> void;
}
}

Expand All @@ -89,7 +91,7 @@ static int inline high_pulse_sample(
timer tmr;
p_sda :> int _;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
release_clock_and_wait(p_scl, fall_time, (bit_time * 3) / 4);
release_clock_and_wait(p_scl, fall_time, (bit_time * 3) / 4, kbits_per_second);
p_sda :> sample_value;
fall_time = fall_time + bit_time;
tmr when timerafter(fall_time) :> void;
Expand All @@ -111,13 +113,13 @@ static void inline high_pulse(

timer tmr;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
release_clock_and_wait(p_scl, fall_time, (bit_time * 3) / 4);
release_clock_and_wait(p_scl, fall_time, (bit_time * 3) / 4, kbits_per_second);
fall_time = fall_time + bit_time;
tmr when timerafter(fall_time) :> void;
p_scl <: 0;
}

/** Output a start bit. The function returns the 'fall time' i.e. the
/** Output a start bit. The function updates the 'fall_time', i.e. the
* reference clock time when the SCL line transitions to low.
*/
static void start_bit(
Expand All @@ -132,9 +134,8 @@ static void start_bit(
timer tmr;

if (!stopped) {
fall_time += compute_low_period_ticks(kbits_per_second);
tmr when timerafter(fall_time) :> fall_time;
release_clock_and_wait(p_scl, fall_time, compute_bus_off_ticks(kbits_per_second));
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
release_clock_and_wait(p_scl, fall_time, bit_time, kbits_per_second);
}

// Drive SDA low
Expand All @@ -160,7 +161,7 @@ static void stop_bit(
timer tmr;
p_sda <: 0;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
release_clock_and_wait(p_scl, fall_time, bit_time);
release_clock_and_wait(p_scl, fall_time, bit_time, kbits_per_second);
p_sda :> void;
delay_ticks(compute_bus_off_ticks(kbits_per_second));
}
Expand Down
23 changes: 12 additions & 11 deletions lib_i2c/src/i2c_master_single_port.xc
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@ static const unsigned inline compute_bus_off_ticks(
/** Reads back the SCL line, waiting until it goes high (in
* case the slave is clock stretching). It is assumed that the clock
* line has been release (driven high) before calling this function.
* Since the line going high may be delayed, the fall_time value may
* need to be adjusted
* Since the line going high may be delayed, the fall_time
* value may need to be adjusted
*/
static void wait_for_clock_high(
port p_i2c,
static const unsigned scl_bit_position,
unsigned &fall_time,
unsigned delay)
unsigned delay,
static const unsigned kbits_per_second)
{
const unsigned SCL_HIGH = BIT_MASK(scl_bit_position);

Expand All @@ -81,7 +82,8 @@ static void wait_for_clock_high(
// executing then the clock needs to be adjusted
const int wake_up_ticks = 10;
if (time > fall_time + delay + wake_up_ticks) {
fall_time = time - delay - wake_up_ticks;
fall_time = time - compute_low_period_ticks(kbits_per_second) - wake_up_ticks;
tmr when timerafter(fall_time + delay) :> void;
}
}

Expand All @@ -103,7 +105,7 @@ static void high_pulse_drive(
p_i2c <: SCL_LOW | sdaValue | other_bits_mask;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
p_i2c <: SCL_HIGH | sdaValue | other_bits_mask;
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, (bit_time * 3) / 4);
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, (bit_time * 3) / 4, kbits_per_second);
fall_time = fall_time + bit_time;
tmr when timerafter(fall_time) :> void;
p_i2c <: SCL_LOW | sdaValue | other_bits_mask;
Expand All @@ -126,7 +128,7 @@ static int high_pulse_sample(
p_i2c <: SCL_LOW | SDA_HIGH | other_bits_mask;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
p_i2c <: SCL_HIGH | SDA_HIGH | other_bits_mask;
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, (bit_time * 3) / 4);
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, (bit_time * 3) / 4, kbits_per_second);

int sample_value = peek(p_i2c);
if (sample_value & SDA_HIGH)
Expand Down Expand Up @@ -157,10 +159,9 @@ static void start_bit(
timer tmr;

if (!stopped) {
fall_time += compute_low_period_ticks(kbits_per_second);
tmr when timerafter(fall_time) :> fall_time;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
p_i2c <: SCL_HIGH | SDA_HIGH | other_bits_mask;
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, compute_bus_off_ticks(kbits_per_second));
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, bit_time, kbits_per_second);
}

p_i2c <: SCL_HIGH | SDA_LOW | other_bits_mask;
Expand All @@ -186,7 +187,7 @@ static void stop_bit(
p_i2c <: SCL_LOW | SDA_LOW | other_bits_mask;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
p_i2c <: SCL_HIGH | SDA_LOW | other_bits_mask;
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, bit_time);
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, bit_time, kbits_per_second);
p_i2c <: SCL_HIGH | SDA_HIGH | other_bits_mask;
delay_ticks(compute_bus_off_ticks(kbits_per_second));
}
Expand Down Expand Up @@ -256,7 +257,7 @@ void i2c_master_single_port(
p_i2c <: SCL_LOW | sda | other_bits_mask;
tmr when timerafter(fall_time + compute_low_period_ticks(kbits_per_second)) :> void;
p_i2c <: SCL_HIGH | sda | other_bits_mask;
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, (bit_time * 3) / 4);
wait_for_clock_high(p_i2c, scl_bit_position, fall_time, (bit_time * 3) / 4, kbits_per_second);
fall_time = fall_time + bit_time;
tmr when timerafter(fall_time) :> void;

Expand Down
4 changes: 2 additions & 2 deletions tests/test_master_clock_stretch.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ def test_master_clock_stretch(capfd, request, nightly, dir, speed, stop, arch):
checker = I2CMasterChecker("tile[0]:XS1_PORT_1A",
"tile[0]:XS1_PORT_1B",
tx_data = [0x99, 0x3A, 0xff],
expected_speed=170,
expected_speed=160,
clock_stretch=5000,
ack_sequence=[True, True, False, # Master write
True, # Master read
True, # Master read
True, True, True, False, # Master write
True, False], # Master write
#original_speed = speed
original_speed = speed # Timing checks use the original speed that the I2C master is configured to run at
)

tester = Pyxsim.testers.AssertiveComparisonTester(
Expand Down

0 comments on commit 5897cf4

Please sign in to comment.