[Solved] ESP8266 to Nano I2C Problems.

I'm trying to get I2C working between an Arduino Nano and an ESP8266.
I'm using the ESP8266 Community libs v1.6.4-673-g8cd3697 from GitHub - esp8266/Arduino: ESP8266 core for Arduino

Master[ESP8266]:

#include <Wire.h>
#define I2CAddressESPWifi 6
int x=32;

void setup()
{
  Serial.begin(115200);
  Wire.begin(0,2);//Change to Wire.begin() for non ESP.
}

void loop()
{
  Wire.beginTransmission(I2CAddressESPWifi);
  Wire.write(x);
  Wire.endTransmission();
  x++;
  delay(1);//Required. Not sure why!

  Wire.requestFrom(I2CAddressESPWifi,10);
  Serial.print("Request Return:[");
  while (Wire.available())
  {
    delay(1);
    char c = Wire.read();
    Serial.print(c);
  }
  Serial.println("]");
  delay(500);
}

Slave[Nano]:

#include <Wire.h>
#define I2CAddressESPWifi 6

void setup()
{
  Serial.begin(115200);
  Wire.begin(I2CAddressESPWifi);
  Wire.onReceive(espWifiReceiveEvent);
  Wire.onRequest(espWifiRequestEvent);
}

void loop()
{
  delay(1);
}

void espWifiReceiveEvent(int count)
{
  Serial.print("Received[");
  while (Wire.available())
  {
    char c = Wire.read();
    Serial.print(c);
  }
  Serial.println("]");
}

void espWifiRequestEvent()
{
  String ts = getTime();
  Serial.print("Sending:[");
  Serial.print(ts.c_str());
  Serial.println("]");
  Wire.write(ts.c_str());
}

String getTime(){
  int sec = millis() / 1000;
  int min = sec / 60;
  int hr = min / 60;
  String ts = "U:";
  if (hr<10) ts+="0";
  ts += hr;
  ts +=":";
  if ((min%60)<10) ts+="0";
  ts += min % 60;
  ts +=":";
  if ((sec%60)<10) ts+="0";
  ts += sec % 60;
  return(ts);
}

If I use the same code above with an Uno as Master, it works fine!

Wiring wise, I just have straight connections from the ESP GPIOs to the A4/A5 on the Nano. I've tried using 4K7 pull ups, but it doesn't make a difference.

What's strange is if you use the default example code for I2C master/slave it works ok, but as soon as you try and speed things up with faster requests like this, it just doesn't work on the ESP.

Any help on debugging this would be greatly appreciated!

Hi Enigma644

What's strange is if you use the default example code for I2C master/slave it works ok

Just to confirm, using this other code with the same wiring between the devices, you got I2C to work ok with ESP8266 as master and Nano as slave? Can you post that code?

Regards

Ray

Yes. It's just the example code that comes with the Arduino IDE. ESP Master, Nano Slave.

File > Examples > Wire : master_reader,master_writer,slave_receiver,slave_sender.

I think it works because there are long delay commands in the example code.
More importantly, the above code works with a Nano Slave, Uno Master, but NOT a Nano Slave, ESP Master!

In the ESP master, you could try setting the wire speed, in case it defaults to higher and this, with the absence of delays, is causing the problem.

Try adding after Wire.begin()

Wire.setClock(100000);

Wire.setclock didn't work :frowning:
Tried values from 10 to 10,000,000. Didn't seem to make any difference. Slave Nano still receives ok, but the ESP just gets the same junk data returned.

Slave Nano still receives ok, but the ESP just gets the same junk data returned.

Ah, this wasn't clear from your original post. So, on the ESP, you see the "Received[" OK but the data that follows is junk? Nothing received?

I would try testing by sending just a byte or two from the Nano to the ESP.

You could also look at the issues page on GitHub for the core in case a similar problem has been reported.

I think I've figured it out.. It looks like if I do any calculations in the Wire.onRequest() handler that it doesn't have time to create the response and I just get garbage. So now in my master I'm using the first char transmission to trigger building the data response into a global, then waiting before doing Wire.requestFrom and now I'm getting a response back!

Even doing a Serial.print() in the slave Wire.onRequest() interrupt handler seems to be enough to stop it from working!
I'm guessing there must be a bug in the ESP wire lib that's not letting it wait long enough for a response?
Surely I should be able to do some calculations in Wire.onRequest??
There's nothing in the wire interrupt handler docs that says the response needs to be quick.

Working Code:
[Slave_Nano]

#include <Wire.h>
#define I2CAddressESPWifi 6

char response[11] ="0123456789";

