fifo overflow while using MPU-6050 and SD Card Module .

Hi

I mixing MPU6050 sample and SD Card and it says fifo overflow in every ~500 milisecond :confused:

6,6677, 2.89,-2.83,59.52
6,6700, 2.87,-2.79,59.48
FIFO overflow!
6,6734, 2.84,-1.85,58.42
6,6757, 2.84,-1.82,58.38

  • I changed Baud Rate into low number ,but not happened! :frowning:
  • I changed TWBR into low number (12) but not happened! :frowning:
  • I add delay into the end of ‚Äúvoid loop()‚ÄĚ but not happened! :frowning:

I attached my code to post.
thanks for your help…

MPU6050_SD.ino (17 KB)

you should not slow your loop, you are making the problem worse.

consider changing the DMP output rate - from the top if my head the default sampling rate is 100Hz and with all your prints (consider minimizing that) or SD card access, you are probably impacting the performance of your loop and thus are filling up the FIFO faster than you empty it.

J-M-L: you should not slow your loop, you are making the problem worse.

consider changing the DMP output rate - from the top if my head the default sampling rate is 100Hz and with all your prints (consider minimizing that) or SD card access, you are probably impacting the performance of your loop and thus are filling up the FIFO faster than you empty it.

sooo.... how I can fix that ?! :blush:

sshahriyari:
sooo… how I can fix that ?! :blush:

I faced this problem and resolved it. Here is my code it should work with your libraries as you have them :slight_smile:

This is what I am using to control my Balancing bot with no FIFO overflow issues and it has lots of documentation on retrieving the DMP data from the FIFO buffer

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
MPU6050 mpu;

#define DEBUG
#ifdef DEBUG
//#define DPRINT(args...)  Serial.print(args)             //OR use the following syntax:
#define DPRINTSTIMER(t)    for (static unsigned long SpamTimer; (unsigned long)(millis() - SpamTimer) >= (t); SpamTimer = millis())
#define  DPRINTSFN(StrSize,Name,...) {char S[StrSize];Serial.print("\t");Serial.print(Name);Serial.print(" "); Serial.print(dtostrf((float)__VA_ARGS__ ,S));}//StringSize,Name,Variable,Spaces,Percision
#define DPRINTLN(...)      Serial.println(__VA_ARGS__)
#else
#define DPRINTSTIMER(t)    if(false)
#define DPRINTSFN(...)     //blank line
#define DPRINTLN(...)      //blank line
#endif



#define LED_PIN 13 // 

// supply your own gyro offsets here, scaled for min sensitivity use MPU6050_calibration.ino
// -4232  -706  1729  173 -94 37
//                       XA      YA      ZA      XG      YG      ZG
//int MPUOffsets[6] = {  -4232,  -706,   1729,    173,    -94,     37};
int MPUOffsets[6] = {  2471,  -563,  1628,  8, -23, 53};


// ================================================================
// ===                      i2c SETUP Items                     ===
// ================================================================
void i2cSetup() {
  // join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();
  TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
#endif
}

// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
  mpuInterrupt = true;
}

// ================================================================
// ===                      MPU DMP SETUP                       ===
// ================================================================
int FifoAlive = 0; // tests if the interrupt is triggering
int IsAlive = -20;     // counts interrupt start at -20 to get 20+ good values before assuming connected
// MPU control/status vars
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
byte StartUP = 100; // lets get 100 readings from the MPU before we start trusting them (Bot is not trying to balance at this point it is just starting up.)

