Arduino-esp32: I2C not working on ESP32

Created on 18 Oct 2017  ·  57Comments  ·  Source: espressif/arduino-esp32

Hardware:

Board: ESP32 Dev Module
Core Installation/update date: 11/jul/2017
IDE name: Arduino IDE
Flash Frequency: 40Mhz
Upload Speed: 115200

Description:

I am not able to generate the I2C clock. I have an ST microelectronics accelerator that I am using which has an I2C interface. So just wanted to see if I2C is working.

I have seen many people running into the same problem but could not find a solution for this issue. No errors generated when compiling the code.

Please find my code below.

Sketch:

//Change the code below by your sketch

include "Wire.h"

void setup() {
Wire.begin(21,22);
Serial.begin(115200);
Wire.setClock(400000); // choose 400 kHz I2C rate
Serial.println("Start i2c-test");
}

void loop() {
byte error;

// 0x20 is the address of a pcf8574 GPIO expander
Serial.println("Try to contact 0x20");
uint8_t data = 0;
// Wire.beginTransmission(0x3A);
// error = Wire.endTransmission();
Wire.beginTransmission(0x3B); // Initialize the Tx buffer
Wire.write(0x0F); // Put WHO_AM_I address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(0x3B, 1); // Read two bytes from slave PROM address
while (Wire.available()) {
data = Wire.read(); } // Put read results in the Rx buffer
Serial.print("Error code is:");
Serial.println(data);

delay(1000);
}

Most helpful comment

@njbuch
End of the week, I'll have another release that includes tested and working code for both peripherals, This fix is included, Perhaps I'll have Slave Mode included.

Chuck.

All 57 comments

@muktillc , in issue #90 I commented a possible solution.
Here is a I2C scanner that works on ESP32's
The Debug output shows my problem. The first section of output is what happens when the SDA line is held low by the ESP32. I touched EN(reset) on my WeMos bluetooth&battery. The reset cleared the SDA line and the scan successfully worked on the second attempt.

My system:

5v segment

0x20,0x21 (MCP23008) I/O expanders connected to 4x4 matrix and 20x4 LCD
0x50 24LC32 EEPROM
0x68 DS1307 RTC

3.3v segment

0x51,0x55,0x56 24LC512
0x52,0x53,0x54 24LC64

Scanner Code

/* I2C slave Address Scanner
for 5V bus
 * Connect a 4.7k resistor between SDA and Vcc
 * Connect a 4.7k resistor between SCL and Vcc
for 3.3V bus
 * Connect a 2.4k resistor between SDA and Vcc
 * Connect a 2.4k resistor between SCL and Vcc

 */

#include <Wire.h>

void scan(){
Serial.println(" Scanning I2C Addresses");
uint8_t cnt=0;
for(uint8_t i=0;i<128;i++){
  Wire.beginTransmission(i);
  uint8_t ec=Wire.endTransmission(true);
  if(ec==0){
    if(i<16)Serial.print('0');
    Serial.print(i,HEX);
    cnt++;
  }
  else Serial.print("..");
  Serial.print(' ');
  if ((i&0x0f)==0x0f)Serial.println();
  }
Serial.print("Scan Completed, ");
Serial.print(cnt);
Serial.println(" I2C Devices found.");
}

bool i2cReady(uint8_t adr){
uint32_t timeout=millis();
bool ready=false;
while((millis()-timeout<100)&&(!ready)){
    Wire.beginTransmission(adr);
    ready=(Wire.endTransmission()==0);
    }
return ready;
}

