Jump to content
I2Cdevlib Forums

Arduino freezes randomly using MPU6050 and SD shield


Recommended Posts

Hello!

 

I'm trying to log the acceleration measured by a MPU6050 on a GY-521 breakout board on a microSD card using a microSD shield made by Sparkfun.

 

Because the MPU6050_DMP6 sketch from the MPU6050 library of Jeff Rowberg (also using his I2Cdev lib) and the dataLogger sketch from the SDfat library  both worked very good (when runnning alone) i thought i could combine them to achieve my goal.

I deleted the (for my use) unnecessary code and instead of printing the acceleration data to the serial monitor i print it to the logfile.

But this is not working so great. The sketch stops working completely random. Sometimes it runs for a couple of minutes, sometimes only for a few seconds. When it freezes i have to reset the arduino and it runs again for some time.

I just can't figure out what the problem is.

 

Here is what i already tried:

 

1) check the connections

   SD shield is just put on top of the arduino

   MPU -> Arduino

   VCC -> 5V

   GND -> GND

   SCL -> Analog 5

   SDA -> Analog 4

   INT -> Digital 2

   solder points look good

 

2) check memory usage 

   don't remember the exact value but it was stable and there was enough free memory

 

3) a LOT of different approaches how to handle the data

   all with pretty much the same results, i will spare you the details because mostly it was "try and error"

 

Here is the basic sketch i described:

 




/////////////////////////////////////////////////////////////////////////////////
#define BUTTON_PIN 4


/////////////////////////////////////////////////////////////////////////////////
//////////////Includes, Constants and Objects for datalogging////////////////////
#include <SdFat.h>


// SD chip select pin.  Be sure to disable any other SPI devices such as Enet.
const uint8_t chipSelect = 8;


//#define LOG_ACC


// Log file base name.  Must be six characters or less.
#define FILE_BASE_NAME "DATA"


// Error messages stored in flash.
#define error(msg) error_P(PSTR(msg))


// File system object.
SdFat sd;


// Log file.
SdFile file;


//Variable for collumn separation  *************
char tab = ';';


/////////////////////////////////////////////////////////////////////////////////
//////////////////////Includes, Constants and Objects for MPU////////////////////
#include "I2Cdev.h"


#include "MPU6050_6Axis_MotionApps20.h"


//#define OUTPUT_READABLE_REALACCEL


// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif


// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
//MPU6050 mpu(0x69); // <-- use for AD0 high


//#define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6)
bool blinkState = false;


// 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


// packet structure for InvenSense teapot demo
uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', '\n' };


/////////////////////////////////////////////////////////////////////////////////
//////////////////////////////User functions/////////////////////////////////////


//------------------------------------------------------------------------------
// Write data header.
void writeHeader() 
{
  file.print(F("accel_X"));
  file.print(tab);
  file.print(F("accel_Y"));
  file.print(tab);
  file.print(F("accel_Z"));
  
  file.println();
}


//------------------------------------------------------------------------------
// error messages
void error_P(const char* msg) {
  sd.errorHalt_P(msg);
}


//------------------------------------------------------------------------------
// Interrupt detection
volatile bool mpuInterrupt = false;     // indicates whether MPU interrupt pin has gone high
void dmpDataReady() {
    mpuInterrupt = true;
}


//------------------------------------------------------------------------------
// setup function
void setup() 
{
  const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
  char fileName[13] = FILE_BASE_NAME "00.CSV";
  
  Serial.begin(115200);
  //while (!Serial) {} // wait for Leonardo
  //delay(1000);
  
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  Serial.println(F("Press Button to start"));
  while(digitalRead(BUTTON_PIN)) {} //wait for button
  
  // Initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!sd.begin(chipSelect, SPI_FULL_SPEED)) sd.initErrorHalt();
  
  // Find an unused file name.
  if (BASE_NAME_SIZE > 6) 
  {
    error("FILE_BASE_NAME too long");
  }
  while (sd.exists(fileName)) 
  {
    if (fileName[BASE_NAME_SIZE + 1] != '9') 
    {
      fileName[BASE_NAME_SIZE + 1]++;
    } 
    else if (fileName[BASE_NAME_SIZE] != '9') 
    {
      fileName[BASE_NAME_SIZE + 1] = '0';
      fileName[BASE_NAME_SIZE]++;
    } 
    else 
    {
      error("Can't create file name");
    }
  }
  if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) error("file.open");
  do 
  {
    delay(10);
  } while (Serial.read() >= 0);
  
  Serial.print(F("Logging to: "));
  Serial.println(fileName);
  
  // Write data header.
  writeHeader();
  
  // 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


  // initialize device
  Serial.println(F("Initializing I2C devices..."));
  mpu.initialize();


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


  // load and configure the DMP
  Serial.println(F("Initializing DMP..."));
  devStatus = mpu.dmpInitialize();


  // supply your own gyro offsets here, scaled for min sensitivity
  mpu.setXGyroOffset(99);
  mpu.setYGyroOffset(-35);
  mpu.setZGyroOffset(67);
  mpu.setZAccelOffset(1106); // 1688 factory default for my test chip


  // 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.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
    attachInterrupt(0, 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(")"));
  }


    // configure LED for output
    pinMode(13, OUTPUT);
}




// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================


void loop() 
{
  // if programming failed, don't try to do anything
  if (!dmpReady) return;
    
  // wait for MPU interrupt
  while (!mpuInterrupt && fifoCount < packetSize) 
  {
        // other program behavior stuff here
        // .
        // .
        // .
        // if you are really paranoid you can frequently test in between other
        // stuff to see if mpuInterrupt is true, and if so, "break;" from the
        // while() loop to immediately process the MPU data
        // .
        // .
        // .
  }


    // reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();


    // get current FIFO count
    fifoCount = mpu.getFIFOCount();


    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));


    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();


        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;


        // get real acceleration, adjusted to remove gravity
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetAccel(&aa, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
        
        file.print(aaReal.x);
        file.write(tab);//***************
        file.print(aaReal.y);
        file.write(tab);//***************
        file.println(aaReal.z);
      
        // Force data to SD and update the directory entry to avoid data loss.
        if (!file.sync() || file.getWriteError()) Serial.println(F("write error"));
        
        if (!digitalRead(BUTTON_PIN)) 
        {
          // Close file and stop.
          file.close();
          Serial.println(F("Done"));
          while(1) {}
        }
    }
}



If you have any ideas how to solve this issue, any help will be greatly appreciated.

wambo

Link to comment
Share on other sites

  • 3 weeks later...
  • 1 month later...

Hello Wambo0402,

 

Any luck with this problem? I ran into the same problem with the Sparkfun 9150 breakout and the Adafruit microSD breakout card. Something I have found that makes it work better is not flushing the SD buffer everytime you write to it, but only every 10 or more times. Also, saving the data in binary will save the conversion time.

 

I get the feeling that the Arduino (I am using a UNO) just doesn't have enough horsepower. I have been trying to get the Texas Instrument Tiva TM4C123G using the Energia IDE (adapted from Arduino), but I need to convert the files. Not an easy task. The Tiva series of microprocessors are considerably more powerful than the Arduinos, and a lot cheaper (about $13.25 at Element14.com). There are other IDEs, including Code Composer Studio, but the learning curve is quite steep, since a lot of the underlying hardware details are not hidden from you as in the Arduino or Energia IDEs, and you have to deal with them explicitly. 

 

For my application, I need to have 100% reliability. I still don't have it.

 

Best of luck

Link to comment
Share on other sites

  • 6 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...