Skip to content

I2C Master Wire.requestFrom timeout not obeyed, takes a whole second to read when slave is not present #5934

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
leifclaesson opened this issue Nov 27, 2021 · 37 comments
Assignees
Labels
Area: ESP-IDF related ESP-IDF related issues Area: Peripherals API Relates to peripheral's APIs. Status: Blocked by ESP-IDF Status: Needs investigation We need to do some research before taking next steps on this issue
Milestone

Comments

@leifclaesson
Copy link
Contributor

What you are trying to do?
I'm trying to read from an I2C device which is not always present.
With ESP32 Arduino 1.0.6, the read fails instantly as it should. With 2.0.1 it blocks for a full second (1000ms) every time.

This sketch will duplicate the error, no hardware required.

#include <Wire.h>

void setup()
{
	Serial.begin(115200);

	Wire.begin();
}

void loop()
{

	uint32_t time_before=millis();

	const int address=10;
	const int length=16;

	int rcvd = Wire.requestFrom(address, (uint8_t) length, (uint8_t) true);
	if(rcvd==length)
	{
		uint8_t data[length];
		Wire.readBytes(data, length);
	}

	Serial.printf("I2C: Received %u bytes in %u ms\n",rcvd,millis()-time_before);

	delay(250);
}

If run on a regular ESP32 board with Arduino Core version 1.0.6, each Wire.requestFrom completes instantly or within 1 millisecond. With 2.0.1 it takes 1001 milliseconds.

I discovered the issue when recompiling a large project with the new Arduino core, so I stripped it down until I found the issue, but I don't know what's causing it.

I followed the code into esp32-hal-i2c.c and attempted to change the last parameter of i2c_master_cmd_begin to a hardcoded 1, and it still took a full second to complete the failed read -- the parameter change made no difference at all, so it seems perhaps the issue is all the way down inside the IDF?

Hardware:

Board: Generic 38-pin ESP32 dev board
Core Installation version: 2.0.1 (and for reference 1.0.6)
IDE name: Sloeber 4.4.0
Flash Frequency: 40Mhz
PSRAM enabled: no
Upload Speed: 921600
Computer OS: Windows 10

Debug Messages:

I tried, there are no I2C related debug messages even on Verbose.
@me-no-dev me-no-dev self-assigned this Nov 27, 2021
@me-no-dev me-no-dev added the Status: Test needed Issue needs testing label Nov 27, 2021
@leifclaesson
Copy link
Contributor Author

Thanks @me-no-dev

@CarlosGS
Copy link

CarlosGS commented Dec 2, 2021

Looks related to espressif/esp-idf#4999

@leifclaesson
Copy link
Contributor Author

Looks related to espressif/esp-idf#4999

Now that you mention it yes, it does look similar.. but that thread is from April 2020 which is over a year ago. This was not a problem in 1.0.6 (as far as I could tell?) which is from March 2021 which is only 7 months ago at the time of this writing?

@CarlosGS
Copy link

CarlosGS commented Dec 8, 2021

Sorry I hadn't seen the dates. But since 1.0.6 is based on IDF v3.3.5 and that thread is about IDF v4.2, maybe the bug was introduced in between those IDF versions?

@leifclaesson
Copy link
Contributor Author

Sorry I hadn't seen the dates. But since 1.0.6 is based on IDF v3.3.5 and that thread is about IDF v4.2, maybe the bug was introduced in between those IDF versions?

Definitely possible. :)

@VojtechBartoska VojtechBartoska added the Area: Peripherals API Relates to peripheral's APIs. label Dec 13, 2021
@leifclaesson
Copy link
Contributor Author

Did you get a change to test it yet? The example code above requires no additional hardware to reproduce the issue.

@pgrawehr
Copy link
Contributor

I can definitelly confirm the bug. When there's no device listening on the given address, Wire.requestFrom takes at least 1 second before it returns.

@simondddd
Copy link