void MPU6050Connect() {
  static int MPUInitCntr = 0;
  // initialize device
  mpu.initialize(); // same
  // load and configure the DMP
  devStatus = mpu.dmpInitialize();// same

  if (devStatus != 0) {
    // ERROR!
    // 1 = initial memory load failed
    // 2 = DMP configuration updates failed
    // (if it's going to break, usually the code will be 1)

    char * StatStr[5] { "No Error", "initial memory load failed", "DMP configuration updates failed", "3", "4"};

    MPUInitCntr++;

    Serial.print(F("MPU connection Try #"));
    Serial.println(MPUInitCntr);
    Serial.print(F("DMP Initialization failed (code "));
    Serial.print(StatStr[devStatus]);
    Serial.println(F(")"));

    if (MPUInitCntr >= 10) return; //only try 10 times
    delay(1000);
    MPU6050Connect(); // Lets try again
    return;
  }
  mpu.setXAccelOffset(MPUOffsets[0]);
  mpu.setYAccelOffset(MPUOffsets[1]);
  mpu.setZAccelOffset(MPUOffsets[2]);
  mpu.setXGyroOffset(MPUOffsets[3]);
  mpu.setYGyroOffset(MPUOffsets[4]);
  mpu.setZGyroOffset(MPUOffsets[5]);

  Serial.println(F("Enabling DMP..."));
  mpu.setDMPEnabled(true);
  // enable Arduino interrupt detection
  Serial.println(F("Enabling interrupt detection (Arduino external interrupt pin 2 on the Uno)..."));
  Serial.print("mpu.getInterruptDrive=  "); Serial.println(mpu.getInterruptDrive());
  attachInterrupt(0, dmpDataReady, RISING); //pin 2 on the Uno
  mpuIntStatus = mpu.getIntStatus(); // Same
  // get expected DMP packet size for later comparison
  packetSize = mpu.dmpGetFIFOPacketSize();
  delay(1000); // Let it Stabalize
  mpu.resetFIFO(); // Clear fifo buffer
  mpu.getIntStatus();
  mpuInterrupt = false; // wait for next interrupt
}

