8000 extmod/machine_i2c: Add clock stretching support. · sparkfun/circuitpython@ec078af · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit ec078af

Browse files
deshipudpgeorge
authored andcommitted
extmod/machine_i2c: Add clock stretching support.
When the clock is too fast for the i2c slave, it can temporarily hold down the scl line to signal to the master that it needs to wait. The master should check the scl line when it is releasing it after transmitting data, and wait for it to be released. This change has been tested with a logic analyzer and an i2c slace implemented on an atmega328p using its twi peripheral, clocked at 8Mhz. Without the change, the i2c communication works up to aboy 150kHz frequency, and above that results in the slave stuck in an unresponsive state. With this change, communication has been tested to work up to 400kHz.
1 parent 1f69b16 commit ec078af

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

extmod/machine_i2c.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434

3535
#if MICROPY_PY_MACHINE_I2C
3636

37+
// Clock stretching limit, so that we don't get stuck.
38+
#define I2C_STRETCH_LIMIT 255
39+
3740
typedef struct _machine_i2c_obj_t {
3841
mp_obj_base_t base;
3942
uint32_t us_delay;
@@ -53,6 +56,11 @@ STATIC void mp_hal_i2c_scl_low(machine_i2c_obj_t *self) {
5356

5457
STATIC void mp_hal_i2c_scl_release(machine_i2c_obj_t *self) {
5558
mp_hal_pin_od_high(self->scl);
59+
mp_hal_i2c_delay(self);
60+
// For clock stretching, wait for the SCL pin to be released, with timeout.
61+
for (int count = I2C_STRETCH_LIMIT; mp_hal_pin_read(self->scl) == 0 && count; --count) {
62+
mp_hal_delay_us_fast(1);
63+
}
5664
}
5765

5866
STATIC void mp_hal_i2c_sda_low(machine_i2c_obj_t *self) {
@@ -71,7 +79,6 @@ STATIC void mp_hal_i2c_start(machine_i2c_obj_t *self) {
7179
mp_hal_i2c_sda_release(self);
7280
mp_hal_i2c_delay(self);
7381
mp_hal_i2c_scl_release(self);
74-
mp_hal_i2c_delay(self);
7582
mp_hal_i2c_sda_low(self);
7683
mp_hal_i2c_delay(self);
7784
}
@@ -81,7 +88,6 @@ STATIC void mp_hal_i2c_stop(machine_i2c_obj_t *self) {
8188
mp_hal_i2c_sda_low(self);
8289
mp_hal_i2c_delay(self);
8390
mp_hal_i2c_scl_release(self);
84-
mp_hal_i2c_delay(self);
8591
mp_hal_i2c_sda_release(self);
8692
mp_hal_i2c_delay(self);
8793
}
@@ -108,14 +114,12 @@ STATIC int mp_hal_i2c_write_byte(machine_i2c_obj_t *self, uint8_t val) {
108114
}
109115
mp_hal_i2c_delay(self);
110116
mp_hal_i2c_scl_release(self);
111-
mp_hal_i2c_delay(self);
112117
mp_hal_i2c_scl_low(self);
113118
}
114119

115120
mp_hal_i2c_sda_release(self);
116121
mp_hal_i2c_delay(self);
117122
mp_hal_i2c_scl_release(self);
118-
mp_hal_i2c_delay(self);
119123

120124
int ret = mp_hal_i2c_sda_read(self);
121125
mp_hal_i2c_delay(self);
@@ -150,7 +154,6 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
150154
uint8_t data = 0;
151155
for (int i = 7; i >= 0; i--) {
152156
mp_hal_i2c_scl_release(self);
153-
mp_hal_i2c_delay(self);
154157
data = (data << 1) | mp_hal_i2c_sda_read(self);
155158
mp_hal_i2c_scl_low(self);
156159
mp_hal_i2c_delay(self);
@@ -163,7 +166,6 @@ STATIC int mp_hal_i2c_read_byte(machine_i2c_obj_t *self, uint8_t *val, int nack)
163166
}
164167
mp_hal_i2c_delay(self);
165168
mp_hal_i2c_scl_release(self);
166-
mp_hal_i2c_delay(self);
167169
mp_hal_i2c_scl_low(self);
168170
mp_hal_i2c_sda_release(self);
169171

0 commit comments

Comments
 (0)
0