Is there a simple workaround for this?
I have tried to recompile the libraries using https://github.com/espressif/esp32-arduino-lib-builder modifying the driver i2c.c as seen in espressif/esp-idf#4999 but I get errors when I use the libraries I obtain.

@VojtechBartoska
Copy link
Contributor

hello guys, can you please validate if this is still present on v2.0.3-rc1? thanks

@VojtechBartoska VojtechBartoska added the Resolution: Awaiting response Waiting for response of author label Apr 8, 2022
@pgrawehr
Copy link
Contributor

@VojtechBartoska I have now checked with the current master (6cfe461) and unfortunately, the problem is unchanged. Wire.requestFrom(address, (byte)1) takes exactly 1 second when there's no device at the given address.

I did update the toolchain (by running get.exe), but do I need to update something else?

@VojtechBartoska VojtechBartoska removed the Resolution: Awaiting response Waiting for response of author label Apr 11, 2022
@VojtechBartoska
Copy link
Contributor

Hi, seems you did it right and this issue still persist. We will take a look on it.

@me-no-dev
Copy link
Member

The problem is here. I2C_CMD_ALIVE_INTERVAL_TICK is 1000ms and it seems that it's the minimum time to wait. I guess this should/can be considered a bug in IDF's I2C driver.

@VojtechBartoska would you report this?

@pgrawehr
Copy link
Contributor

@me-no-dev There's already a ticket at espressif/esp-idf#4999 Maybe you put your suggested fix there?

@VojtechBartoska
Copy link
Contributor

@me-no-dev Reported to the existing issue.

@VojtechBartoska VojtechBartoska moved this from Todo to Under investigation in Arduino ESP32 Core Project Roadmap Apr 28, 2022
@VojtechBartoska VojtechBartoska added Area: ESP-IDF related ESP-IDF related issues Status: Pending and removed Status: Test needed Issue needs testing labels Apr 28, 2022
@me-no-dev me-no-dev moved this from Under investigation to In Progress in Arduino ESP32 Core Project Roadmap May 9, 2022
@VojtechBartoska VojtechBartoska self-assigned this May 11, 2022
@VojtechBartoska
Copy link
Contributor

Thanks, let us please now, on which version did you test it?

@leifclaesson
Copy link
Contributor Author

leifclaesson commented Mar 21, 2024

Hello @leifclaesson, is this still valid?

Yes @VojtechBartoska, literally three years later the issue remains. I am still using v1.0.6 for all my projects that use I2C, and that is most of them.

I just tested with version 2.0.11, issue remains. A one second deadlock of the main thread completely breaks I2C bus scanning. I am surprised the issue has survived for three years considering how popular I2C is...

The sketch in my original problem report is still a valid test. You don't need any I2C hardware to run it, because the problem occurs when there is no I2C device connected on that bus. All you need is any ESP32 and the Arduino IDE.

It would be great to finally have a solution to this issue -- 1.0.6 is getting long in the tooth and missing more and more features compared to current versions, but with such a basic thing being broken for three years I and surely others are forced to stick with an outdated version that does handle the basics reliably.

@leifclaesson
Copy link
Contributor Author

To add a few more data points, it seems I am not alone in discovering this issue. I googled "esp32 i2c arduino timeout" and this is the first result.

If you notice, the replies are horrifyingly unhelpful, blaming his hardware and essentially saying "don't do that".
I don't think this is correct.
Conceptionally, the I2C bus has a master and multiple slaves. (Please forgive my non-PC terminology -- this is just simply what the I2C standard calls it.)
The master is the ESP32. The master toggles the CLOCK pin high and low, and selectively holds the DATA pin low, or not, to address and send data to a slave. Then, the master keeps toggling the CLOCK pin, reading the DATA pin so that the slave can respond -- or not. Other than for rare devices that do "clock stretching" by holding the clock pin down to give themselves more time to respond, timeouts do not ever enter into the equation. If a slave chooses not to respond, or if there is no slave present, all that happens is that the master immediately gets 0xFF in response -- all bits high.