// ================================================================
// ===                    MPU DMP Get Data                      ===
// ================================================================
void GetDMP() { // Best version I have made so far
  // Serial.println(F("FIFO interrupt at:"));
  // Serial.println(micros());
  static unsigned long LastGoodPacketTime;
  mpuInterrupt = false;
  FifoAlive = 1;
  fifoCount = mpu.getFIFOCount();
  if ((!fifoCount) || (fifoCount % packetSize)) { // we have failed Reset and wait till next time!
    digitalWrite(LED_PIN, LOW); // lets turn off the blinking light so we can see we are failing.
    mpu.resetFIFO();// clear the buffer and start over
  } else {
    while (fifoCount  >= packetSize) { // Get the packets until we have the latest!
      mpu.getFIFOBytes(fifoBuffer, packetSize); // lets do the magic and get the data
      fifoCount -= packetSize;
    }
    LastGoodPacketTime = millis();
    MPUMath(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<< On success MPUMath() <<<<<<<<<<<<<<<<<<<
    digitalWrite(LED_PIN, !digitalRead(LED_PIN)); // Blink the Light
  }
}


// ================================================================
// ===                        MPU Math                          ===
// ================================================================
float Yaw, Pitch, Roll;
void MPUMath() {
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  Yaw = (ypr[0] * 180.0 / M_PI);
  Pitch = (ypr[1] *  180.0 / M_PI);
  Roll = (ypr[2] *  180.0 / M_PI);
  DPRINTSTIMER(100) {
    DPRINTSFN(15, "\tYaw:", Yaw, 6, 1);
    DPRINTSFN(15, "\tPitch:", Pitch, 6, 1);
    DPRINTSFN(15, "\tRoll:", Roll, 6, 1);
    DPRINTLN();
  }
}
// ================================================================
// ===                         Setup                            ===
// ================================================================
void setup() {
  Serial.begin(115200); //115200
  while (!Serial);
  Serial.println("i2cSetup");
  i2cSetup();
  Serial.println("MPU6050Connect");
  MPU6050Connect();
  Serial.println("Setup complete");
  pinMode(LED_PIN, OUTPUT);
}
// ================================================================
// ===                          Loop                            ===
// ================================================================
void loop() {
  if (mpuInterrupt ) { // wait for MPU interrupt or extra packet(s) available
    GetDMP();
  }
}

Enjoy

Z

Attached MPU Calibration Code Below

MPU6050_calibration.ino (7.64 KB)

many thanks guys !

I found a very bad solution ...

To prevent overflow problems, please, go to MPU6050_6Axis_MotionApps20.h and modify that line:

0x02, 0x16, 0x02, 0x00, 0x01 // D_0_22 inv_set_fifo_rate The value in bold is the objective! Change it to 0x03 or 0x04 or 0x05 to reduce the Hz of rate. I am using 0x03 and not getting error values, junk data, or overflows anymore.

I have overflow even with "0x03" . I was forced to use "0x04" ! :(

Who knows where is my problem?

My modules :

  • Arduino Genuino UNO
  • MPU6050 (Pin A5,2)
  • SD Card Module (Pin 10,11,12,13)

Do you understand what fifo means and how it works ?

In a nutshell

1/ you have a component (MPU) capturing samples and puttting those samples in a buffer. The sampling rate is defined through an API, you can get 10 samples per second, 50 or 100. Each sample has a certain size (number of bytes captured) and your total buffer has a certain size. Say your buffer is 1000 bytes, a sample 10 bytes and you are capturing at 100 Hz (100 times per second) then in 1 second you captured 100 x 10 bytes = 1000 bytes and thus your buffer is full

2/ seprarateky - totally independently - you have a processor reading the oldest sample (fifo = first in first out) and doing something with it.

It becomes obvious then that if your process consuming the samples is too slow compared to the one creating the samples then you will overflow. This is what is happening to you most likely.

Three options to solve this:

1/ make your loop faster - you need to handle a sample in the loop FASTER than they are being captured. (You might want to understand better how buffer are used to write to an SD card and leverage that)

2/ slow acquisition rate in the MPU to match the time it takes to deal with a sample

3/ empty the sample buffer every time you get a chance to read the buffer and only use the latest sample to take action in the loop

Or a mix of those technics

sshahriyari:
many thanks guys !

I found a very bad solution …

I have overflow even with ‚Äú0x03‚ÄĚ . I was forced to use ‚Äú0x04‚ÄĚ ! :frowning:

Who knows where is my problem?

My modules :

  • Arduino Genuino UNO
  • MPU6050 (Pin A5,2)
  • SD Card Module (Pin 10,11,12,13)

The initial program developed by Jeff Rowberg is difficult to troubleshoot and integrate additional code into it. this version I created does exactly the same but without the confusion.

I moved your SD Card Code you added to his sketch into my version and I have compiled it successfully it should be easier to read and follow because everything is in functions

I also added a FIFO Reset Right after the SD Card Code to clear out any bad old or corrupt data if it takes too long to handle the SD Card transaction.

Third I added a spam timer to the serial output because that takes time and could be part of your problem too.

Last I noticed your dynamic memory was getting low so I placed the static strings inside the F() macro preventing a copy of the string from being set in dynamic memory.

So if all works perfectly you will store gyro data at 100 times a second and display on the serial port a sample of the output at 10 times a second

The New SaveDataToSDCard() function:

// ================================================================
// ===                  Save Data To SD Card                    ===
// ================================================================
void SaveDataToSDCard() {
  float Yaw, Pitch, Roll;
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  Yaw = (ypr[0] * 180.0 / M_PI);
  Pitch = (ypr[1] *  180.0 / M_PI);
  Roll = (ypr[2] *  180.0 / M_PI);

  unsigned long Time;
  Time = micros();
  myFile.print(millis()); myFile.print(F(",\t"));
  myFile.print(Yaw); myFile.print(F(","));
  myFile.print(Pitch); myFile.print(F(","));
  myFile.print(Roll); myFile.println();
  myFile.flush();  // Save it.

  Time = micros() - Time;
  char S[10]; 
  // Serial port Spam Prevention:
  static int Counter; // MPU6050 interrupt triggers every 10 Milliseconds unless other code takes too long
  if ( Counter >= 10 ) { // Print output every 100 milliseconds
    Serial.print(F("SD Card Save Time "));    Serial.print(Time); Serial.print(F(" Microseconds"));
    Serial.print(F("\tYaw "));   Serial.print(dtostrf((float) Yaw, 6, 1 , S));
    Serial.print(F("\tPitch "));  Serial.print(dtostrf((float) Pitch, 6, 1 , S));
    Serial.print(F("\tRoll "));   Serial.print(dtostrf((float) Roll, 6, 1 , S));
    Serial.println();
    Counter = 0;
  }
  Counter++;

  // Reset The FIFO Buffer Because the above lines probibly takes longer than 10 milliseconds to handle and The next FIFO output Could Be OLD and or Corrupt data
  mpuInterrupt = false;
  mpu.resetFIFO();// clear the FIFO buffer and start over

}

Complete Sketch attached Below

I was not able to test this code directly with an SD card Please Let me know how it goes.

Z

MPU6050_Latest_code_SD.ino (8.93 KB)

zhomeslice: I was not able to test this code directly with an SD card Please Let me know how it goes.

probably a minor mistake with capital C and lower case c to the static counter variable

J-M-L: probably a minor mistake with capital C and lower case c to the static counter variable

I Saw That... Thought I corrected it before upload Thanks J-M-L for the catch :) Fixed the original post #7's file Z

zhomeslice: I Saw That... Thought I corrected it before upload Thanks J-M-L for the catch :) Fixed the original post #7's file Z

