Problema extraño con Intel Edison e IMU MPU-9150

Entonces, estoy tratando de obtener mediciones del sensor MPU-9150 de Invensense usando Intel Edison. Puedo comunicarme con el sensor y los valores parecen razonables.

Pero después de un número específico de ciclos, mido solo un cero de todos los registros de datos. Este error es repetible: cuando trato de leer los datos del acelerómetro y el giroscopio (6 registros de datos), el flujo de datos se detiene exactamente en 84 ciclos. Si trato de leer solo los valores del acelerómetro, se detiene en el doble del no. de ciclos, es decir, 168. Siento que algunos datos se están desbordando, pero aún no pude averiguarlo.

Espero su respuesta y gracias!

Salud,

Federico

Código:

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;  
    }  
}  

Captura de pantalla de la consola:ingrese la descripción de la imagen aquí

Referencia:

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

Respuestas (1)

No estoy familiarizado con Intel Edison, pero esto suena como un desbordamiento de búfer interno en el MPU-9150. Parece que el MPU-9150 tiene un búfer FIFO interno entre la interfaz I2C y el motor de movimiento real. Cuando realiza un printf (presumiblemente a través de alguna interfaz de depuración basada en JTAG que emula un puerto serie) es probablemente mucho más lento que el tiempo que lleva leer el valor de un sensor. Entonces, lo que probablemente sucede es que está eliminando los valores del sensor usando I2C e printf mucho más lento de lo que el sensor de movimiento está escribiendo valores. En algún momento, el búfer se desborda debido a esto y pone la MPU en algún estado de error.

Siempre que diseñe un sistema en tiempo real, debe tener en cuenta que la depuración de printf puede ser miles de veces más lenta que todo lo demás que sucede en su ciclo principal. Una forma simple de ver si este es el problema es imprimir solo 1 de cada 1000 valores de muestra (lea todas las muestras a través de I2C, pero solo imprima una de cada 1000). Si esto lo soluciona, su problema está en las impresiones de depuración y no es algo específico del controlador I2C.

Hola Zuofu, finalmente descubrí el problema. El bus I2C se declaró como un puntero aleatorio que produjo una falla de segmentación cuando se convirtió en NULL. ¡Gracias!