espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.76k stars 7.44k forks source link

I2C stability using Feather ESP32 and MPU6050 #3701

Open ABKingbird opened 4 years ago

ABKingbird commented 4 years ago

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:


#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"

MPU6050 mpu;

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

#define INTERRUPT_PIN 12
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}

void setup(){
  Serial.begin(115200);
  Wire.begin();
  Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
                                        //^ doesn't make a difference, still crashes

  mpu.initialize();

  // verify connection
  Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

  // load and configure the DMP
  devStatus = mpu.dmpInitialize();
  pinMode(INTERRUPT_PIN, INPUT);

  // set Offsets
  mpu.setXAccelOffset(2220);
  mpu.setYAccelOffset(-1155);
  mpu.setZAccelOffset(380); 
  mpu.setXGyroOffset(13);
  mpu.setYGyroOffset(23);
  mpu.setZGyroOffset(14);

  // set Rate
  mpu.setRate(19);

  // make sure it worked (returns 0 if so)
  if (devStatus == 0) {

    // turn on the DMP, now that it's ready
    Serial.println(F("Enabling DMP..."));
    mpu.setDMPEnabled(true);

    // enable Arduino interrupt detection
//    Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
//    Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
//    Serial.println(F(")..."));
    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
    mpuIntStatus = mpu.getIntStatus();

    // set our DMP Ready flag so the main loop() function knows it's okay to use it
//    Serial.println(F("DMP ready! Waiting for first interrupt..."));
    dmpReady = true;

    // get expected DMP packet size for later comparison
    packetSize = mpu.dmpGetFIFOPacketSize();
  }
  else {
    // ERROR!
    // 1 = initial memory load failed
    // 2 = DMP configuration updates failed
    // (if it's going to break, usually the code will be 1)
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(devStatus);
    Serial.println(F(")"));

  }
}

void loop(){
  if (!dmpReady) {
    return;
  }

  while (!mpuInterrupt && fifoCount < packetSize) {
    if (!mpuInterrupt && fifoCount < packetSize) {
      fifoCount = mpu.getFIFOCount();
    }
  }

  mpuInterrupt = false;
  mpuIntStatus = mpu.getIntStatus();

  fifoCount = mpu.getFIFOCount();
  if(fifoCount < packetSize){
//    Serial.println("fifoCount < packetSize");
  }

  else if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
    // reset so we can continue cleanly
    mpu.resetFIFO();
//    Serial.println(F("FIFO overflow!"));
  } 

  else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)) {

    // read a packet from FIFO
    while(fifoCount >= packetSize){ 
      mpu.getFIFOBytes(fifoBuffer, packetSize);
      fifoCount -= packetSize;
      }

    mpu.dmpGetQuaternion(&q, fifoBuffer);
    mpu.dmpGetAccel(&aa, fifoBuffer);
    mpu.dmpGetGravity(&gravity, &q);
    mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
    mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
//    Serial.print("areal\t");
    Serial.print(aaReal.x);
    Serial.print("\t");
    Serial.print(aaReal.y);
    Serial.print("\t");
    Serial.print(aaReal.z);
    Serial.print("\n");
//    Serial.println(metriseis);
  }
}

Debug Messages:

While working, it shows me this error, but still continues:

18:02:40.032 -> 3   -2  -19
18:02:40.079 -> 3   -3  -20
18:02:40.126 -> 2   -3  -19
18:02:40.173 -> 5   0   -17
18:02:40.207 -> 4   -1  -15
18:02:40.242 -> 3   -5  -19
18:02:40.276 -> 5   -5  -28
18:02:40.318 -> -2  -2  -28
18:02:40.351 -> -4  -4  -25
18:02:40.400 -> -3  -3  -32
18:02:40.466 -> [E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbebec
18:02:40.466 -> [I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
18:02:40.466 -> [I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
18:02:40.466 -> [I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
18:02:40.466 -> [I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
18:02:40.466 -> [I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
18:02:40.466 -> [I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5
18:02:40.466 -> [I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84c0 bits=312
18:02:40.466 -> [I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb84f0
18:02:40.466 -> [I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb8584
18:02:40.500 -> [I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
18:02:40.500 -> [I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
18:02:40.500 -> [I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
18:02:40.500 -> [I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
18:02:40.500 -> [I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
18:02:40.500 -> [I][esp32-hal-i2c.c:311] i2cDumpDqData(): Debug Buffer not Enabled
18:02:40.500 -> [I][esp32-hal-i2c.c:354] i2cDumpInts(): Debug Buffer not Enabled
18:02:40.500 -> [I][esp32-hal-i2c.c:1130] i2cProcQueue(): Bus busy, reinit
18:02:40.500 -> -8  -1  -31
18:02:40.535 -> -7  -2  -25
18:02:40.585 -> -1  -3  -26
18:02:40.585 -> -1  -5  -23
18:02:40.632 -> -1  -5  -17
18:02:40.679 -> 1   -5  -19
18:02:40.726 -> 2   -1  -20

And finally, it shows me this and stops working:

18:05:33.998 -> 1   -1  -10
18:05:34.032 -> -1  -1  -11
18:05:34.098 -> [E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbebec
18:05:34.098 -> [I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
18:05:34.098 -> [I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
18:05:34.098 -> [I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
18:05:34.098 -> [I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
18:05:34.098 -> [I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
18:05:34.098 -> [I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5
18:05:34.098 -> [I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84c0 bits=312
18:05:34.098 -> [I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb84f0
18:05:34.098 -> [I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb8584
18:05:34.134 -> [I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
18:05:34.134 -> [I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
18:05:34.134 -> [I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
18:05:34.134 -> [I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
18:05:34.134 -> [I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
18:05:34.134 -> [I][esp32-hal-i2c.c:311] i2cDumpDqData(): Debug Buffer not Enabled
18:05:34.134 -> [I][esp32-hal-i2c.c:354] i2cDumpInts(): Debug Buffer not Enabled
18:05:34.134 -> [I][esp32-hal-i2c.c:1130] i2cProcQueue(): Bus busy, reinit

After crashing, it just stays like that forever, and it shows me this after reset button has been pressed:

18:09:04.859 -> ets Jun  8 2016 00:22:57
18:09:04.859 -> 
18:09:04.859 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
18:09:04.859 -> configsip: 0, SPIWP:0xee
18:09:04.859 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
18:09:04.859 -> mode:DIO, clock div:1
18:09:04.859 -> load:0x3fff0018,len:4
18:09:04.859 -> load:0x3fff001c,len:1044
18:09:04.859 -> load:0x40078000,len:8896
18:09:04.859 -> load:0x40080400,len:5816
18:09:04.859 -> entry 0x400806ac
18:09:05.046 -> Checking hardware revision...
18:09:05.046 -> Revision @ user[16][6] = 0
18:09:05.046 -> Resetting memory bank selection to 0...
18:09:05.046 -> DMP Initialization failed (code 1)

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.

lbernstone commented 4 years ago

Follow the instructions in the Wire docs. Post your debug results, and @stickbreaker will likely be able to help you.

ABKingbird commented 4 years ago
19:30:03.624 -> 3   -1  -15
19:30:03.657 -> 1   -4  -15
19:30:03.725 -> -1  0   -11
19:30:03.759 -> -2  2   -13
19:30:03.827 -> [E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbebec
19:30:03.827 -> [I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
19:30:03.827 -> [I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
19:30:03.827 -> [I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
19:30:03.827 -> [I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
19:30:03.827 -> [I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
19:30:03.827 -> [I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5
19:30:03.827 -> [I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84c0 bits=312
19:30:03.827 -> [I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb84f0
19:30:03.827 -> [I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb8584
19:30:03.861 -> [I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
19:30:03.861 -> [I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
19:30:03.861 -> [I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
19:30:03.861 -> [I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
19:30:03.861 -> [I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
19:30:03.861 -> [I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 R STOP buf@=0x3ffc0314, len=2, pos=0, ctrl=11111
19:30:03.861 -> [I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: ..                               00 00 
19:30:03.930 -> [I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 row   count   INTR    TX  RX  Tick 
19:30:03.930 -> [I][esp32-hal-i2c.c:350] i2cDumpInts(): [01]    0x0001  0x0002  0x0001  0x0000  0x00027684
19:30:03.930 -> [I][esp32-hal-i2c.c:350] i2cDumpInts(): [02]    0x0001  0x0200  0x0000  0x0000  0x00027684
19:30:03.930 -> [I][esp32-hal-i2c.c:350] i2cDumpInts(): [03]    0x0001  0x0020  0x0000  0x0000  0x00027684
19:30:03.930 -> [I][esp32-hal-i2c.c:1130] i2cProcQueue(): Bus busy, reinit
19:30:03.930 -> [V][esp32-hal-i2c.c:1484] i2cInit(): num=0 sda=23 scl=22 freq=0
19:30:03.930 -> [V][esp32-hal-i2c.c:1680] i2cSetFrequency(): freq=100000Hz
19:30:03.930 -> [V][esp32-hal-i2c.c:1696] i2cSetFrequency(): cpu Freq=240Mhz, i2c Freq=100000Hz
19:30:03.930 -> [V][esp32-hal-i2c.c:1704] i2cSetFrequency(): Fifo delta=1

This is what it showed me after I uncommented the #define ENABLE_I2C_DEBUG_BUFFER. Should I do the "Manually controlled Debugging" step as well or is this enough?

stickbreaker commented 4 years ago

@ABKingbird in the Wire() library directory is a documents folder that explains the debug output here

The Interesting parts from your first log output:

18:02:40.466 -> [I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5 18:02:40.500 -> [I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1 18:02:40.500 -> [I][esp32-hal-i2c.c:1130] i2cProcQueue(): Bus busy, reinit

From the Debug Documentation:

Error Msg Description Values
error internal ERROR status 0=not configured, 1=ok, 2=error, 3=address NAK, 4=data NAK, 5=arbitration loss, 6=timeout
errorByteCnt position in current data block when error occured -1=address byte

  The I2C hardware saw an arbitration error, The SDA line was LOW when the ESP32 expected it to be HIGH. Another device was driving the Bus when the ESP32 thought it had control.

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 Wire() transaction was started, so the bus was automatically cycled to abort the previous transaction and reset the I2c Bus.

A bus busy state can be detected by using: bool Wire.busy(); which returns true if I2C hardware thinks the bus is being controlled by another MASTER, or a i2c transaction was STARTed without a STOP being observed to end it. This busy condition is created when a TIMEOUT error occurs.

Wire() error Defines Numeric value Description
I2C_ERROR_OK 0 Success
I2C_ERROR_DEV 1 i2c hardware error, interrupt not available
I2C_ERROR_ACK 2 No i2c Slave device answered address id
I2C_ERROR_TIMEOUT 3 i2c SCL period exceeded maximum supported 13.1ms
I2C_ERROR_BUS 4 Bus is not Idle
I2C_ERROR_BUSY 5 Either previous transaction aborted, or Other MASTER device is using BUS. SDA and/or SCL is not HIGH.
I2C_ERROR_MEMORY 6 unable to allocate Memory buffer for transaction Queue
I2C_ERROR_CONTINUE 7 Still building I2C transaction, all i2c transaction must be terminated with a STOP (Wire.endTransmission(), Wire.endTransmission(true), Wire.requestFrom(id,len), or Wire.requestFrom(id,len,true))
I2C_ERROR_NO_BEGIN 8 Wire.write(),Wire.endTransmission() encountered before Wire.beginTransmission()

To manually recover the bus, you can use bool Wire.begin(); (without parameters) it will reuse your previously configured pins and clockrate. It will recycle the bus is necessary and return TRUE if the bus is ready for use.

Chuck.

lbernstone commented 4 years ago

Chuck, you should tag this issue as FOR REFERENCE. Good info.

ABKingbird commented 4 years ago

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 am waiting for it to crash to get some data right before the crash. So far, all the commands in the loop section look like this:

I2C (0x68) reading 2 bytes from 0x72...0 0. Done (2 read).
I2C (0x68) reading 2 bytes from 0x72...0 2A. Done (2 read).
I2C (0x68) reading 1 bytes from 0x3A...3. Done (1 read).
I2C (0x68) reading 2 bytes from 0x72...0 2A. Done (2 read).
I2C (0x68) reading 42 bytes from 0x74...3F FF 6F 53 0 60 8B C0 0 5F D5 6C FF FC 59 2 FF FF E9 A4 FF FF FF FE FF FF F4 D2 FF 5 D5 74 0 B1 5C 59 1F E4 33 DD B2 6A. Done (42 read).
-155 81 -26
I2C (0x68) reading 2 bytes from 0x72...0 0. Done (2 read).
I2C (0x68) reading 2 bytes from 0x72...0 0. Done (2 read).
I2C (0x68) reading 2 bytes from 0x72...0 2A. Done (2 read).
I2C (0x68) reading 1 bytes from 0x3A...3. Done (1 read).
I2C (0x68) reading 2 bytes from 0x72...0 2A. Done (2 read).
I2C (0x68) reading 42 bytes from 0x74...3F FF 6C FB 0 60 EB 9A 0 61 3 0 FF FC 58 72 FF FF DE 77 FF FF FF FE 0 0 0 0 FF 4 CB F5 0 AD 73 43 1F E0 F2 27 B2 6A. Done (42 read).
-154 77 -30

I will keep it running till it crashes and then post again.

ABKingbird commented 4 years ago

Welp. It seems that it didn't crash at all with that way. Don't know if I should be happy with that. My thought is (not sure though) that because Serial.print adds some kind of lag, the ESP32 and the MPU are given more time to synchronize. Don't know, whatever.

Anyway, I closed it and altered the libraries, as you told me to. After the upload, the system crashed as expected: -First "mini-crash" which didn't stop it from running:

031-19
033-14
-435-15
-237-20
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbebec
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84c0 bits=112
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb84f0
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb8584
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 R STOP buf@=0x3ffc0314, len=2, pos=0, ctrl=11111
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: ..                               00 00 
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 rowcountINTRTXRXTick 
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01]0x00010x00020x00010x00000x0000a19f
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02]0x00010x02000x00000x00000x0000a19f
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03]0x00010x00200x00000x00000x0000a19f
Read failure, expected 2, received 0, err=4(BUS)
[I][esp32-hal-i2c.c:1130] i2cProcQueue(): Bus busy, reinit
[V][esp32-hal-i2c.c:1484] i2cInit(): num=0 sda=23 scl=22 freq=0
[V][esp32-hal-i2c.c:1680] i2cSetFrequency(): freq=100000Hz
[V][esp32-hal-i2c.c:1696] i2cSetFrequency(): cpu Freq=240Mhz, i2c Freq=100000Hz
[V][esp32-hal-i2c.c:1704] i2cSetFrequency(): Fifo delta=1
-629-15
-1331-18
-933-19
-1033-14
032-17

-Second(and final) crash:

-35-20
-51-22
-30-25
-40-23
-12-21
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbebec
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84c0 bits=112
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb84f0
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb8584
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 R STOP buf@=0x3ffc0314, len=2, pos=0, ctrl=11111
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: ..                               00 00 
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 rowcountINTRTXRXTick 
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01]0x00010x00020x00010x00000x0001699e
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02]0x00010x02000x00000x00000x0001699e
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03]0x00010x00200x00000x00000x0001699e
[I][esp32-hal-i2c.c:1130] i2cProcQueue(): Bus busy, reinit
[V][esp32-hal-i2c.c:1484] i2cInit(): num=0 sda=23 scl=22 freq=0
[V][esp32-hal-i2c.c:1680] i2cSetFrequency(): freq=100000Hz
[V][esp32-hal-i2c.c:1696] i2cSetFrequency(): cpu Freq=240Mhz, i2c Freq=100000Hz
[V][esp32-hal-i2c.c:1704] i2cSetFrequency(): Fifo delta=1
Write failure err=2(ACK)
Read failure, expected 1, received 0, err=2(ACK)
Write failure err=2(ACK)
Read failure, expected 2, received 0, err=2(ACK)
Write failure err=2(ACK)
Read failure, expected 2, received 0, err=2(ACK)
Write failure err=2(ACK)
Read failure, expected 2, received 0, err=2(ACK)
Write failure err=2(ACK)
Read failure, expected 2, received 0, err=2(ACK)
Write failure err=2(ACK)

The last two lines just kept going afterwards, meaning it got stuck.

stickbreaker commented 4 years ago

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 Serial.printf() to a log_e() it will display the source line of the message, and you can identify the section of the library where the mpu6050 is being overloaded. You might have to reduction of i2c command rate.

Chuck.

stickbreaker commented 4 years ago

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.

ABKingbird commented 4 years ago

So that means it's probably the MPU's hardware or library problem? Anyway, yesterday, when I altered the library, I put a different name at each iteration of Wire.endTransmission() and Wire.requestFrom(). The part of code which the system gets stuck into is:

#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

Write failure err5=2(ACK)
Register Address=114

and some

Read failure, expected 2, received 0, err3=2(ACK)

here and there, which both belong in the "if" sketch above.

Finally, the system crashed, showing me this:

-3-3-3
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbebec
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb843c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=5
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84c0 bits=312
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb84f0
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb8584
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
[I][esp32-hal-i2c.c:288] i2cDumpDqData(): [0] 7bit 68 R STOP buf@=0x3ffc0314, len=2, pos=0, ctrl=11111
[I][esp32-hal-i2c.c:306] i2cDumpDqData(): 0x0000: ..                               00 00 
[I][esp32-hal-i2c.c:346] i2cDumpInts(): 0 rowcountINTRTXRXTick 
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [01]0x00010x00020x00010x00000x000abcb7
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [02]0x00010x02000x00000x00000x000abcb7
[I][esp32-hal-i2c.c:350] i2cDumpInts(): [03]0x00010x00200x00000x00000x000abcb7
[I][esp32-hal-i2c.c:1130] i2cProcQueue(): Bus busy, reinit
[V][esp32-hal-i2c.c:1484] i2cInit(): num=0 sda=23 scl=22 freq=0
[V][esp32-hal-i2c.c:1680] i2cSetFrequency(): freq=100000Hz
[V][esp32-hal-i2c.c:1696] i2cSetFrequency(): cpu Freq=240Mhz, i2c Freq=100000Hz
[V][esp32-hal-i2c.c:1704] i2cSetFrequency(): Fifo delta=1
Write failure err5=2(ACK)
Register Address=58
Read failure, expected 1, received 0, err3=2(ACK)
Write failure err5=2(ACK)
Register Address=114
Read failure, expected 2, received 0, err3=2(ACK)
Write failure err5=2(ACK)
Register Address=114
Read failure, expected 2, received 0, err3=2(ACK)
Write failure err5=2(ACK)
Register Address=114
Read failure, expected 2, received 0, err3=2(ACK)
Write failure err5=2(ACK)
Register Address=114

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

stickbreaker commented 4 years ago

Is that code a cut and paste from your source?
There is an extra Wire.beginTransmission(), delete it. I marked it with ">>>>>>>>>>>>>"

Also with ESP32, the BUFFER_LENGTH should be 128. I don't see where it is defined.

Chuck.

ABKingbird commented 4 years ago

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)". I commented it, ran the system again but got the exactly same errors; Some "Write failure" and "Read failure" here and there, one "mini-crash" and finally the last crash. All the same.

stickbreaker commented 4 years ago
                    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()));
}
stickbreaker commented 4 years ago

can you point me to copies of your included libraries:

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"

I'll take a look at them and see if I can identify coding that does not work with the ESP32.

I use Wire() with multiple I2C devices on the same bus without problems. I use 24lc512 EEPROMS and read blocks of 4096 bytes at a time and update a SSD1306 OLED at 40fps with a I2C clock at 800KHz.

Chuck.

ABKingbird commented 4 years ago

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. By the way, this unnecessary Wire.beginTransmission() appears also at some other similar parts of the library. I commented it there as well but still same errors.

Link to libraries: https://github.com/jrowberg/i2cdevlib These two libraries are located under "/Arduino" path. I extracted them in the libraries folder of Arduino sketch location.

ABKingbird commented 4 years ago

It is also worth mentioning that I had to to do these changes: https://github.com/jrowberg/i2cdevlib/pull/367 in order to compile. It wouldn't compile in the Arduino IDE if I had included the #include "MPU6050_6Axis_MotionApps20.h" unless these changes were made.

I-Connect commented 4 years ago

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 This is the main function that gets the data from the fifo buffer.

int8_t MPU6050::GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
     int16_t fifoC;
     // This section of code is for when we allowed more than 1 packet to be acquired
     uint32_t BreakTimer = micros();
     do {
         if ((fifoC = getFIFOCount())  > length) {

             if (fifoC > 200) { // if you waited to get the FIFO buffer to > 200 bytes it will take longer to get the last packet in the FIFO Buffer than it will take to  reset the buffer and wait for the next to arrive
                 resetFIFO(); // Fixes any overflow corruption
                 fifoC = 0;
                 while (!(fifoC = getFIFOCount()) && ((micros() - BreakTimer) <= (11000))); // Get Next New Packet
                 } else { //We have more than 1 packet but less than 200 bytes of data in the FIFO Buffer
                 uint8_t Trash[BUFFER_LENGTH];
                 while ((fifoC = getFIFOCount()) > length) {  // Test each time just in case the MPU is writing to the FIFO Buffer
                     fifoC = fifoC - length; // Save the last packet
                     uint16_t  RemoveBytes;
                     while (fifoC) { // fifo count will reach zero so this is safe
                         RemoveBytes = min((int)fifoC, BUFFER_LENGTH); // Buffer Length is different than the packet length this will efficiently clear the buffer
                         getFIFOBytes(Trash, (uint8_t)RemoveBytes);
                         fifoC -= RemoveBytes;
                     }
                 }
             }
         }
         if (!fifoC) return 0; // Called too early no data or we timed out after FIFO Reset
         // We have 1 packet
         if ((micros() - BreakTimer) > (11000)) return 0;
     } while (fifoC != length);
     getFIFOBytes(data, length); //Get 1 packet
     return 1;
}

and the method that handles the calibration:

void MPU6050::PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops){
    uint8_t SaveAddress = (ReadAddress == 0x3B)?((getDeviceID() < 0x38 )? 0x06:0x77):0x13;

    int16_t  Data;
    float Reading;
    int16_t BitZero[3];
    uint8_t shift =(SaveAddress == 0x77)?3:2;
    float Error, PTerm, ITerm[3];
    int16_t eSample;
    uint32_t eSum ;
    Serial.write('>');
    for (int i = 0; i < 3; i++) {
        I2Cdev::readWords(devAddr, SaveAddress + (i * shift), 1, (uint16_t *)&Data); // reads 1 or more 16 bit integers (Word)
        Reading = Data;
        if(SaveAddress != 0x13){
            BitZero[i] = Data & 1;                                       // Capture Bit Zero to properly handle Accelerometer calibration
            ITerm[i] = ((float)Reading) * 8;
            } else {
            ITerm[i] = Reading * 4;
        }
    }
    for (int L = 0; L < Loops; L++) {
        eSample = 0;
        for (int c = 0; c < 100; c++) {// 100 PI Calculations
            eSum = 0;
            for (int i = 0; i < 3; i++) {
                I2Cdev::readWords(devAddr, ReadAddress + (i * 2), 1, (uint16_t *)&Data); // reads 1 or more 16 bit integers (Word)
                Reading = Data;
                if ((ReadAddress == 0x3B)&&(i == 2)) Reading -= 16384;  //remove Gravity
                Error = -Reading;
                eSum += abs(Reading);
                PTerm = kP * Error;
                ITerm[i] += (Error * 0.001) * kI;               // Integral term 1000 Calculations a second = 0.001
                if(SaveAddress != 0x13){
                    Data = round((PTerm + ITerm[i] ) / 8);      //Compute PID Output
                    Data = ((Data)&0xFFFE) |BitZero[i];         // Insert Bit0 Saved at beginning
                } else Data = round((PTerm + ITerm[i] ) / 4);   //Compute PID Output
                I2Cdev::writeWords(devAddr, SaveAddress + (i * shift), 1, (uint16_t *)&Data);
            }
            if((c == 99) && eSum > 1000){                       // Error is still to great to continue 
                c = 0;
                Serial.write('*');
            }
            if((eSum * ((ReadAddress == 0x3B)?.05: 1)) < 5) eSample++;  // Successfully found offsets prepare to  advance
            if((eSum < 100) && (c > 10) && (eSample >= 10)) break;      // Advance to next Loop
            delay(1);
        }
        Serial.write('.');
        kP *= .75;
        kI *= .75;
        for (int i = 0; i < 3; i++){
            if(SaveAddress != 0x13) {
                Data = round((ITerm[i] ) / 8);      //Compute PID Output
                Data = ((Data)&0xFFFE) |BitZero[i]; // Insert Bit0 Saved at beginning
            } else Data = round((ITerm[i]) / 4);
            I2Cdev::writeWords(devAddr, SaveAddress + (i * shift), 1, (uint16_t *)&Data);
        }
    }
    resetFIFO();
    resetDMP();
}
LeehamElectronics commented 3 years ago

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. Here is the error message:

*WM: [1] connectTimeout not set, ESP waitForConnectResult... 
Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed)
Core 1 register dump:
PC      : 0x400d194c  PS      : 0x00060034  A0      : 0x40085390  A1      : 0x3ffbe7b0  
A2      : 0x00000007  A3      : 0x3ffc1b78  A4      : 0x00000080  A5      : 0x00000000  
A6      : 0x00000000  A7      : 0x1300025c  A8      : 0x80081444  A9      : 0x00000001  
A10     : 0x00000000  A11     : 0x00000000  A12     : 0x3ffc1ee4  A13     : 0x00000000  
A14     : 0x3ffc1ee0  A15     : 0xffffffff  SAR     : 0x00000016  EXCCAUSE: 0x00000007  
EXCVADDR: 0x00000000  LBEG    : 0x00000000  LEND    : 0x00000000  LCOUNT  : 0x00000000  
Core 1 was running in ISR context:
EPC1    : 0x40087648  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x400d194c

Backtrace: 0x400d194c:0x3ffbe7b0 0x4008538d:0x3ffbe7d0 0x40087645:0x3ffba190 0x400837ab:0x3ffba1b0 0x40089799:0x3ffba1d0

Rebooting...
ets Jun  8 2016 00:22:57

Any help would be great!! Cheers

LeehamElectronics commented 3 years ago

Wait is this the reason? https://github.com/tzapu/WiFiManager/issues/854#issuecomment-475146945

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?

LeehamElectronics commented 3 years ago

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