might be worth resetting it too from time to time (and for sake of clarity formally initialize it to 0)

J-M-L: might be worth resetting it too from time to time (and for sake of clarity formally initialize it to 0)

Yep this is what happens when you switch from a blink without delay to a counter and assume everything works lol Corrected this also Thanks again. I hope this solves sshahriyari problem. I have been thinking about creating a similar function then I saw sshahriyari post and it gave me the excuse to make it happen. :) Now all I need is the SD Card for my project. Z

Now all I need is the SD Card for my project.

yeah - $1 on eBay if you want to wait for a month...

zhomeslice: The initial program developed by Jeff Rowberg is difficult to troubleshoot and integrate additional code into it. this version I created does exactly the same but without the confusion.

I moved your SD Card Code you added to his sketch into my version and I have compiled it successfully it should be easier to read and follow because everything is in functions

I also added a FIFO Reset Right after the SD Card Code to clear out any bad old or corrupt data if it takes too long to handle the SD Card transaction.

Third I added a spam timer to the serial output because that takes time and could be part of your problem too.

Last I noticed your dynamic memory was getting low so I placed the static strings inside the F() macro preventing a copy of the string from being set in dynamic memory.

So if all works perfectly you will store gyro data at 100 times a second and display on the serial port a sample of the output at 10 times a second

The New SaveDataToSDCard() function:

// ================================================================
// ===                  Save Data To SD Card                    ===
// ================================================================
void SaveDataToSDCard() {
  float Yaw, Pitch, Roll;
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  Yaw = (ypr[0] * 180.0 / M_PI);
  Pitch = (ypr[1] *  180.0 / M_PI);
  Roll = (ypr[2] *  180.0 / M_PI);

  unsigned long Time;   Time = micros();   myFile.print(millis()); myFile.print(F(",\t"));   myFile.print(Yaw); myFile.print(F(","));   myFile.print(Pitch); myFile.print(F(","));   myFile.print(Roll); myFile.println();   myFile.flush();  // Save it.

  Time = micros() - Time;   char S[10];   // Serial port Spam Prevention:   static int Counter; // MPU6050 interrupt triggers every 10 Milliseconds unless other code takes too long   if ( Counter >= 10 ) { // Print output every 100 milliseconds     Serial.print(F("SD Card Save Time "));    Serial.print(Time); Serial.print(F(" Microseconds"));     Serial.print(F("\tYaw "));  Serial.print(dtostrf((float) Yaw, 6, 1 , S));     Serial.print(F("\tPitch "));  Serial.print(dtostrf((float) Pitch, 6, 1 , S));     Serial.print(F("\tRoll "));  Serial.print(dtostrf((float) Roll, 6, 1 , S));     Serial.println();     Counter = 0;   }   Counter++;

  // Reset The FIFO Buffer Because the above lines probibly takes longer than 10 milliseconds to handle and The next FIFO output Could Be OLD and or Corrupt data   mpuInterrupt = false;   mpu.resetFIFO();// clear the FIFO buffer and start over

}



