-
Notifications
You must be signed in to change notification settings - Fork 7.6k
I2C stability using Feather ESP32 and MPU6050 #3701
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
Comments
Follow the instructions in the Wire docs. Post your debug results, and @stickbreaker will likely be able to help you. |
This is what it showed me after I uncommented the #define ENABLE_I2C_DEBUG_BUFFER. |
@ABKingbird in the The Interesting parts from your first log output:
From the Debug Documentation:
What I expect happened is that the MPU6050 Stretched SCL longer than the ESP32 will accept while it was generating a sample during a read cycle. The ESP32 aborted the I2C cycle, but the MPU6050 was still in the read, the ESP32 started a new cycle and the MPU6050 output data on SDA unexpectedly. I would go back and modify your MPU6050 libraries to report the Success status on EVERY I2C transaction instead of assuming the transaction succeeded. uint8_t err = Wire().endTransmission();
if( err != 0){
Serial.printf("Write failure err=%d(%s)\n",err,Wire.getErrorText(err));
}
// and
uint8_t count = Wire.requestFrom(id,reqCnt);
if(count != reqCnt){
Serial.printf("Read failure, expected %d, received %d, err=%d(%s)\n",reqcnt, count, Wire.lastError(), Wire.getErrorText(Wire.lastError());
} That will give you a place to start looking for the Problem. You are running up against a limitation of the ESP32, SCL stretching is limited to 13.1ms in the current version of the hardware. The I2C specification does not include this limitation in it's specification. The last log message "Bus Buzy, ReInit" is telling you that SDA and/or SCL were not HIGH when a A bus busy state can be detected by using:
To manually recover the bus, you can use Chuck. |
Chuck, you should tag this issue as FOR REFERENCE. Good info. |
First of all thank you so much for your lengthy and helpful answer. Sorry for me taking so long to answer back but I had dinner and since then I have been trying to fully grasp your answer. The MPU library does not use "raw" Wire.h commands, but includes a library called "I2Cdev.h", which in turn contains these functions: public:
I2Cdev();
static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data);
static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data);
static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data);
static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data);
static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data);
static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data);
static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data);
static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data);
static uint16_t readTimeout;
}; By looking around in that library, I found out that it has a similar debug serial print like the esp32-hal-i2c.c does. I uncommented it and got the whole system running again.
I will keep it running till it crashes and then post again. |
Welp. It seems that it didn't crash at all with that way. Don't know if I should be happy with that. Anyway, I closed it and altered the libraries, as you told me to. After the upload, the system crashed as expected:
-Second(and final) crash:
The last two lines just kept going afterwards, meaning it got stuck. |
It looks like the MPU6050 is hanging. after the first error, it no longer answer i2c requests and takes a power cycle to recover. If you change the Chuck. |
The 2(ACK) is where the MPU6050 isn't answering(locked up) the ESP32 is functioning correctly. It detected a bus problem (MPU6050 lockup), recycled the bus, clearing the bus, But the MPU6050 is hung. Chuck. |
So that means it's probably the MPU's hardware or library problem? #elif (ARDUINO > 100)
// Arduino v1.0.1+, Wire library
// Adds official support for repeated start condition, yay!
// I2C/TWI subsystem uses internal buffer that breaks with large data requests
// so if user requests more than BUFFER_LENGTH bytes, we have to do it in
// smaller chunks instead of all at once
for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) {
Wire.beginTransmission(devAddr);
Wire.write(regAddr);
uint8_t err5 = Wire.endTransmission();
if( err5 != 0){
Serial.printf("Write failure err5=%d(%s)\n",err5,Wire.getErrorText(err5));
Serial.printf("Register Address=%d\n", regAddr); //<---- I added this
}
Wire.beginTransmission(devAddr);
uint8_t count3 = Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
if(count3 != (uint8_t)min(length - k, BUFFER_LENGTH)){
Serial.printf("Read failure, expected %d, received %d, err3=%d(%s)\n", (uint8_t)min(length - k, BUFFER_LENGTH), count3, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
}
for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
data[count] = Wire.read();
#ifdef I2CDEV_SERIAL_DEBUG
Serial.print(data[count], HEX);
if (count + 1 < length) Serial.print(" ");
#endif
}
}
#endif After running the code, there was no "mini-crash" but some
and some
here and there, which both belong in the "if" sketch above. Finally, the system crashed, showing me this:
For reference, Register 58 is the Interrupt Register, which shows the interrupt status of each interrupt generation source and Register 114 (along with 115) are the FIFO Count Registers which keep track of the number of samples currently in the FIFO buffer. How should I continue? Is it worth spending my time on it (I do my thesis and can't afford much time, plus my brain hurts). |
Is that code a cut and paste from your source? Also with ESP32, the Chuck. |
Yes this is a straight copy from the library file. The only things I changed were the Wire.endTransmission and Wire.requestFrom for the debug. The BUFFER_LENGTH is indeed 128, I just found it in the Wire.h file I don't see the mark that you are talking about, but I think that you mean the second Wire.beginTransmission(), which happens right after the "if( err5 != 0)". |
Serial.printf("Register Address=%d\n", regAddr); //<---- I added this
}
>>>>>>>>>> Wire.beginTransmission(devAddr);
uint8_t count3 = Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
if(count3 != (uint8_t)min(length - k, BUFFER_LENGTH)){
Serial.printf("Read failure, expected %d, received %d, err3=%d(%s)\n", (uint8_t)min(length - k, BUFFER_LENGTH), count3, Wire.lastError(), Wire.getErrorText(Wire.lastError()));
} |
can you point me to copies of your included libraries:
I'll take a look at them and see if I can identify coding that does not work with the ESP32. I use Chuck. |
Yep, that's the one I commented. Right before "uint8_t count3 = ..." Serial.printf("Register Address=%d\n", regAddr);
}
//Wire.beginTransmission(devAddr);
uint8_t count3 = Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); Exactly same errors happen. Link to libraries: |
It is also worth mentioning that I had to to do these changes: |
Hi @stickbreaker , Did you get a chance to take a look at the libraries (https://github.com/jrowberg/i2cdevlib)? I have the same issue of the MPU locking up during I2C communicatons. Only removing and restoring power to the MPU6050 seems to resolve this lockup. Hope you can help as the DMP function in the MPU6050 works really really well. It gives very stable outputs (if it does not crash ;-)) Let me know if you need any help testing/debugging. thx, Jeroen PS, Some comments which I hope makes it easier for you to check. There are two pieces of code that are (timing-) critical as using the built in DMP uses a fifo buffer that can also overflow and/or requires a lot of reads/writes. They both use the underlying I2C methods in https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/I2Cdev/I2Cdev.cpp In https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/MPU6050.cpp
and the method that handles the calibration:
|
Same issue here! I am using latest ESP32 WifiManager Development library and the MPU6050 library. When the INT (interrupt) pin is connected to the Arduino it crashes on startup forever.
Any help would be great!! |
Wait is this the reason? Do I need to make it so WifiManager does not run at the same time that the MPU6050 is running?? How would I do that? |
Fixed it, ignore my silly commit commenting above. All I did was run the WifiManager setup code BEFORE the MPU6050 starts loading, this prevents the 12C Bus thing from crashing my ESP32. Hope this can help someone else too. |
Hardware:
Board: Adafruit ESP32 Feather Huzzah
Core Installation version: 1.04
IDE name: Arduino IDE
Flash Frequency: 80Mhz
PSRAM enabled: ?no? ?yes?
Upload Speed: 115200
Computer OS: Windows 10
Debug Level: Verbose
Description:
Hello, I have an MPU6050 Accelerometer connected to my ESP32 Feather via I2C and I am having some problems with the stability of the connection(see below). I can get some values for like seconds/minutes before it crashes due to I2C connection probably.
The sketch I am using makes use of the DMP, FIFO and Interrupt signals of the MPU6050. If I instead don't use the above(DMP, FIFO, and Int) and just get the raw values of the MPU, it works almost perfectly!
Sketch:
Debug Messages:
While working, it shows me this error, but still continues:
And finally, it shows me this and stops working:
After crashing, it just stays like that forever, and it shows me this after reset button has been pressed:
meaning it can't get DMP to work again, no matter how many times I reset it. Code 1 is, as stated above in the sketch, something about "initial memory load failed" . To get over that, I simply plug the Vcc pin out of the MPU and put it back on.
Thank you in advance.
The text was updated successfully, but these errors were encountered: