Bug on WIRE.H library from Arduino

Hi,

I was facing serious problems with MPU6050 usin JEFF'S ROWBERG library cause my arduino intermitently hangs. I thought it was JEFF'S ROWBERG library fault but it is not! Today I removed that library from my code and used only WIRE.H and the bug still happens.

Connect your MPU6050 to your arduino (VCC, GND, SCL and SDA) and run the simplest code below.

#include "Wire.h"
const int MPU=0x68;  
int ax;

void setup() {

    Serial.begin(115200);
    
    Wire.begin();
    Wire.beginTransmission(MPU);
    Wire.write(0x6B); 
    Wire.write(0); 
    Wire.endTransmission(true);

}

void loop() {
    
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    
    Wire.requestFrom(MPU,14,true);  

    ax = Wire.read()<<8|Wire.read();
    
    Serial.println(ax);

}

Open your computer serial and wait a few seconds, usually after around 10-30 seconds arduino will hang. I decided to use several println in the code above to track which line was hanging and I discovered it always hangs at this line:

Wire.requestFrom(MPU,14,true);

How can I report this bug and try to help to get it solved?

How can I report this bug and try to help to get it solved?

Perhaps you should start by explaining why you are requesting 14 bytes but only reading 2.

@PaulS thanks for your help. I need to ask for 14 bytes cause it's the default of all data the MPU6050 provides. Actually in my code I use all the 14 bytes asked, I just simplified it above to make the code smaller and easy for you to reproduce the bug. In my code I actually do this (see that there are 7 lines with 2 read() in every line, so I use all the 14 bytes):

	ax = Wire.read()<<8|Wire.read();    
	ay = Wire.read()<<8|Wire.read();
	az = Wire.read()<<8|Wire.read();
	temperatura = Wire.read()<<8|Wire.read();
	gx = Wire.read()<<8|Wire.read();
	gy = Wire.read()<<8|Wire.read();
	gz = Wire.read()<<8|Wire.read();
const int MPU=0x68;
    Wire.beginTransmission(MPU);

Wire.beginTransmission

Description

Begin a transmission to the I2C slave device with the given address. Subsequently, queue bytes for transmission with the write() function and transmit them by calling endTransmission().

Parameters

address: the 7-bit address of the device to transmit to

have you tried

const [b]byte[/b] MPU=0x68;

instead of int to have 8 bits instead of 16?

@J-M-L I never tried byte but I tried now and the same problem happens. You see, there is no error in that code cause I can retrieve all the data from my MPU6050 for about 10-30 seconds, after that arduino freezes and no output is sent to the serial. It's not a problem with my arduino, nor with my cables or mpu6050. I tried this on other arduino and other module and the same happens. Also asked my teacher and he tried my code in his setup and also got a freeze. He was the one who told me to report this as a bug but I have no idea how to do this.

    Wire.endTransmission(false);
   
    Wire.requestFrom(MPU,14,true);

Try releasing the bus before starting another transmission:

    Wire.endTransmission(true);
   
    Wire.requestFrom(MPU,14,true);

I tried it just now, didnt work too :frowning:

You fail to do any error checking. Is data available to be read? Have you checked the datasheet for the maximum sampling rate?

@Martin-X I fail to do any error checking cause arduino freezes at the line "Wire.requestFrom(MPU,14,true); ". How can I handle any error if I cannot have the return of that line? Arduino simply does not get over that line, it stays there forever.

If you run the code I gave you you will see it works for about 10-30 seconds, after that it freezes for no reason.

The sampling rate of MPU6050 does not look to be a problem cause I see guys in the internet (using Jeff Rowberg library) getting 200 Hz of data (5ms to every read) while my code above runs at most at 80 Hz.

I don't have that component, so cannot check the code personally. You have made an assumption that the code fails on that line, but your code does not clearly identify the statement that fails. Wire.endTransmission() returns a value, why don't you check that? Using Wire.available() will also confirm that there is data to be read.

I didnt make any assumption. I did a serial.print before each line of my code and every time arduino freezes is at the same serial.print (right before that line I told you).

Hey guys, I know you all wanna help but this is a clear bug. Anyone can check this bug, I already tried with arduino nano and uso and the bug happens. Tried also with an mpu6050 from another seller and the same problem happens.

I think there is nothing to discuss here, I just wanna know if you can kindly tell me how to report a bug at wire.h library. Every other library that I use with arduino has a bug tracker on github so I can post the bug there and try to get it solved. But I cant find the wire.h repository or bug tracker. Can you please help me with that? The code is fine, there is nothing wrong with it. Nor with my setup. There is clearly a bug here, so lets try to report it!

I'm running your original code on a Mega 2560 with no problems yet. I don't have a MPU6050, but does that make a difference? Does you code lock up after 30 seconds or so with no I2C device connected?

batata004:
Hey guys, I know you all wanna help but this is a clear bug.

That is less likely than the alternative.

SurferTim:
I'm running your original code on a Mega 2560 with no problems yet.

And there you have it. What is far more likely than the arduino libraries being buggy is that you have some hardware problem or some other error. Bad earthing? Need decoupling capacitors?

