espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
12.99k stars 7.29k forks source link

ESP32-S2 I2C 1000ms to execute i2c_master_cmd_begin #9177

Open astrogene1000 opened 5 months ago

astrogene1000 commented 5 months ago

Board

ESP32-S2 based

Device Description

Multiple I2C devices

Hardware Configuration

GPIO 11 & 12 connected to I2C

Version

latest master (checkout manually)

IDE Name

1.8.19 with Arduino 3.0.0-Alpha3

Operating System

W10

Flash frequency

As per S2 spec

PSRAM enabled

yes

Upload speed

115200

Description

Hello all,

Wondering what is causing a delay on I2C when there is no pullup on SDA or SCL.

Now why no pull-up: 1) Connected to multiple I2C devices, each has a pullup, if cable is pulled the higher level program querying the ESP times out because the ESP is stuck in I2C write so cannot process the higher level program query.

I am using Wire library which provides wire.cpp which calls i2cWrite in esp32-hal-i2c.c which calls ret = i2c_master_cmd_begin((i2c_port_t)i2c_num, cmd, timeOutMillis / portTICK_PERIOD_MS);

Now whether I have timeoutMillis set to 5 or 50 or whatever, it is taking 1000ms for i2c_master_cmd_begin((i2c_port_t)i2c_num, cmd, timeOutMillis / portTICK_PERIOD_MS); to return.

During this 1000ms the SCL is gating out at my set frequency of 100khz See attached JPG

S2_i2c_1000ms_2

Thank you for you time!

Gene

Sketch

#include <Wire.h>

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("Setup");
  // put your setup code here, to run once:
Wire.begin(12,11, 100000); 
}
unsigned int lastError = 0;
void loop() {
  // put your main code here, to run repeatedly:
  Wire.beginTransmission(0xf);
  Wire.write((uint8_t)0x83);
  lastError = Wire.endTransmission();
  Serial.printf("Last Error = %d\r\n",lastError);
}

Debug Message

16:04:49.275 -> Last Error = 2
16:04:50.261 -> Last Error = 5

Other Steps to Reproduce

I also see same when using Arduino 2.0.14 Espessif.

I have checked existing issues, online documentation and the Troubleshooting Guide

Jason2866 commented 5 months ago

i2c bus without pull up resistors is using out of specs. Don't expect anything working when doing this. On a bus the last device should have this resistors.

astrogene1000 commented 5 months ago

Sorry but the line state should not affect timeout's as to when the framework returns control to the calling program. The time span is always almost exactly 1000ms, not something random.

TD-er commented 4 months ago

Actually it does make a difference as I2C also supports something like clock stretching. This is when a device can keep a pin (I think it is SCL, but could also be SDA) low to indicate it isn't ready yet.

IMHO this was an awful design decision, but we're stuck with it and thus also with sensors so poorly designed they actually need this clock stretching to work. (I3C no longer has this 'feature' :) )

Anyway, having the pins 'floating' or continuously 'pulled down' is undefined behavior and will cause timeouts as you're seeing.

If you want to see when this waiting actually occurs, you can set some other GPIO pins high/low in your code and add them to your logic analyzer. Since the write function and endTransmission both return some kind of result, it is essential that the data has been sent or at least attempted to be sent.

astrogene1000 commented 4 months ago

Totally appreciate what you are saying but will add the 1000ms seen is totally arbitrary and controlled someplace inside the framework. The ask here would be to expose allowing to set this timeout also.

TD-er commented 4 months ago

You may need to check the code, but if my memory serves me right, then this timeout was coupled to the clock stretch timeout and I think there is some function to set the clock stretch. (at least there was some debate about it a while ago, when issues with clock stretching needs were raised for ESP32)

Whether this is strictly correct to consider "clock stretching" the same as timeout is up for debate, but I think these are now linked in ESP32 code.

Jason2866 commented 4 months ago

The clock stretching timeout is set here https://github.com/tasmota/arduino-esp32/blob/main/cores/esp32/esp32-hal-i2c.c#L133

TD-er commented 4 months ago

By the way, it seems like the I2C pins are by default also pulled up internally. See: https://github.com/tasmota/arduino-esp32/blob/fc1114d28e2957062459de2e99def2c04e1eec71/cores/esp32/esp32-hal-i2c.c#L115-L116 So if yours are not "high" then I guess you might be using pins that will be pulled down externally?

astrogene1000 commented 4 months ago

@TD-er, correct, the pullup's are on the far end.

@Jason2866 so following it through, //Clock Stretching Timeout: 20b:esp32, 5b:esp32-c3, 24b:esp32-s2 i2c_set_timeout((i2c_port_t)i2c_num, I2C_LL_MAX_TIMEOUT);

So basically set it to the largest value that fit's in 24 bits for an ESP32-s2 From: components/hal/esp32s2/include/hal/i2c_ll.h

define I2C_LL_MAX_TIMEOUT I2C_TIME_OUT_REG_V

With components/soc/esp32s2/include/soc/i2c_reg.h

define I2C_TIME_OUT_REG_V 0xFFFFFF

Got it!

Thank you!

Gene