void eepromSize(){
Serial.println("Discovering eeprom sizes 0x50..0x57");
uint8_t adr=0x50,i;
uint16_t size;
char buf[64];
while(adr<0x58){
    i=0;
    size = 0x1000; // Start at 4k
    i += sprintf_P(&buf[i],PSTR("0x%02X: "),adr);
    if(i2cReady(adr)) { // EEPROM answered
        uint8_t zeroByte;
        Wire.beginTransmission(adr);
        Wire.write((uint8_t)0); // set address ptr to 0, two bytes High
        Wire.write((uint8_t)0); // set address ptr to 0, two bytes Low
        uint8_t err=Wire.endTransmission();
        if(err==0){// worked
          err=Wire.requestFrom(adr,(uint8_t)1);
            if(err==1){// got the value of the byte at address 0
                zeroByte=Wire.read();
                uint8_t saveByte,testByte;
                do{
                    if(i2cReady(adr)){
                        Wire.beginTransmission(adr);
                        Wire.write(highByte(size)); // set next test address
                        Wire.write(lowByte(size));
                        Wire.endTransmission();
                        err=Wire.requestFrom(adr,(uint8_t)1);
                        if(err==1){
                            saveByte=Wire.read();
                            Wire.beginTransmission(adr);
                            Wire.write(highByte(size)); // set next test address
                            Wire.write(lowByte(size));
                            Wire.write((uint8_t)~zeroByte); // change it
                            err=Wire.endTransmission();
                            if(err==0){ // changed it
                                if(!i2cReady(adr)){
                                    i+=sprintf_P(&buf[i],PSTR(" notReady2.\n"));
                                    Serial.print(buf);
                                    adr++;
                                    break;
                                    }
                                Wire.beginTransmission(adr);
                                Wire.write((uint8_t)0); // address 0 byte High
                                Wire.write((uint8_t)0); // address 0 byte Low
                                err=Wire.endTransmission();
                                if(err==0){
                                    err=Wire.requestFrom(adr,(uint8_t)1);
                                    if(err==1){ // now compare it
                                      testByte=Wire.read();
                                        }
                                    else {
                                        testByte=~zeroByte; // error out
                                        }
                                    }
                                else {
                                    testByte=~zeroByte;
                                    }
                                }
                            else {
                                testByte = ~zeroByte;
                                }
                            //restore byte
                            if(!i2cReady(adr)){
                                i+=sprintf_P(&buf[i],PSTR(" notReady4.\n"));
                                Serial.print(buf);
                                adr++;
                                break;
                                }

                            Wire.beginTransmission(adr);
                            Wire.write(highByte(size)); // set next test address
                            Wire.write(lowByte(size));
                            Wire.write((uint8_t)saveByte); // restore it
                            Wire.endTransmission();
                            }
                        else testByte=~zeroByte;
                        }
                    else testByte=~zeroByte;
                    if(testByte==zeroByte){
                        size = size <<1;
                        }
                    }while((testByte==zeroByte)&&(size>0));
                if(size==0) i += sprintf_P(&buf[i],PSTR("64k Bytes"));
                else i+=sprintf_P(&buf[i],PSTR("%dk Bytes"),size/1024);
                if(!i2cReady(adr)){
                    i+=sprintf_P(&buf[i],PSTR(" notReady3.\n"));
                    Serial.print(buf);
                    adr++;
                    continue;
                    }
                Wire.beginTransmission(adr);
                Wire.write((uint8_t)0); // set address ptr to 0, two bytes High
                Wire.write((uint8_t)0); // set address ptr to 0, two bytes Low
                Wire.write(zeroByte);  //Restore
                err=Wire.endTransmission();
                }
            else i+=sprintf_P(&buf[i],PSTR("Read 0 Failure"));
            }
        else i+=sprintf_P(&buf[i],PSTR("Write Adr 0 Failure"));

      }
    else i+=sprintf_P(&buf[i],PSTR("Not Present."));
    Serial.println(buf);
    adr++;
    }
}

void setup(){
Serial.begin(115200);
Wire.begin();
scan();
Serial.println();
eepromSize();
}

void loop(){}

Debug Output

 Scanning I2C Addresses
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
Scan Completed, 0 I2C Devices found.

Discovering eeprom sizes 0x50..0x57
0x50: Not Present.
0x51: Not Present.
0x52: Not Present.
0x53: Not Present.
0x54: Not Present.
0x55: Not Present.
0x56: Not Present.
0x57: Not Present.
ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0010,len:4
load:0x3fff0014,len:572
load:0x40078000,len:0
load:0x40078000,len:9880
entry 0x400789d8
 Scanning I2C Addresses
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
20 21 .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
50 51 52 53 54 55 56 .. .. .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. 68 .. .. .. .. .. .. .. 
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. 
Scan Completed, 10 I2C Devices found.

