Electronic – Weird problem with Intel Edison and IMU MPU-9150

accelerometercimuintelsensor

So I am trying to get measurements from the MPU-9150 sensor from Invensense using the Intel Edison. I am able to communicate with the sensor and the values seem sensible.

But after a specific number of cycles, I measure only a zero from all data registers. This error is repeatable: When I try to read the Accelerometer and Gyro data(6 data registers), the data stream stops exactly at 84 cycles. If I try to read jus the Accelerometer values, it stops at double the no. of cycles i.e. 168. I sense some data is overflowing, but couldn't figure out yet.

Looking for your reply and Thanks!

Cheers,

Frederic

Code:

MPU9150.h

//Self Test registers R/W  
#define SELF_TEST_X  0x0D  
#define SELF_TEST_Y  0x0E  
#define SELF_TEST_Z  0x0F  
#define SELF_TEST_A  0x0A  

//Configuration Registers  
#define SMPRT_DIV    0x19 //Sample Rate Divider  
#define CONFIG       0x1A //FSYNC & DLPF config  
#define GYRO_CONFIG  0x1B //Self-Test & Scale select  
#define ACCEL_CONFIG 0x1C //Self-Test & Scale select  

//Interrupt Registers  
#define INT_ENABLE   0x38  
#define INT_STATUS   0x3A  

//Accelerometer Measurement Registers  
#define ACCEL_XOUT_H 0x3B  
#define ACCEL_XOUT_L 0x3C  
#define ACCEL_YOUT_H 0x3D  
#define ACCEL_YOUT_L 0x3E  
#define ACCEL_ZOUT_H 0x3F  
#define ACCEL_ZOUT_L 0x40  

//Temperature Measurement Registers  
//Temperature in degrees C = (TEMP_OUT Register Value as a signed quantity)/340 + 35  
#define TEMP_OUT_H   0x41  
#define TEMP_OUT_L   0x42  

//Gyroscope Measurement Registers  
#define GYRO_XOUT_H  0x43  
#define GYRO_XOUT_L  0x44  
#define GYRO_YOUT_H  0x45  
#define GYRO_YOUT_L  0x46  
#define GYRO_ZOUT_H  0x47  
#define GYRO_ZOUT_L  0x48  

//Power Management Registers  
#define PWR_MGMT_1   0x6B  
#define PWR_MGMT_2   0x6C  

//Device i.d. Register  
#define WHO_AM_I     0x75  

/* 
R1 - 0x69 
R2 - 0x68 
*/  
#define MPU_ADDR     0x68  

//Reset the Registers and Power  
#define PWR_RESET    0x80  
#define DEVICE_ON    0x00  

//Accelerometer Scale  
#define ACCEL_2G     0x00  
#define ACCEL_4G     0x08  
#define ACCEL_8G     0x10  
#define ACCEL_16G    0x18  

//Gyroscope Scale  
#define GYRO_250     0x00  
#define GYRO_500     0x08  
#define GYRO_1000    0x10  
#define GYRO_2000    0x18  

#define SAMPLE_RATE  0x00  

#define DLPF_CFG     0x01  

MPU9150.c

#include <stdio.h>  
#include <stdlib.h>  
#include <signal.h>  
#include "mraa.h"  
#include "MPU9150.h"  

void MPU9150_I2C_Init(void);  
void MPU9150_I2C_Config(void);  
void MPU9150_I2C_Write(uint8_t address, uint8_t value);  
void MPU9150_I2C_Read(uint8_t address, uint8_t *value);  
int16_t MPU9150_Get_Measurement(uint8_t addrL, uint8_t addrH);  
void sig_handler(int signum);  

sig_atomic_t volatile isrunning = 1;  

//Acceleometer Measurement Storage Variables  
int16_t Accel_X = 0;  
int16_t Accel_Y = 0;  
int16_t Accel_Z = 0;  

//Gyroscope Measurement Storage Variables  
int16_t Gyro_X = 0;  
int16_t Gyro_Y = 0;  
int16_t Gyro_Z = 0;  

//Temperature Measurement Storage Variable  
float Temperature = 0;  

//Variable to Store LOW and HIGH Register values  
uint8_t Measurement_L = 0;  
uint8_t Measurement_H = 0;  

int main(int argc, char **argv)  
{  
    printf("--------------------------------------------------\n");  
    printf("------------------eGlove Project------------------\n");  
    printf("--------------------------------------------------\n");  
    sleep(1); //1s delay  

    signal(SIGINT, &sig_handler);  
    usleep(1000); //1ms delay  

    MPU9150_I2C_Init();  
    sleep(1); //1s delay  

    MPU9150_I2C_Config();      
    sleep(1); //1s delay  

    while(isrunning)  
    {  
        //Get Accelerometer Measurements  
        Accel_X = MPU9150_Get_Measurement(ACCEL_XOUT_L, ACCEL_XOUT_H);  
    Accel_Y = MPU9150_Get_Measurement(ACCEL_YOUT_L, ACCEL_YOUT_H);  
    Accel_Z = MPU9150_Get_Measurement(ACCEL_ZOUT_L, ACCEL_ZOUT_H);  

        //Get Gyroscope Measurements  
    Gyro_X = MPU9150_Get_Measurement(GYRO_XOUT_L, GYRO_XOUT_H);  
    Gyro_Y = MPU9150_Get_Measurement(GYRO_YOUT_L, GYRO_YOUT_H);  
    Gyro_Z = MPU9150_Get_Measurement(GYRO_ZOUT_L, GYRO_ZOUT_H);  

        //Print Accelerometer Values  
        printf("Accelerometer:\n X:%d\n Y:%d\n Z:%d\n ", Accel_X, Accel_Y, Accel_Z);  

        //Print Gyroscope Values  
    printf("Gyroscope:\n X:%d\n Y:%d\n Z:%d\n ", Gyro_X, Gyro_Y,Gyro_Z);  

        //Sample Readings every second  
        sleep(1); //1s delay  
    }  
    return MRAA_SUCCESS;  
}  

void MPU9150_I2C_Init(void)  
{  
    mraa_init();  
    mraa_i2c_context mpu9150_i2c;  
    mpu9150_i2c = mraa_i2c_init(1);  

  if (mpu9150_i2c == NULL)   
    {  
        printf("MPU9150 I2C initialization failed, exit...\n");  
        exit(1);  
    }  

    printf("MPU9150 I2C initialized successfully\n");  

    mraa_i2c_address(mpu9150_i2c, MPU_ADDR);  
    printf("MPU9150 I2C Address set to 0x%x\n", MPU_ADDR);  
}  

void MPU9150_I2C_Config(void)  
{  
    mraa_i2c_context mpu9150_i2c;  
    mpu9150_i2c = mraa_i2c_init(1);  

    //Reset all the Registers  
  mraa_i2c_address(mpu9150_i2c, MPU_ADDR);  
    MPU9150_I2C_Write(PWR_MGMT_1, PWR_RESET);  
    printf("MPU9150 Reset\n");  
    sleep(1); //1s delay  

    mraa_i2c_address(mpu9150_i2c, MPU_ADDR);  
     MPU9150_I2C_Write(PWR_MGMT_1, DEVICE_ON);  
    printf("MPU9150 Switched ON\n");  
    sleep(1); //1s delay  

    mraa_i2c_address(mpu9150_i2c, MPU_ADDR);  
  uint8_t data = mraa_i2c_read_byte_data(mpu9150_i2c, WHO_AM_I);  
  printf("Who am I: 0x%x\n", data);  
    sleep(1); //1s delay  

     MPU9150_I2C_Write(SMPRT_DIV, SAMPLE_RATE);  

     MPU9150_I2C_Write(CONFIG, DLPF_CFG);  

     //Set the Gyroscope Scale to 250°/s  
     MPU9150_I2C_Write(GYRO_CONFIG, GYRO_500);  

    //Set the Accelerometer Scale to 2G  
     MPU9150_I2C_Write(ACCEL_CONFIG, ACCEL_2G);  

    printf("Initialization Complete: All Systems are GO!!!\n");  
}  

void MPU9150_I2C_Write(uint8_t address, uint8_t value)  
{  
    mraa_i2c_context mpu9150_i2c;  
    mpu9150_i2c = mraa_i2c_init(1);  

    //Set MPU Device Address  
    mraa_i2c_address(mpu9150_i2c, MPU_ADDR);  

    //Write Command and Data  
    mraa_i2c_write_byte_data(mpu9150_i2c, value, address);  
}  

void MPU9150_I2C_Read(uint8_t address, uint8_t *value)  
{  
    mraa_i2c_context mpu9150_i2c;  
    mpu9150_i2c = mraa_i2c_init(1);  

    //Set ALS Device Address  
    mraa_i2c_address(mpu9150_i2c, MPU_ADDR);  

    //Write Command and Read Data  
    *value = mraa_i2c_read_byte_data(mpu9150_i2c, address);  
}  

int16_t MPU9150_Get_Measurement(uint8_t addrL, uint8_t addrH)  
{      
    //Read & Store the Lower Byte  
    MPU9150_I2C_Read(addrL, &Measurement_L);  

    //Read & Store the Higher Byte  
    MPU9150_I2C_Read(addrH, &Measurement_H);  

  return (int16_t)((Measurement_H << 8) + Measurement_L);  
}  

//Signal Handler  
void sig_handler(int signum)  
{  
    if(signum == SIGINT)  
    {  
        isrunning = 0;  
    }  
}  

Console Screenshot:
enter image description here

Reference:

MPU-9150 Register Map: http://43zrtwysvxb2gf29r5o0athu.wpengine.netdna-cdn.com/wp-content/uploads/2015/02/MPU-9150-Register-Map.pdf

Best Answer

I'm unfamiliar with the Intel Edison, but this sounds like some internal buffer overflow in the MPU-9150. It looks like the MPU-9150 has an internal FIFO buffer between the I2C interface and the actual motion engine. When you do a printf (presumably through some JTAG based debugging interface emulating a serial port) is probably much slower than the time it takes to read out a sensor value. So what is likely happening is that you are removing sensor values using I2C and printf much slower than the motion sensor is writing values. At some point the buffer overflows because of this, and puts the MPU into some error state.

Whenever you design a real-time system, you must keep in mind that debugging printf may be thousands of times slower than everything else which is happening in your main loop. One simple way to see if this is the problem is to only print out 1 out of every 1000 sample values (read all samples through I2C, but only print out one in 1000). If this fixes it, your problem is indeed in the debug printouts and not anything specific to the I2C driver.