I2C Wrong (but consistent) values

Hi guys,

I've been at this for the better part of this week and ran out of resources to find/read online.

My setup is an ESP8266 (nodemcu V3) as master and an Arduino Nano as Slave and what I am trying to accomplish is a standard Master reader Slave sender scenario to transfer 2 byte or uint8_t values.

I know the Arduino Nano is 5V and the esp is 3.3v and I am using a generic Chinese I2C bi-directional logic level converter (3.3V to 5V 2/4/8 Channel Logic Level Converter Module Bi-Directional Arduino | eBay - the 2CH GY type).

Also the same master successfully communicates with 2 other 3.3v slaves - a bh1750 sensor and a VEML6070 sensor on the same Wire bus.

The issue I am dealing with is that I the 2 data bytes that are (supposedly) sent by teh slave are not the same as the 2 data bytes thar are received by the master. The values appear random but consistent. For example if I send (byte)0 and(byte)0 from the slave the master receives (byte)12 and (byte) 127.

The code I am using for the master is

byte buf[2] = {0, 0};
byte bytesRead = _wire->requestFrom((uint8_t)_addr, (byte)2);
if (bytesRead != 2)
{
//log error
}
else
{
_wire->readBytes(buf, 2);
}

and the code for the slave is

void handleI2CRequest()
{
byte buffer[2];

buffer[0] = (byte) 50;
buffer[1] = (byte) 50;
Wire.write(buffer,2);
}

The above code is slightly simplified.

I also tried adding 2 4k7 resistors as pullups on the arduino and activating the Nano's internal pull-ups and combination of the two but no luck. And this is on top of the pull-up resistors (~20k?) on the logic level shifter

I do not own an oscilloscope and this might be the last think I can check with - to see if the internal pull-ups are correct and the signal is correct ad until I can get my hands on one - do you have any ideas? Maybe someone banged his/hers head on something similar before?

Any ideas are welcomed - thank you!

The above code is slightly simplified.

Post actual and complete code. If you don't want to post your complete project's code, simplify it to a sketch that shows the same behavior and post that.

Are the grounds connected?

Fair enough, you have the full code both for the master and the slave attached to this post. There is a lot of out of scope code in there so that is why I wanted to spare you going throug 100 lines of code to get to 3 important ones.

pylon:
Are the grounds connected?

Yes, the grounds are connected through the logic level shifter. I used a multi-meter to measure the resistance between the 5v side and 3v side on the converter and there is almost no resistance so it is a direct link.

As a side note I also swapped the logic level converter with another identical one and I still get the same result.

My next step would be to test the slave with another 5V arduino master and see if anything changes - I will do that over the weekend and update the thread.

Thank you.

master-bah_lightning.cpp (1.97 KB)

master-bah_lightning.h (1.75 KB)

slave-main.cpp (3.61 KB)

handleI2CRequest() is called in interrupt context, so:

  • never call any method of the Serial object inside of it
  • declare all variables "volatile" used in it and somewhere else
  • make it as fast as possible, I'm not sure that ESP processors support clock stretching (might be the reason for the symptoms you see)

The master code is still not complete. At what frequency is the I2C bus driven?

Thanks for the suggestions. The slave runs on an Arduino Nano. Only the master runs on ESP8266. I will post a test sketch with the master initialization as soon as I can.
The clock speed is the default one I am not changing it - I just pass the global Wire as a parameter to the master class begin() method - though this is a valid lead as I am using the same Wire object for the other sensors too and the other libraries might change some parameters.
One is the Adafruit BME280 library.

I just saw in the code for the ESP8266 that you can set a clock stretching limit in their version of the Wire library. So it seems that the processor supports clock stretching but it's not clear what default are active without changing anything.

Do you have a logic analyzer? That's the easiest way to find out which part doesn't behave correctly.

pylon:
I just saw in the code for the ESP8266 that you can set a clock stretching limit in their version of the Wire library. So it seems that the processor supports clock stretching but it's not clear what default are active without changing anything.

Do you have a logic analyzer? That's the easiest way to find out which part doesn't behave correctly.

Thanks a lot - setClockStretchLimit to something like 1500 did the trick but actually that got me thinking and refactored a lot of the client code

My handleI2CRequest function looks now like this

void handleI2CRequest()
{
sendBuffer[0] = spm;
sendBuffer[1] = sIntensityPrc;
Wire.write(sendBuffer, 2);
}

as you said .. it has to be as fast as possible. In this configuration everything works perfectly.
Leaving the old code for the client but setting clock stretch also works but with downsides I d not yet understand.

Bottom line the ESP8266 is eager when waiting for teh response although it is not clear what the exact timeout is. The arduino (especially with badly written code) as a slave is slow to respond and that is why issues occur.

Thank you for all the help.