Discovering eeprom sizes 0x50..0x57
0x50: 4k Bytes
0x51: 64k Bytes
0x52: 8k Bytes
0x53: 8k Bytes
0x54: 8k Bytes
0x55: 64k Bytes
0x56: 64k Bytes
0x57: Not Present.

Chuck.

hello @muktillc
any particullar reason your not using designated wire ports (22/23) or is it just a typo in your code?

I thought the designated ports are pins 21 and 22. Are they 22 and 23??

On Oct 18, 2017 6:58 AM, "EBZ-Krisemendt" notifications@github.com wrote:

hello @muktillc https://github.com/muktillc
any particullar reason your not using designated wire ports (22/23) or is
it just a typo in your code?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/espressif/arduino-esp32/issues/741#issuecomment-337552527,
or mute the thread
https://github.com/notifications/unsubscribe-auth/Aetc8NKnzoqcb76-H5OEGBDso5P7oPmrks5stdnSgaJpZM4P854w
.

shame on me, it's 22/23 on adafruit huzzah32. it's indeed 21/22 on official dev-board, sorry

one quick question regarding the SPI. I am trying to get the SPI work and my
sensor is responding but for some reason the MISO pin (pin #19) is not
accepting
any input. I tested the output of the sensor and it gives the expected
output for the WHO_AM_I register but as soon as I connect the SDO of the
sensor to MISO, the output goes down to zero and I don't see anything
oscilloscope. Wondering if you have seen anything like this.

On Wed, Oct 18, 2017 at 7:07 AM, EBZ-Krisemendt notifications@github.com
wrote:

shame on me, it's 22/23 on adafruit huzzah32. it's indeed 21/22 on
official dev-board, sorry


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/espressif/arduino-esp32/issues/741#issuecomment-337555283,
or mute the thread
https://github.com/notifications/unsubscribe-auth/Aetc8F32vTnT-El7hVBV2kiPItKpFq3bks5stdvcgaJpZM4P854w
.

pin 19 is working fine here :) bad soldering? something else pulling the pin?

Sorry for the late reply. I was able to get this part working and the SPI works as desired. I had to change the pin 19 to pin 22 for my code and it seems to be working. However, I ran into another issue, which was my original problem. I have a AT30TS75 temperature sensor which only has I2C. I could not get I2C working on pin 21 and 22 using Arduino IDE, which I believe are the default pins. I was wondering if there is a way to change the pins from 21 and 22 to 32 and 33. How do i do it?

@muktillc
I think I found and issue with the ReStart operation. In your Example:

/ 0x20 is the address of a pcf8574 GPIO expander
Serial.println("Try to contact 0x20");
uint8_t data = 0;
// Wire.beginTransmission(0x3A);
// error = Wire.endTransmission();
Wire.beginTransmission(0x3B); // Initialize the Tx buffer
Wire.write(0x0F); // Put WHO_AM_I address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(0x3B, 1); // Read two bytes from slave PROM address
while (Wire.available()) {
data = Wire.read(); } // Put read results in the Rx buffer
Serial.print("Error code is:");
Serial.println(data);
delay(1000);
}

Is that Restart( Wire.endTransmission(false);) necessary for the correct operation of your sensor?
If your sensor requires the restart, I think we'll have to make a new function in Wire() because I think the hardware cannot hang the bus waiting after the sendStop=false;. An I2C bus timeOut will occur.

If you want to test my theory out I'll write a function that you can insert into your ESP source files
Arduino\hardware\espressif\esp32\cores\esp32\esp32-hal-i2c.c
Arduino\hardware\espressif\esp32\cores\esp32\esp32-hal-i2c.h
Arduino\hardware\espressif\esp32\libraries\Wire\src\Wire.cpp
Arduino\hardware\espressif\esp32\libraries\Wire\src\Wire.h

uint8_t Wire.transact(const uint8_t ID,uint8_t* writeBytes,const uint8_t writeLen, const uint8_t readLen);

to use it with your example:

uint8_t writeBuf[10];
uint8_t writeLen=0;
writeBuf[writeLen++] = 0x0f; //build command buffer

