Skip to content
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

I2C not working on ESP32 #741

Closed
muktillc opened this issue Oct 17, 2017 · 58 comments
Closed

I2C not working on ESP32 #741

muktillc opened this issue Oct 17, 2017 · 58 comments

Comments

@muktillc
Copy link

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);
}

@stickbreaker
Copy link
Contributor

@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.

@EBZ-Krisemendt
Copy link

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

@muktillc
Copy link
Author

muktillc commented Oct 18, 2017 via email

@EBZ-Krisemendt
Copy link

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

@muktillc
Copy link
Author

muktillc commented Oct 27, 2017 via email

@me-no-dev
Copy link
Member

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

@muktillc
Copy link
Author

muktillc commented Nov 5, 2017

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?

@stickbreaker
Copy link
Contributor

@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.

@stickbreaker
Copy link
Contributor

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

Chuck.

@zachfi
Copy link

zachfi commented Mar 1, 2018

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.

@njbuch
Copy link

njbuch commented Mar 18, 2018

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 );

@stickbreaker
Copy link
Contributor

@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.

@njbuch
Copy link

njbuch commented Mar 19, 2018

@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 :)

@stickbreaker
Copy link
Contributor

@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.

@njbuch
Copy link

njbuch commented Mar 19, 2018

Superb, I just did what this suggest, with your file and the input from:stickbreaker#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.

@stickbreaker
Copy link
Contributor

@njbuch post your I2c reading code:

chuck.

@njbuch
Copy link

njbuch commented Mar 19, 2018

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 <Arduino.h>
#include <Wire.h>                                                       // required by BME280 library
#include <BME280_t.h>                                                   // 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
}

@stickbreaker
Copy link
Contributor

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.

@njbuch
Copy link

njbuch commented Mar 19, 2018

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

@stickbreaker
Copy link
Contributor

@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.

@joncl
Copy link

joncl commented Apr 13, 2018

@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!

\libraries\Wire\scr\Wire.h
\libraries\Wire\scr\Wire.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

@zachfi
Copy link

zachfi commented Apr 16, 2018

How do I update to use the fixed version?

@stickbreaker
Copy link
Contributor

@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

@zachfi
Copy link

zachfi commented Apr 20, 2018

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

@beegee-tokyo
Copy link
Contributor

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

@zachfi
Copy link

zachfi commented Apr 20, 2018

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

@stickbreaker
Copy link
Contributor

stickbreaker commented Apr 20, 2018

@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.

@maribeiro
Copy link

maribeiro commented May 15, 2018

@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.

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.

@maribeiro
Copy link

maribeiro commented May 15, 2018

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!

@stickbreaker
Copy link
Contributor

@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.

@maribeiro
Copy link

maribeiro commented May 16, 2018

@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.

@stickbreaker
Copy link
Contributor

@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.

@maribeiro
Copy link

maribeiro commented May 16, 2018

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.

@stickbreaker
Copy link
Contributor

@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.

@copercini
Copy link
Contributor

The I2C core was changed to @stickbreaker code officially after 13dcfe5 (thanks @stickbreaker), Let's close issues with old code and if have problems with the new code, open new issues =)

@zachfi
Copy link

zachfi commented Jul 2, 2018

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

@qazi24
Copy link

qazi24 commented Jul 10, 2018

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

@stickbreaker
Copy link
Contributor

@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.

@ytemelli
Copy link

ytemelli commented Aug 1, 2018

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

@stickbreaker
Copy link
Contributor

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

Chuck.

@telliottosceola
Copy link

@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.

@stickbreaker
Copy link
Contributor

@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.

@telliottosceola
Copy link

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

@lspaula
Copy link

lspaula commented Jan 15, 2019

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

@Bryanbaring
Copy link

Bryanbaring commented Feb 6, 2019

@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

@stickbreaker
Copy link
Contributor

@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.

@thehellmaker
Copy link

@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?

@stickbreaker
Copy link
Contributor

@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.

@thehellmaker
Copy link

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

@Thomas127
Copy link

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

@Thomas127
Copy link

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"

@lbernstone
Copy link
Contributor

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

@Thomas127
Copy link

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

@radimsejk
Copy link

Hello, sorry for opening this again, but I think I do have this problem occuring. I have Sparkfun's ESp32 Thing plus with multiple QWIIC boards connected to it (accelerometer, two buttons, mp3 trigger, port expander, WS2812 leds and current meter). It works for random amount of time (sometimes few minutes sometimes few hours) and then this happens:

[W][esp32-hal-i2c.c:1419] i2cCheckLineState(): invalid state sda(23)=1, scl(22)=0
[D][esp32-hal-i2c.c:1427] i2cCheckLineState(): Recovered after 1 Cycles
[E][esp32-hal-i2c.c:1434] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init sda=1, scl=0

Sometimes it is sda(23)=1, scl(22)=0 and sometimes sda(23)=0, scl(22)=0

All those boards have pullups and I have cut them on all except one as recommended so now it should have 2.2k on both lines.
I have connected two 100uF capacitors on the power line (one near the ESP32 and one on the other end of I2C line.

Is there anything I could do more to make it work? Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests