MPU9150 (JEFF LIB) + FIFOOVERFLOW INTERRUPT + SERIAL PRINT

Arduino enthusiasts!

I am trying to log accelerometer and gyro data using Serial.print. I have enabled the FIFO_Overflow interrupt. Whenever I log data, the serial port freezes. I am suspecting an interrupt issue while I am using Serial.print. Is there any way to get continuous data for debugging purposes? I know that the Serial library can affect interrupts and wonder whether you guys could help me a little bit ?

#include "Wire.h"    
#include "I2Cdev.h"
#include "MPU9150.h"
#include "helper_3dmath.h"
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU9150 accelGyroMag;    
#define LED_PIN 13
volatile boolean state_fifo_int = false;
uint16_t fifo_count;
uint8_t fifo_buffer[8];
int16_t acc_temp[3];
int16_t gyro_x;

void setup(){
    // join I2C bus (I2Cdev library doesn't do this automatically)
    Wire.begin();    
    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(115200);
    // initialize device
    Serial.println("Initializing I2C devices...");
    accelGyroMag.initialize();
    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelGyroMag.testConnection() ? "MPU9150 connection successful" : "MPU9150 connection failed");
    // configure Arduino LED for
    pinMode(LED_PIN, OUTPUT);
    attachInterrupt(0,fifo_int,CHANGE);
}

void fifo_int() {
  state_fifo_int = true; 
}

void loop(){
  while(!state_fifo_int) {
    accelGyroMag.setIntFIFOBufferOverflowEnabled(true);
    // enable fifo_interrupt
    accelGyroMag.setFIFOEnabled(true);
    accelGyroMag.setAccelFIFOEnabled(true);
    accelGyroMag.getXGyroFIFOEnabled();
    accelGyroMag.getAccelFIFOEnabled();
    fifo_count = accelGyroMag.getFIFOCount();
    accelGyroMag.getFIFOBytes(fifo_buffer,8); // fill in fifo bytes
    acc_temp[0] = (((int16_t)fifo_buffer[0]) << 8) | fifo_buffer[1];
    acc_temp[1] = (((int16_t)fifo_buffer[2]) << 8) | fifo_buffer[3];
    acc_temp[2] = (((int16_t)fifo_buffer[4]) << 8) | fifo_buffer[5];
    gyro_x = (((int16_t)fifo_buffer[6]) << 8) | fifo_buffer[7];
    Serial.print((float)acc_temp[0]/16384);
    Serial.print("  ");
    Serial.print((float)acc_temp[1]/16384);
    Serial.print(" ");
    Serial.print((float)acc_temp[2]/16384);
    Serial.print(" ");
    Serial.println(gyro_x);
   }
   accelGyroMag.setIntFIFOBufferOverflowEnabled(false);
   // disable fifo_interrupt
   accelGyroMag.resetFIFO();
   state_fifo_int = false;
}

volkan163:
Arduino enthusiasts!

I am trying to log accelerometer and gyro data using Serial.print. I have enabled the FIFO_Overflow interrupt. Whenever I log data, the serial port freezes. I am suspecting an interrupt issue while I am using Serial.print. Is there any way to get continuous data for debugging purposes? I know that the Serial library can affect interrupts and wonder whether you guys could help me a little bit ?

void setup(){
    attachInterrupt(0,fifo_int,CHANGE);
}

I would not use CHANGE as interrupt trigger, your Sensor should only trigger on low or high, not both. The sensor can be configured for either. but your code does not specify which is being used.

this is how I change your code:

void blink(uint16_t offTime, uint16_t onTime){
digitalWrite(LED_BUILTIN,HIGH);
if(onTime) delay(onTime);
digitalWrite(LED_BUILTIN,LOW);
if(offTime) delay(offTime);
}

void resetSensor(){
    // verify connection
if(accelGyroMag.testConnection()){ //disable interrupts
   accelGyroMag.setIntFIFOBufferOverflowEnabled(false);
   // disable fifo_interrupt
   accelGyroMag.resetFIFO();
   }

if(!accelGyroMag.testConnection()){ // try to recover sensor
  accelGyroMag.initialize();
  }
if(accelGyroMag.testConnection()){  // reconfigure sensor for Fifo and interrupts
   accelGyroMag.setFIFOEnabled(true);
   accelGyroMag.setAccelFIFOEnabled(true);
   accelGyroMag.getXGyroFIFOEnabled();
   accelGyroMag.getAccelFIFOEnabled();
   accelGyroMag.setIntFIFOBufferOverflowEnabled(true);
   }
else {
  Serial.println("MPU9150 connection failed");
  Serial.println("locking UP");
  while(true){
     for(uint8_t i=0;i<3;i++){blink(50,100);} // S
     delay(250);
     for(uint8_t i=0;i<3;i++){blink(50,300);} // O
     delay(250);
     for(uint8_t i=0;i<3;i++){blink(50,100);} // S
     delay(500);
    }
  }
}


void setup(){
// other stuff
  attachInterrupt(0,fifo_int,LOW);
  resetSensor();
}

void fifo_int() {
  state_fifo_int = true;
}

static unsigned long timeout =0; // used to detect dead sensor/connection

void loop(){
if(state_fifo_int){ // interrupt has triggered
  state_fifo_int= false; // clear interrupt marker
  fifo_count = accelGyroMag.getFIFOCount();         // why is this called?  is fifo only 1 element deep?
  accelGyroMag.getFIFOBytes(fifo_buffer,8); // fill in fifo bytes
  acc_temp[0] = (((int16_t)fifo_buffer[0]) << 8) | fifo_buffer[1];
  acc_temp[1] = (((int16_t)fifo_buffer[2]) << 8) | fifo_buffer[3];
  acc_temp[2] = (((int16_t)fifo_buffer[4]) << 8) | fifo_buffer[5];
  gyro_x = (((int16_t)fifo_buffer[6]) << 8) | fifo_buffer[7];

  Serial.print((float)acc_temp[0]/16384);
  Serial.print("  ");
  Serial.print((float)acc_temp[1]/16384);
  Serial.print(" ");
  Serial.print((float)acc_temp[2]/16384);
  Serial.print(" ");
  Serial.println(gyro_x);

  blink(0,1); // really quick blink
  timeout = millis(); // time of last interrupt
   }

if(millis()-timeout)>1000) { //last interrupt was over 1 second ago! better reset Sensor!
  blink(100,500);
  resetSensor();

  }

}

try this code

Chuck.

Oh, thanks Chuck. I have tested your code with the fifoOverflow_int and it didnt worked as expected, I got the same problem. The trouble I am facing is that the void loop stops after certain interrupts. I have encountered similiar issues when coding a keypad or a button. For instance, pressing on a interrupt driven button swiftly will affect the interrupt queue , meaning the nC cant handle several interrupts, or the number of interrupt queues are limited. I dont exactly know how the arduino chip/software handles interrupt queues.

Furthermore when I removed the fifo_Overflow_int functionality from the code,the code worked excellently.

I personally think there is a sync problem between the arduino and the sensor itself. I have also read that the Serial library can affect real time systems by adding delay, this is also very common when using UART for debug printing in product software.

Hmm I found the sampling rate for the fifo is 20 Hz in the sensor chip, maybe there is a way to sync the arduino and the sensor.

volkan163:
Oh, thanks Chuck. I have tested your code with the fifoOverflow_int and it didnt worked as expected, I got the same problem. The trouble I am facing is that the void loop stops after certain interrupts. I have encountered similiar issues when coding a keypad or a button. For instance, pressing on a interrupt driven button swiftly will affect the interrupt queue , meaning the nC cant handle several interrupts, or the number of interrupt queues are limited. I dont exactly know how the arduino chip/software handles interrupt queues.

Furthermore when I removed the fifo_Overflow_int functionality from the code,the code worked excellently.

I personally think there is a sync problem between the arduino and the sensor itself. I have also read that the Serial library can affect real time systems by adding delay, this is also very common when using UART for debug printing in product software.

the symptoms you are describing match a 'missed' interrupt. The processing of an interrupt exceed the interval between interrupts.

You receive an interrupt, start processing the interrupt, clear the interrupt status in the sensor, the sensor generates a new interrupt, you complete the current interrupt.

when you complete the current interrupt the Arduino re-enables the interrupt hardware, since the interrupt method of 'FALLING' was specified, the interrupt line must go High before it will trigger the interrupt, but since the sensor has already triggered a new interrupt, the pin never goes high. Hence the Hang.

I added that timeout section at the end of loop() to recover from this situation. did you ever see the slow blink pattern?

chuck.

No chuck your slow blink pattern are not working in this case. After reading the datasheet on the PS manual for the MPU9150 I found out that the INT1 pulse ( INT pin ) is 50uS.

So what I simply did was to declare an integer variable as global and increment it whenever an interrupt occure.

Once the program has looped once, then I checked the incremented variable which was 48!. 48 interrupts.. I think I have to double check it with an oscilloscope.

Additionally I also printed the timeout value in order to see how fast my code looped, and it ended somewhere in 14 ms per loop arbitrary.

I still have to check with an oscilloscope to approve my thesis. Here is the new code. Note that im using the Serial library wich can delay the loop speed, so that has to be taken into account ( I will do a test without it).

But we know that

14ms = 14000uS

and

14000/47 = 291.6666666666666667

The result is 291.66uS for one interrupt pulse from the MPU_9150 chip and if we omit the Serial print lines in the loop I think its near to 50uS , wont be exact though. Do you think im on the rigth way?

I have modified the code a little!

#include "Wire.h"    
#include "I2Cdev.h"
#include "MPU9150.h"
#include "helper_3dmath.h"

#define LED_BUILTIN 13

MPU9150 accelGyroMag; 

volatile boolean state_fifo_int = false;
int x = 0;

void blink(uint16_t offTime, uint16_t onTime){
digitalWrite(LED_BUILTIN,HIGH);
if(onTime) delay(onTime);
digitalWrite(LED_BUILTIN,LOW);
if(offTime) delay(offTime);
}

void start_interrupt(boolean interruptStatus){
  accelGyroMag.setIntFIFOBufferOverflowEnabled(interruptStatus);
}

void resetSensor(){
    // verify connection
    
   Serial.println("Initializing I2C devices...");
    accelGyroMag.initialize();
    // verify connection
    Serial.println(accelGyroMag.testConnection() ? "MPU9150 connection successful" : "MPU9150 connection failed");
  if(accelGyroMag.testConnection()){ //disable interrupts
     accelGyroMag.setIntFIFOBufferOverflowEnabled(false);
     // disable fifo_interrupt
     accelGyroMag.resetFIFO();
     Serial.println("Connection tested successfully, Disabling interrupts");
     }
if(!accelGyroMag.testConnection()){ // try to recover sensor
  accelGyroMag.initialize();
    Serial.println("Initialize if connection test failed");
  }
if(accelGyroMag.testConnection()){  // reconfigure sensor for Fifo and interrupts
   Serial.println("Enable fifo INT");
   accelGyroMag.setFIFOEnabled(true);
   accelGyroMag.setIntFIFOBufferOverflowEnabled(true);
   accelGyroMag.setXGyroFIFOEnabled(true);
   accelGyroMag.setAccelFIFOEnabled(true);
   }
else {
 // Serial.println("MPU9150 connection failed");
  //Serial.println("locking UP");
  while(true){
     for(uint8_t i=0;i<3;i++){blink(50,100);} // S
     delay(250);
     for(uint8_t i=0;i<3;i++){blink(50,300);} // O
     delay(250);
     for(uint8_t i=0;i<3;i++){blink(50,100);} // S
     delay(500);
    }
  }
}

void setup(){
  Wire.begin();    
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
// other stuff
  attachInterrupt(0,fifo_int,RISING);
  resetSensor();
}

void fifo_int() {
  noInterrupts();
  x++;
  state_fifo_int = true;
  
}

static unsigned long timeout = 0; // used to detect dead sensor/connection
uint16_t fifo_count;
uint8_t fifo_buffer[8];
int16_t acc_temp[3];
int16_t gyro_x;

void loop(){

 if(state_fifo_int){
   state_fifo_int = false;
   blink(0,1);
   Serial.println(x);
   accelGyroMag.getFIFOBytes(fifo_buffer,8); // fill in fifo bytes
   accelGyroMag.resetFIFO();
   acc_temp[0] = (((int16_t)fifo_buffer[0]) << 8) | fifo_buffer[1];
   acc_temp[1] = (((int16_t)fifo_buffer[2]) << 8) | fifo_buffer[3];
   acc_temp[2] = (((int16_t)fifo_buffer[4]) << 8) | fifo_buffer[5];
   gyro_x = (((int16_t)fifo_buffer[6]) << 8) | fifo_buffer[7];
   timeout = millis(); // time of last interrupt
   Serial.println(timeout);
   interrupts();
 }
 
 if((millis()-timeout)>1000){ //last interrupt was over 1 second ago! better reset Sensor!
   blink(100,500);
   resetSensor();
  }
}

regards, Volkan