uint8_t err=Wire.transact(0x3B,writeBuf,writeLen,1);
if(err!=1){ // bogus, Bad stuff
  Serial.print("error during transact");
  }
else{
  while (Wire.available()) {
    Serial.printf("%d ",Wire.read();
    }

Chuck.

@muktillc check out my message #839 . It may be a solution for your problems.

Chuck.

I believe I'm seeing this also, through the https://github.com/adafruit/Adafruit_BME280_Library library which uses Wire under the hood. I just purchased some dev modules hoping to use I2c, but can't get anything function. Hoping this all gets straitened out soon, so thanks for working on it.

I am seeing this as well. Tryed several weird pin-defs - with no luck. Still not sure which is the official I2C pins on my "LOLIN32 Lite" board.

My last attempt, not working, was the following (only snippet).

#define I2C_SDA_PIN 23
#define I2C_SCL_PIN 22

void setup()
{
  Serial.begin(115200);                                            
  Wire.begin( I2C_SDA_PIN, I2C_SCL_PIN, 1000000 );

@njbuch try one of my branches, either Main or Wire-Destructor. My latest Releaset V0.2.0 has a zip file that contains only the required files. These required files are just copied over the files from this repo.

Also, you are specifying the i2c Bus to operate at 1MHz?

I2C has two recognized speeds 100KHz and 400KHz. As the speed increases the Pullup resistor values need to decrease. Check out my Wiki page on resistor value considerations: Pullup Considerations At 1MHz I doubt you have low enough values of resistors for the bus to return to HIGH between bits, also if you do have low enough value, you are approaching the limits of the output drivers.

Chuck.

@stickbreaker thanks for getting back, and putting in the effort to fix this. I am on PlatformIO and your repository is quite a few commits behind on the platformio configuration, and I am too much a beginner to be able to partialle merge two fundamental repositories, but I am still interested in helping, if I can get a few more details on building/testing. You describe a Release-Set zipfile? Which I cannot find. Thanks again :)

@njbuch I don't use platformIO I have no Idea how it is different than using the Arduino environment.

My main repo is only one merge behind espressif/arduino-esp32 merge 1208, fix_SerialBT_read

Does platformIO download the repo every compile? if not just swap in the files from the lastest release zip arduino-esp32-stickbreaker-v0.2.0.zip

past that I don't know how to support platformIO.

Chuck.

Superb, I just did what this suggest, with your file and the input from:https://github.com/stickbreaker/arduino-esp32/issues/16. And it compiles. The output has changed from "Busy timeout errors" to simply no readings.

I am on the LOLIN32-Lite board, and I have connected SCL->22 and SDA->23 with a revised Wire.begin(23,22) (with no frequency ;) ) and the sensor is a BME280.

@njbuch post your I2c reading code:

chuck.

I have just realized that Pin22 is actually also the built-in led. Wat!? I am looking at https://wiki.wemos.cc/_media/products:lolin32:sch_lolin32_lite_v1.0.0.pdf right now, to find out what pins might make most sense...
```

include

include // required by BME280 library

include // import BME280 template library

define I2C_SDA_PIN 23

define I2C_SCL_PIN 22

BME280<> BMESensor; // instantiate sensor

void setup()
{
Serial.begin(115200); // initialize serial
// initialize I2C that connects to sensor
Wire.begin( I2C_SDA_PIN, I2C_SCL_PIN );
BMESensor.begin(); // initalize bme280 sensor
}

void loop() {
BMESensor.refresh(); // read current sensor data

Serial.print("Temperature: ");
Serial.print(BMESensor.temperature); // display temperature in Celsius
Serial.println("C");

Serial.print("Humidity: ");
Serial.print(BMESensor.humidity); // display humidity in %
Serial.println("%");

Serial.print("Pressure: ");
Serial.print(BMESensor.pressure / 100.0F); // display pressure in hPa
Serial.println("hPa");

delay(1000); // wait a while before next loop
}

look through your BME280_t library for any Wire.begin(); statements I just realized that callingWire.begin() without any parameters will use the default values i.e SDA, SCL. So if the BME280_t library re-inits Wire() it is equivalent to Wire.begin(21,22);

Inside wire.cpp at TwoWire::begin() replace the two if(pin) with

  if(sdaPin < 0) { // default param passed
    if(num == 0) {
      if(sda==-1) sdaPin = SDA; //use Default Pin
      else sdaPin = sda; // reuse prior pin
      } 
    else {
      if(sda==-1) {
        log_e("no Default SDA Pin for Second Peripheral");
        return; //no Default pin for Second Peripheral
        }        
      else sdaPin = sda; // reuse prior pin
      }
    }

  if(sclPin < 0) { // default param passed
    if(num == 0) {
      if(scl==-1) sclPin = SCL; // use Default pin
      else sclPin = scl; // reuse prior pin
      }
    else {
      if(scl==-1){
        log_e("no Default SCL Pin for Second Peripheral");
        return; //no Default pin for Second Peripheral
        }
      else sclPin = scl; // reuse prior pin
      }
    }

Try that.
Chuck.

@stickbreaker you are the hero of day - right there! Its working like a charm. 👍
Temperature: 25.18C Humidity: 34.29% Pressure: 1011.40hPa

@njbuch
End of the week, I'll have another release that includes tested and working code for both peripherals, This fix is included, Perhaps I'll have Slave Mode included.

Chuck.

@stickbreaker, you are indeed a hero! I have one BME280 and two SSD1306 LED displays on I2C and a ESP32. I also ran into this issue where the ESP32 would consistently freeze after ~10 minutes, looping forever on esp32-hal-i2c timeout errors (or something like that). Replacing those five files from your link above seems to have fix it right up. The ESP32 has been reporting humidity/temps now all day with no issues!

\librariesWire\scrWire.h
\librariesWire\scrWire.cpp
\cores\esp32\esp32-hal-i2c.h
\cores\esp32\esp32-hal-i2c.c
\cores\esp32\esp32-hal-log.h

arduino-esp32-stickbreaker-v0.2.0.zip

How do I update to use the fixed version?

@xaque208
You can use the link in my prior message to get a zip archive that only contains the five required files. Just replace the five matching files in the ../hardware/Espressif/esp32 with these new files.

Chuck

I've checked out the git repo with from the stickbreaker-i2c branch. I think github swallowed the link above.

I put a link to @stickbreaker releases and a small explanation how to use it into the Wiki

Will this code make it into the mainline master branch at some point, or will this remain a fork?

@xaque208 me-no-dev created a staging branch stickbreaker-i2c in this repo, we are just testing it before merging. Hopefully the need for my fork will disappear in the next couple of week. Then we can have a stable and reliable i2c subsystem.

Chuck.

Any update on the merge? I am also encountering issues with I2C, and tried to incorporate your changes, but unfortunately I cannot compile your code (it complaining about some missing functions). It did work when I copied your full esp32 library strangely enough.

Dear @tomlevels, they created a branch at https://github.com/espressif/arduino-esp32/tree/stickbreaker-i2c. I just tried to download it using Git Gui and it seems to be working. Go to menu Branch > Checkout, select "tracking branch"

I tried that branch right now but from time to time I still get problems communicating with DS3231 RTC. I don't get any visible error output apart from ([E][esp32-hal-i2c.c:1113] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init).
This makes it impossible to communicate properly with the RTC and therefore i cannot get the time properly :/

@stickbreaker any clues?

@maribeiro Based on your extensive and comprehensive error report, I would say the purple wire shouldn't be touching the chartreuse square. :grinning: Don't cross the beams!

That is my best guess. Wither or not it applies to your situation, you will have to decide.

Change the debug level, to at least ERROR, you could go clear up to INFO. If you have the debug set to ERROR and you are not seeing any output on the Serial monitor, I2C is not encountering any errors. If you cannot read or set the device it points to an hardware error usually, or your software logic has failed.

What is your circuit? What is the value of your pullups? How long is your I2C bus? What devices are on the bus? It is all 3.3V or do you have logic level converters to other voltages?

In my stickbreaker repo, there are two example sketches in the Wire library. Try the i2c_scan.ino

here is a little test:

Wire.beginTransmission(0x68);
Wire.write(0x0);
uint8_t err = Wire.endTransmission(true);
if(err!= 0){
  Serial.println("RTCC not present at address 0x68.");
} 
else {
  err = Wire.requestFrom(0x68,12,true);
  if(err !=12){
    Serial.printf(" requestFrom Failed, expected 12 bytes, received =%d\nError %d (%s)\n",err,Wire.lastError()),Wire.getErrorText(Wire.lastError)));
    }
  else { // display it
    while(Wire.available()){
      Serial.printf("0x%02X ",Wire.read());
       }
   Serial.println(); 
  }
} 

Chuck.

@stickbreaker I'm sorry for the short reply earlier, i was on a rush.
Nope, no wires touching anything... it's all on a pcb :D
My circuit is basically the RTC with a coin-cell battery and 4.7K pull-ups on SDA and SCL (https://ibb.co/dDHwrJ), connected to the ESP32 pins 21 and 22 respectively and they're very close on the pcb.
No logic-level converters and no other voltages.

I'm using platformio and thus in order to use your i2c fix i replaced :
cores/esp32/esp32-hal-i2c.c
cores/esp32/esp32-hal-i2c.h
cores/esp32/esp32-hal-log.h
libraries/Wire/Wire.cpp
libraries/Wire/Wire.h

Thing is, I'm able to read the RTC and set it's alarms for a couple of times but sometimes when ESP boots it gives that message "[E][esp32-hal-i2c.c:1113] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init).", previously (before replacing those i2c related files) I would get that "i2cWrite(): Busy Timeout! Addr: 68" message.

  • Running the i2c_scan (https://playground.arduino.cc/Main/I2cScanner) for like a couple of minutes, I get:
Scanning...
I2C device found at address 0x68  !
done

EDIT:

  • Running the test code you provided , plus adding Wire.begin(), I get:
    0x58 0x21 0x22 0x02 0x15 0x05 0x18 0x55 0x53 0x97 0x95 0x00

no errors for now, but will have to run it for a couple of times because the error doesn't show always.

Ok, after approx. an hour of my sketch running I got the problem again:
[E][esp32-hal-i2c.c:1113] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init
00/00/2000 00:00:00
and the clock cant be read.

I compiled with build_flags = -DCORE_DEBUG_LEVEL=1 (ERROR)
but no other error besides that above one is popping up
changed to DEBUG_LEVEL=5 (DEBUG)
and also got :
_[W][esp32-hal-i2c.c:1097] i2cCheckLineState(): invalid state sda=0, scl=1_
[E][esp32-hal-i2c.c:1113] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init
RTCC not present at address 0x68.

Went back to your sketch and get same thing (with DEBUG_LEVEL=5 (DEBUG)):
_[W][esp32-hal-i2c.c:1097] i2cCheckLineState(): invalid state sda=0, scl=1_
[E][esp32-hal-i2c.c:1113] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init
RTCC not present at address 0x68.

Don't think that's a hardware problem.
On my sketch I'm basically just reading the clock and a temperatur sensor and then cutting the power to the ESP and RTC (has a coin-cell batt) via a mosfet, and then the RTC turns mosfet ON with its INT pin which in turn makes the ESP do the same thing over and over again.
But then again, even going back to your simple test code makes it behave incorrectly!

@maribeiro
This is the code from the stickbreaker-i2c branch.

static bool i2cCheckLineState(int8_t sda, int8_t scl){
    if(sda < 0 || scl < 0){
        return true;//return true since there is nothing to do
    }
    // if the bus is not 'clear' try the recommended recovery sequence, START, 9 Clocks, STOP
    digitalWrite(sda, HIGH);
    digitalWrite(scl, HIGH);
    pinMode(sda, PULLUP|OPEN_DRAIN|OUTPUT|INPUT);
    pinMode(scl, PULLUP|OPEN_DRAIN|OUTPUT|INPUT);

    if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state
        log_w("invalid state sda=%d, scl=%d\n", digitalRead(sda), digitalRead(scl));
        digitalWrite(sda, HIGH);
        digitalWrite(scl, HIGH);
        delayMicroseconds(5);
        digitalWrite(sda, LOW);
        for(uint8_t a=0; a<9; a++) {
            delayMicroseconds(5);
            digitalWrite(scl, LOW);
            delayMicroseconds(5);
            digitalWrite(scl, HIGH);
        }
        delayMicroseconds(5);
        digitalWrite(sda, HIGH);
    }

    if(!digitalRead(sda) || !digitalRead(scl)) { // bus in busy state
        log_e("Bus Invalid State, TwoWire() Can't init");
        return false; // bus is busy
    }
    return true;
}

That error is telling you that the i2c bus, either SCL or SDA is held low. the ESP32 tried to manually stimulated an i2c recovery operation, but some device is holding the bus low. Since the ESP32 is running, it is not at fault, that only leaves the DS3231.

From your circuit description, I suspect it is a power issue, can you post a schematic / link that I can look at. If you are truly using a coin cell battery, you only have milli amps of power available. Try adding a 100uf cap in parallel with the coin cell. That will increase the instantaneous current available on power up.

Specs on CR2032 Coin cell Energizer CR2032

energizer cr2032 pulse discharge

As you can see they only rate the battery for 6.8ma max pulse.

Chuck.

@stickbreaker first, let me thank you for your time and help.
RTC isn't powered just by the coin-cell, the coin-cell is just for keeping the clock (as a backup power source).
The circuit is this: https://drive.google.com/open?id=1tyCYdXj9xVyZ_jKyRlxneEfv09QpoGfp
Main idea is having the ESP logging some temperature/GPS and programming the RTC to wake the whole circuit every 5 minutes. So, when RTC alarm fires , it makes the INT pin go LOW and therefore turning mosfet Q5 on, which in turn makes 3.3V available to the RTC itself (along with its pull-ups) and also powers the ESP.

Simple test sketch i'm using:
https://pastebin.com/bT88FbA5
Library: https://github.com/Makuna/Rtc/
After a while, as I said, it goes nuts... and cant read RTC anymore.

PS: I also have two temperature sensors (DS18B20) using by OneWire.. could this somehow cause this issue ?
As relevant info, I had this whole circuit/code working for 6 days uninterrupted. It started giving my those "i2cWrite(): Busy Timeout! Addr: 68" just lately but very sporadically (and I didn't change anything on the pcb). But at the moment, it doesn't hold for even an hour.

@maribeiro on pg 11 of Maxim's DS3231 data sheet, it states the i2c interface is live if Vcc ~OR~ VBat is valid. And the procedure to reset the i2c interface is not standard.

In your ~setup()~ before ~Wire.begin~

pinmode(scl,output);
PinMode(sda,input);
While(!digitalRead(sda)){
DigitalWrite(scl,low);
DelayMicros(5);
DigitalWrite(scl,high);
DelayMicros(5);
}

:Note, capitalization is screwed up, my phone is assuming i am writing english!

Chuck.

Thanks, will try that and report.
Unfortunately the problem doesn't always show after an hour or two.
I have the circuit running today for about 3hours and it's still working :|
But yeah, I'm guessing you're on the right track regarding the 'i2c interface reset' because as soon as I set the flags to clear the alarm, it shuts the whole circuit down and there still might be some transmissions occurring which may lead to an incoherent state.

@maribeiro Can you add a capacitor to the base of Q3 to delay the turn off, If you had a few ms of power the I2C communication could complete and you could just spin waiting for the power to fail.

Even a 100nf cap should give you a few milliseconds after the rtcc clears it's alarm output.

Chuck.

The I2C core was changed to @stickbreaker code officially after https://github.com/espressif/arduino-esp32/commit/13dcfe5c13bc882f8923d137ed604aa65b6db057 (thanks @stickbreaker), Let's close issues with old code and if have problems with the new code, open new issues =)

Great, thank you for the work here. Looking forward to testing.

how can i read or write in i2c? i am new in esp32 plz help me

@qazi24 Use the same commands as you use for the Arduino Uno.

//setup
Wire.begin();

//write
Wire.beginTransmission(i2cAddress);
Wire.write(byteValue);
Wire.endTransmission();

//read
Wire.requestFrom(i2cAddress,count);
while(Wire.available()){
  uint8_t b=Wire.read();
 }

You must have pullup resistors on both SDA and SCL, the builtin pullups of the chip are too weak to function correctly.

Chuck.

void setup() {
pinMode(SDA,INPUT_PULLUP);
pinMode(SCL,INPUT_PULLUP);

@ytemelli
The built in pullups on the esp32 are too weak to support reliable communications.

Chuck.

@stickbreaker,

I know this issue is closed but I'm experiencing the same issues as @maribeiro.

I have application using the ESP32 connected to an MCP23008. I am reading the inputs on the MCP23008 in the main loop really fast. If I power cycle just the ESP32 module it is very easy to get the MCP23008 stuck in I2C read state where it has the SDA line held low. I can verify this with a meter on the SDA line. I am not able to complete Wire.begin until the MCP23008 is power cycled. It seems there is no way to get it out of it's stuck I2C Slave Read state. I see you are pulsing the SCL line high then low 9 times, I tried increasing that cycle count but to no avail. I don't think this is an issue with your library but rather an issue with the i2c protocol in general or possibly just the way the MCP23008 behaves. Any advice would be greatly appreciated.

@telliottosceola what version are you using?

I would recommend updating to the latest dev level. I2c is just 4 files #1962 describes them.

I use MCP23008 as keypad drivers (4x4 matrix) without any problems.

Wire.begin() will cycle the bus and return true or false if it successfully init's the bus.

Set your debug level to VERBOSE it will report how many cycle it took to clear a stuck bus.

Chuck.

Works flawlessly now. I can't thank you enough. I have been banging my head on my desk for a couple of days now trying to fix the issue. That said I just quickly looked over i2cCheckLineState and I don't see any changes. What have you changed since the files you referenced in arduino-esp32-stickbreaker-v0.2.0.zip above that would have fixed this issue?

P.S. I'm a developer at ncd.io. I'd like to offer you some free hardware for your kind efforts here. We make an enormous line of I2C peripherals for almost any application which sounds like you might be interested in ;). If you are interested in some free hardware shoot me an email travis at ncd.io and I'll get you fixed up.

Thanks Chuck,
Travis

People,

There is a fix on Release 1.0.1 January 2019 (https://github.com/espressif/arduino-esp32/releases) with regard to:

9a7946e I2C fix READ of zero bytes hardware hang (#2301)

That was the issue for me. I2C working flawlessly now.

Regards,

Luciano

@stickbreaker
sir im having difficulty with the i2c "xgzp 6867" pressure sensor . im getting error uploading my code in arduino ide with wemos lolin 32 .. any suggestion or any working code sir would be a great help to me .. thanks in advance

@Bryanbaring Open up a new issue, don't hijack this closed thread.

If you can't upload code to the esp32, I can't help you with i2c issues.

Chuck.

@ytemelli
The built in pullups on the esp32 are too weak to support reliable communications.

Chuck.

Is this always requrired when using esp32 for i2c or something specific to a usecase?

@thehellmaker The ESP32's pullups are very weak, 50k to 100k ohm. Unless you want to run the i2c interface at 10khz you will need lower value resistors as pullups. With a 3.3v bus( the operating voltage of the ESP32) you should use a 3.3k ohm, at 100khz and a 2.4k ohm at 400khz.

Chuck.

@stickbreaker thank you so much.. This solved my intermittent failures with i2c on esp32. Much appreciated

Hello everyone I have did your program about the test of i2c and with my esp32 it's a mini wemos ttgo esp32 and the program give always the same answer same when I reset my esp32 . Do you have a solution because I search during one month and I not find solutions

Her answer of program is :
"Discovering eeprom sizes 0x50..0x57
0x50: Not Present.
0x51: Not Present.
0x52: Not Present.
0x53: Not Present.
0x54: Not Present.
0x55: Not Present.
0x56: Not Present.
0x57: Not Present"

Please do not hijack issues. Open a new issue and follow the issue template

I'm sorry, I'm a new in the forum so i don't know how it works

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DrewHoyt picture DrewHoyt  ·  4Comments

Curclamas picture Curclamas  ·  4Comments

maxpromer picture maxpromer  ·  3Comments

mistergreen picture mistergreen  ·  4Comments

merlinschumacher picture merlinschumacher  ·  4Comments