Complete Sketch attached Below

I was not able to test this code directly with an SD card Please Let me know how it goes.

Z

Just I can say " I LOVE YOU" !!!! :D :D :D


Before I read it, I think maybe if I store data with binary format, Can save my time and overflow not happen. is it right?

sshahriyari: Before I read it, I think maybe if I store data with binary format, Can save my time and overflow not happen. is it right?

Not sure Try what I gave you and see if the Time stamp on the serial output is about every 100 Milliseconds if it is The code isn't being delayed if it is greater than 110 milliseconds then we are missing samples because the SD save code is taking longer. You should not experience FIFO overflow errors any more.

zhomeslice: Not sure Try what I gave you and see if the Time stamp on the serial output is about every 100 Milliseconds if it is The code isn't being delayed if it is greater than 110 milliseconds then we are missing samples because the SD save code is taking longer. You should not experience FIFO overflow errors any more.

I tested it, it works perfectly. but how I can know it does overflow or not?


new problem: I just add a tone into your code and arduino IDE says "Sketch too big" this code :

if ((millis()/100)%50==0) {
    tone(9, 988, 50);
    myFile.print(",Beep");
  }

sshahriyari:
I tested it, it works perfectly. but how I can know it does overflow or not?


new problem:
I just add a tone into your code and arduino IDE says ‚ÄúSketch too big‚ÄĚ
this code :

if ((millis()/100)%50==0) {

tone(9, 988, 50);
   myFile.print(",Beep");
 }

Is there another library added?
Can you post the complete sketch file as an attachment?
I am not sure how to help
Also Post some of the serial output. I will be able to tell if it overflowed based on the SD Card Save Time given
Z

Well the tone library is large and uses interrupts so will slow your loop even further... are you sure you need bells and whistles to this code? If so you will need to swap for a more capable arduino (more memory, faster CPU)

zhomeslice:
Is there another library added?
Can you post the complete sketch file as an attachment?
I am not sure how to help
Also Post some of the serial output. I will be able to tell if it overflowed based on the SD Card Save Time given
Z

No, I dont add library. just this code " tone(9, 988, 50); " into a if()
yes, I attached.

J-M-L:
Well the tone library is large and uses interrupts so will slow your loop even further… are you sure you need bells and whistles to this code? If so you will need to swap for a more capable arduino (more memory, faster CPU)

I want to use this device as portable logger. I add some tone because I can’t use serial monitor in portable mode. This is why I need tone :confused:

*** many thanks for your help guys. ***

MPU6050_Latest_code_SD_tone.ino (9.02 KB)

No, I dont add library. just this code " tone(9, 988, 50); " into a if()

Well that adds to your program the code for tone() which is large. Consider adding a LED instead if you run out of memory...

sshahriyari: new problem: I just add a tone into your code and arduino IDE says "Sketch too big" this code :

if ((millis()/100)%50==0) {
    tone(9, 988, 50);
    myFile.print(",Beep");
  }

UNO compiled Successfully!

Sketch uses 26,862 bytes (83%) of program storage space. Maximum is 32,256 bytes.
Global variables use 1,355 bytes (66%) of dynamic memory, leaving 693 bytes for local variables. Maximum is 2,048 bytes.

I got it to compile for my UNO? what board are you compiling it for?

Z