I mean, if it always hangs here:
Wire.requestFrom(MPU,14,true);

Then the obvious possibility is that your MPU isn't talking to you. Are you sure it's device 0x68 ?

You can post issues in the Arduino github repository but I think the issue needs to be further narrowed down before doing so.

The code is using a flag to disable sending the STOP on a write and then doing a read which I guess does a repeat start operation on the next readFrom()

Is this required?
Does it work if you use the normal endTransmission() which sends the stop?

The wire library has a warning about using this no stop option:

// WARNING: Nothing in the library keeps track of whether
// the bus tenure has been properly ended with a STOP. It
// is very possible to leave the bus in a hung state if
// no call to endTransmission(true) is made. Some I2C
// devices will behave oddly if they do not see a STOP.

Perhaps the slave doesn't support repeated starts?

Also note that Wire.read() can fail. It returns an int which can be -1 instead of the next 8 bit data byte.
I have been burned by this in the past.

In terms of bugs in the Wire code,
I have run into issues & bugs in the Arduino Wire library code of AVR and pic32 (chipkit).
The only way to track stuff like this down is going to be with logic analyzer pictures.
If there is a h/w or s/w issue,
this will be critical to not only show the problem, but also to show others how to replicate the problem and be able to verify that it is fixed.

Some of the issues that I've recently run into are related to misbehaving slaves.
i.e. a slave violates the timing or misbehaves on the bus and confuses the state machine on the master causing the master s/w to get stuck.

I've also seen issues where a master can get confused and think that there is another master on the bus (when there isn't) and essentially lock up waiting for that master to finish or even get thrown into slave mode.
This can happen if external pullups are missing, or on pic32 if you try to immediately do a beginTransmission() after an endTransmission() before waiting at least 25us.

--- bill

If you use a basic Arduino board with ATmega microcontroller, then it is probably not a bug in the Wire library. It might have to do with your hardware, either the voltage levels or the wires.
Can you make a photo that shows the wires between the Arduino and MPU-6050 ?
Which Arduino board do you use ?
Do you use a level shifter ?
Which MPU-6050 module ? Please give a link to it.
How is it powered ?

When you say that it is not the wires, nor the MPU-6050 module, then that raises our suspicion. I made this funny law: What's wrong with BME280 - #4 by Koepel - Sensors - Arduino Forum

The Wire library for the ATmega chips should work. For other processors, there might be a bug.

Could you add a delay at the end of the loop() ? For example 10ms.

The fact that you say the same thing happens with two different libraries should be a clue.

One thing to do is check the return value of Wire.endTransmission(). It should return 0 on success. I don't say it's the cause of your problem but it might give an indication of something being wrong.

2 will indicate that no ack was received when the address was send
3 will indicate that no ack was receivend when data was send
4 will indicate other errors (e.g. the master lost arbitration in a multi-master setup)

I did setup my RTC/EEPROM module and with your code it actually hung at the Wire.endTransmission() in setup() (even after power cycles). I don't know for sure how I solved it, but removing and reinserting wiring and I eventually got it going meaning that it did no longer hang anywhere (even with none-existing addresses).

Note: in my setup, 0x68 is the address of the DS3231 RTC

With a little testing, I think I found your bug. If either the SCK or SDA lines are held LOW by the slave, the I2C bus will crash the Arduino. Is that what you think may be happening? Do you have an o-scope to test with?

edit: If the SDA or SCK lines are resistive (I used a 1K resistor to ground) the arduino doesn't crash, but the I2C bus freezes.

I've just tried to simulate my earlier 'hang'. If I disconnect the 5V from my I2C module, the code hangs at endTransmission() while reading the eeprom.

eeprom routine for information below

byte readEeprom(byte devAddress, int memAddress, byte * ptr, int len)
{
  // clear receive buffer
  memset(ptr, 0, len);

  // setup writing to eeprom
  Serial.print("beginTransmission");
  Wire.beginTransmission(devAddress);
  Serial.println(" done");
  // setup to write to given memory address
  Serial.print("write");
  Wire.write(memAddress & 0xFF);
  Wire.write(memAddress >> 8);
  Serial.println(" done");
  // send the memory address to eeprom
  Serial.print("endTransmission");
  byte rc = Wire.endTransmission();
  Serial.println(" done");
  // check result
  if (rc != 0)
    return rc;

  Serial.print("requestFrom");
  Wire.requestFrom(EEP_ADDRESS, len);
  Serial.println(" done");

  int index = 0;
  while (Wire.available())
  {
    if (index < len)
      ptr[index++] = Wire.read();
  }

  return 0;
}

I managed to hang it once in requestFrom() by disconnecting at the right time.

@batata004
Do you have a power problem?

PS I don't have a scope.

//Edit:
I seem to have a big/little endian mixup :wink: I think I fixed it

Another user led me to the cause of this problem with another I2C problem. His problem was created by a situation similar to sterretje's. Powering down one of the I2C slaves caused the I2C bus to freeze.
http://forum.arduino.cc/index.php?topic=409677.0