Other than to support clock stretching, the master never waits for the slave!

So, why does the ESP32 Arduino core 2.0.1 and forward wait for a whole second -- an astronomically long time for a microcontroller -- for no reason?

1.0.6 and earlier versions do not have this problem at all. Calls return immediately, as they should. Timeout is not even a thing.

@leifclaesson
Copy link
Contributor Author

I ran into the same problem: IMU sensor hanging for 1 second a couple times per minute...

As a workaround I've created a fast bit-bang I2C lib, maybe it is of use for somebody else: https://github.com/qqqlab/ESP32_SoftWire

Thank you for this, @qqqlab ! Definitely keeping this around for a rainy day. I've used the standard SoftWire library plenty on ESP32, and it has worked fine, pretty sure it can't do 3 MHz like yours though.

@shalomberm
Copy link

Any updates for this?

@VojtechBartoska
Copy link
Contributor

we will recheck, assigning to 3.0.5 milestone.

@lucasssvaz will you be please be able to retest this with version 3.0.4? thanks

@VojtechBartoska VojtechBartoska added this to the 3.0.5 milestone Aug 22, 2024
@VojtechBartoska VojtechBartoska added Status: Needs investigation We need to do some research before taking next steps on this issue and removed Resolution: Awaiting response Waiting for response of author labels Aug 22, 2024
@shalomberm
Copy link

For anyone that needs a quick fix you can do

Wire.beginTransmission(_addr);
if (Wire.endTransmission() == 0)
    Wire.requestFrom(_addr, x);

since endTransmition doesnt take up any extra time. Hope this helps

@lucasssvaz lucasssvaz self-assigned this Aug 31, 2024
@lucasssvaz
Copy link
Collaborator

lucasssvaz commented Aug 31, 2024

A fix for this issue was added recently to IDF. Does this still happens in 3.0.x ?

@pgrawehr
Copy link
Contributor

I just updated to the latest master of the Arduino-ESP SDK and yes, it is a lot better than before. A full I2C bus scan now takes aroun 30 seconds, while previously it was much more (can't remember exactly, though). That is still a lot worse than on an Arduino Uno or similar board.

Maybe this could be further improved if that timeout was configurable (is it already?)

@lucasssvaz
Copy link
Collaborator

@pgrawehr It already is with Wire.setTimeOut(time_in_ms). By default it is 50 ms, I haven't tried using lower values though

@gian-didom
Copy link

I am experiencing the same problem and can confirm that the latest version of the SDK does not fix the issue. I still have a 1000ms minimum timeout despite setting it to 50 ms.

@VojtechBartoska VojtechBartoska modified the milestones: 3.0.5, 3.1.0 Oct 21, 2024
@VojtechBartoska
Copy link
Contributor

@lucasssvaz Do you know if there have been any updates regarding this?

@lucasssvaz
Copy link
Collaborator

This might be due to I2C_CMD_ALIVE_INTERVAL_TICK being to high: https://github.com/espressif/esp-idf/blob/release/v5.3/components/driver/i2c/i2c.c#L84

I have not tested but using Arduino as a component and lowering this value might result in a shorter timeout.

@rftafas rftafas modified the milestones: 3.1.0, 3.1.1 Jan 6, 2025
@rftafas rftafas modified the milestones: 3.1.1, 3.2.0 Jan 14, 2025
@Parsaabasi Parsaabasi modified the milestones: 3.2.0, 3.3.0 Mar 12, 2025
@Jason2866
Copy link
Collaborator

closing since outdated. Please open a new issue if the issue still exists with actual Arduino core

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: ESP-IDF related ESP-IDF related issues Area: Peripherals API Relates to peripheral's APIs. Status: Blocked by ESP-IDF Status: Needs investigation We need to do some research before taking next steps on this issue
Projects
Development

No branches or pull requests