1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-21 10:26:06 +03:00

Double I2C read in one transaction skips a clock pulse (#5528) (#6654)

* Double I2C read in one transaction skips a clock pulse (#5528)

See https://github.com/esp8266/Arduino/issues/5528  and the more elaborate [description](https://github.com/maarten-pennings/I2C-tool/blob/master/I2Ctest8266/README.md#how-to-fix)
where @maarten-pennings did all the hard work, but as far as I could see, no PR was made.

I also noticed some code duplication, which I moved to separate functions.

According to [this documentation on I2C clock stretching](https://www.i2c-bus.org/clock-stretching/) it is not allowed to have some slave keep the clock low during transmission of a byte, only after an ack.
So that's why it is not done in the while loop.
But I wondered if there should be an extra delay between the sequence of pulses and the extra added clock "valley". See my comment in the code.

Fixes #5528

* [I2C] Restore clock stretch functionality during transfer

As requested here: 8357a8c644 (r339310509)

* [I2C] Move duplicated clock stretch call to twi_scl_valley function
This commit is contained in:
Gijs Noorlander 2019-10-27 04:59:19 +01:00 committed by Earle F. Philhower, III
parent 5d0b9aa5ac
commit 36c369bb8f

View File

@ -128,6 +128,8 @@ private:
} }
} }
// Generate a clock "valley" (at the end of a segment, just before a repeated start)
void twi_scl_valley(void);
public: public:
void setClock(unsigned int freq); void setClock(unsigned int freq);
@ -386,13 +388,16 @@ unsigned char Twi::writeTo(unsigned char address, unsigned char * buf, unsigned
{ {
write_stop(); write_stop();
} }
else
{
twi_scl_valley();
// TD-er: Also busywait(twi_dcount) here?
// busywait(twi_dcount);
}
i = 0; i = 0;
while (!SDA_READ() && (i++) < 10) while (!SDA_READ() && (i++) < 10)
{ {
SCL_LOW(); twi_scl_valley();
busywait(twi_dcount);
SCL_HIGH();
WAIT_CLOCK_STRETCH();
busywait(twi_dcount); busywait(twi_dcount);
} }
return 0; return 0;
@ -422,13 +427,16 @@ unsigned char Twi::readFrom(unsigned char address, unsigned char* buf, unsigned
{ {
write_stop(); write_stop();
} }
else
{
twi_scl_valley();
// TD-er: Also busywait(twi_dcount) here?
// busywait(twi_dcount);
}
i = 0; i = 0;
while (!SDA_READ() && (i++) < 10) while (!SDA_READ() && (i++) < 10)
{ {
SCL_LOW(); twi_scl_valley();
busywait(twi_dcount);
SCL_HIGH();
WAIT_CLOCK_STRETCH();
busywait(twi_dcount); busywait(twi_dcount);
} }
return 0; return 0;
@ -649,6 +657,14 @@ void ICACHE_RAM_ATTR Twi::onTwipEvent(uint8_t status)
} }
} }
void Twi::twi_scl_valley(void)
{
SCL_LOW();
busywait(twi_dcount);
SCL_HIGH();
WAIT_CLOCK_STRETCH();
}
void ICACHE_RAM_ATTR Twi::onTimer(void *unused) void ICACHE_RAM_ATTR Twi::onTimer(void *unused)
{ {
(void)unused; (void)unused;