void setup()
{
  Serial.begin(115200);
  Wire.begin(I2CAddressESPWifi);
  Wire.onReceive(espWifiReceiveEvent);
  Wire.onRequest(espWifiRequestEvent);
}

void loop()
{
  delay(1);
}

void espWifiReceiveEvent(int count)
{
  Serial.print("Received[");
  while (Wire.available())
  {
    char c = Wire.read();
    Serial.print(c);
  }
  Serial.println("]");
  //calc response.
  String ts = getTime();
  strncpy(response,ts.c_str(),sizeof(response)-1);
}

void espWifiRequestEvent()
{
  /*Serial.print("Sending:[");
  Serial.print(response);
  Serial.println("]");*/
  Wire.write(response);
}

String getTime(){
  int sec = millis() / 1000;
  int min = sec / 60;
  int hr = min / 60;
  String ts = "U:";
  if (hr<10) ts+="0";
  ts += hr;
  ts +=":";
  if ((min%60)<10) ts+="0";
  ts += min % 60;
  ts +=":";
  if ((sec%60)<10) ts+="0";
  ts += sec % 60;
  return(ts);
}

[Master_ESP]

#include <Wire.h>
#define I2CAddressESPWifi 6
int x=32;

void setup()
{
  Serial.begin(115200);
  Wire.begin(0,2);//Change to Wire.begin() for non ESP.
}

void loop()
{
  Wire.beginTransmission(I2CAddressESPWifi);
  Wire.write(x);
  Wire.endTransmission();
  x++;
  delay(1);//Wait for Slave to calculate response.

  Wire.requestFrom(I2CAddressESPWifi,10);
  Serial.print("Request Return:[");
  while (Wire.available())
  {
    delay(1);
    char c = Wire.read();
    Serial.print(c);
  }
  Serial.println("]");
  delay(500);
}

I'm curious, why would you want to use I2C to connect the ESP8266 to an Arduino over Serial?

I'm only using Serial for debugging. Once live the ESP8266 will be running a web server and reading data from the Arduino; in this case providing a remote display for my 3D printer.

Enigma644:
I'm only using Serial for debugging. Once live the ESP8266 will be running a web server and reading data from the Arduino; in this case providing a remote display for my 3D printer.

No, by "over" I meant instead of serial. I thought that the ESP8266 was meant to work using serial, not I2C. Are you referring to the actual module itself, with all GPIO pins exposed, and not the version that's mounted on a breadboard-friendly breakout board that's meant to work with serial?

You can program the ESP8266 just like an Arduino rather than using it as a dumb serial device. See my first post for links to the ESP community libs.

Actually this thread is very helpful. I have an ESP01 hooked to a pro mini using the I2c buss. The benefit here is that the arduino can power down the esp to save power. As the arduino, who monitors sensors and the like determines that a status transmission is necessary, it raises the power up pin on the ESP. The ESP then initializes and requests the status info from the arduino (being that the ESP can only be the master) for transmission.

I like the flexibility of creating my own protocols (other than using the AT command set) and leaving the serial for debugging. With two instances of the Arduino IDE open on the desktop, with my logic analyzer hooked to the I2c bus, I can easily modify, upload and debug the code in rapid fashion.

When I have a project that does not need battery life, I favor the ESP12e. This whole environment is a lot of fun.

This thread helped. The Blink of I2C!

void setup()
{
  Serial.begin(115200);
  Wire.begin();//for ESP8266-12E SDA=D4 and SLC=D5
}

For everybody else who have problems with ESP8266 as I2C master requesting values from Arduino slave.
Set the stretchlimit if ESp is impatient:

Wire.setClockStretchLimit(40000);    // in µs

mde110:
For everybody else who have problems with ESP8266 as I2C master requesting values from Arduino slave.
Set the stretchlimit if ESp is impatient:

Wire.setClockStretchLimit(1500);    // in µs

HI, i just wanted to post and say that so far, this appears to have solved my problem. THANKS!

Am I missing something - Arduino 1.69 - there does not seem to be that stretching command???

Pete.

IT is only available for esp core... Though it seems like it was just a temporary fix for me, as it is no longer working :frowning:

Arghh. oh I thought it was in Arduino code - the issue I'm having is an ESP talking I2c to an actual Arduino (well, an Atmega1284). Multiple byte returns failing and crashing the ESP.

Well, the esp can only be Master, and the Arduino has to be the slave... but while adding that line did improve my i2c performance, it didn't solve it. The arduino receives the request and responds, but for some reason the esp8266 doesn't always see it (sometimes it always does, though)..

I

I use on ESP Master:

Wire.setClockStretchLimit(40000);    // in µs

Test your code with Arduino Master and Arduino Slave. After that, with ESP.
Dont send more than 32 Bytes with your slave!