MMA8452Q Accelerometer Motion Detection Issue

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MMA8452Q Accelerometer Motion Detection Issue

1,980 Views
pallaviingole
Contributor I

Hi,

I am using MMA8452Q Accelerometer with imx6ULL for my project and programming it using linux platform.

I am trying to get the motion detection of accelerometer, for achieving this I have done below register settings in user space:

Step 1: Put the device into Standby Mode: Register 0x2A CTRL_REG1
IIC_RegWrite(0x2A, 0x18); //Set the device in 100 Hz ODR, Standby
Step 2: Set Configuration Register for Motion Detection by setting the “OR” condition OAE = 1, enabling
X, Y, and the latch
IIC_RegWrite(0x15, 0xD8)
Step 3: Threshold Setting Value for the Motion detection of > 3g
Note: The step count is 0.063g/ count
• 3g/0.063g = 47.6; //Round up to 48
IIC_RegWrite(0x17, 0x30)
Step 4: Set the debounce counter to eliminate false readings for 100 Hz sample rate with a requirement
of 100 ms timer.
Note: 100 ms/10 ms (steps) = 10 counts
IIC_RegWrite(0x18, 0x0A);
Step 7: Put the device in Active Mode

IIC_RegWrite(0x2A, 0x19);

and then I am continuously reading the Register 0x16 (FF_MT_SRC) and ( INT_SOURCE) for detecting the motion. I am trying to check 7th bit of this register which is EA bit. This bit should set when there is motion event occurs.

But my test results are as below:

Getting Read value from register as 0x1 - when the accelerometer is stable and not moving.

and Read value from register as 0x0 - when any little movement in accelerometer is there.

But this is not the expected output as my EA bit is never getting set and the value I am reading from FF_MT_SRC register is 0x1 or 0x0, no value change except these two.

 And read value of  INT_SOURCE register is 0x0 always.

Please let me know, what changes needs to be done to get correct value

Thanks in advance.

Regards,

Pallavi

Labels (1)
0 Kudos
6 Replies

1,136 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Pallavi,

First off, I would recommend to check if your I2C communication is running properly Could you please try to read the WHO_AM_I register (0x0D) and all output data registers (0x01 – 0x06) while the device is perfectly level and not moving? The MMA8452Q ID is 0x2A, the X/Y axes should read ~0g and the Z axis should read ~1g, which is +1024 at ±2g range.

 

If you are reading correct data, then you can focus on the motion detection function itself. Seems like you are using the settings from AN4070. The threshold value of 3g might be high, try to decrease it to 1.26g (0x14) for example.

 

If you read first the FF_MT_SRC register and the INT_SOURCE register after it, then it is normal that the INT_SOURCE register is 0x00 as the SRC_FF_MT bit is cleared by reading the FF_MT_SRC register.

Have you tried using an interrupt instead of polling the INT_SOURCE (FF_MT_SRC) register?  Here is my example code I used for the FXLS8471Q.

Best regards,

Tomas

0 Kudos

1,136 Views
pallaviingole
Contributor I

Hi Tomas,

I have also referred a sample shared by you. and updated my code.. still the output is not as expected.

the code snippet is as below:

typedef enum EAccReg{
    eMMA8451_STATUS = 0x00,
    eMMA8451_OUT_X_MSB,
    eMMA8451_OUT_X_LSB,
    eMMA8451_OUT_Y_MSB,
    eMMA8451_OUT_Y_LSB,
    eMMA8451_OUT_Z_MSB,
    eMMA8451_OUT_Z_LSB,

    eMMA8451_F_SETUP = 0x09,
    eMMA8451_TRIG_CFG,
    eMMA8451_SYSMOD,
    eMMA8451_INT_SOURCE,
    eMMA8451_WHO_AM_I,
    eMMA8451_XYZ_DATA_CFG,
    eMMA8451_HP_FILTER_CUTOFF,

    eMMA8451_PL_STATUS,
    eMMA8451_PL_CFG,
    eMMA8451_PL_COUNT,
    eMMA8451_PL_BF_ZCOMP,
    eMMA8451_P_L_THS_REG,

    eMMA8451_FF_MT_CFG,
    eMMA8451_FF_MT_SRC,
    eMMA8451_FF_MT_THS,
    eMMA8451_FF_MT_COUNT,

    eMMA8451_TRANSIENT_CFG = 0x1D,
    eMMA8451_TRANSIENT_SRC,
    eMMA8451_TRANSIENT_THS,
    eMMA8451_TRANSIENT_COUNT,

    eMMA8451_PULSE_CFG,
    eMMA8451_PULSE_SRC,
    eMMA8451_PULSE_THSX,
    eMMA8451_PULSE_THSY,
    eMMA8451_PULSE_THSZ,
    eMMA8451_PULSE_TMLT,
    eMMA8451_PULSE_LTCY,
    eMMA8451_PULSE_WIND,

    eMMA8451_ASLP_COUNT,
    eMMA8451_CTRL_REG1,
    eMMA8451_CTRL_REG2,
    eMMA8451_CTRL_REG3,
    eMMA8451_CTRL_REG4,
    eMMA8451_CTRL_REG5,

    eMMA8451_OFF_X,
    eMMA8451_OFF_Y,
    eMMA8451_OFF_Z,

    eMMA8451_REG_END,
}TEAccReg;

void test()

{

        unsigned char uiCTRL_REG1   = 0;
        unsigned char ucBuff = 0x18;

        /* Open I2c file i2c-0 */
        ML_ACC_giI2cFd = I2COpen(I2C_DEV_1);
        if(ML_ACC_giI2cFd < 0)
        {
            printf("Unable to open i2c file\n");
        }

        if(ioctl(ML_ACC_giI2cFd,I2C_SLAVE_FORCE, MMA8452_I2C_ADDRESS) < 0)
        {
            printf("\nioctl error\n");
        }
        else
        {
            printf(" ioctl success\n");
        }

        /* Put the device into Standby Mode */
        I2CWriteRegisterVal(ML_ACC_giI2cFd,eMMA8451_CTRL_REG1,ucBuff,2,
                            MMA8452_I2C_ADDRESS);

        ucBuff = 0xD8;
        /* Set Configuration Register for Motion Detection by setting
         * the “OR” condition OAE = 1, enabling X, Y, and the latch
        */
        I2CWriteRegisterVal(ML_ACC_giI2cFd,eMMA8451_FF_MT_CFG,ucBuff,2,
                            MMA8452_I2C_ADDRESS);
        ucBuff = 0x85;
        // Set threshold to 312.5mg (5 x 62.5mg )
        I2CWriteRegisterVal(ML_ACC_giI2cFd,eMMA8451_FF_MT_THS,ucBuff,2,MMA8452_I2C_ADDRESS);

        ucBuff = 0x02;
        // Latch enabled, motion detection enabled for X and Y axis
        I2CWriteRegisterVal(ML_ACC_giI2cFd,eMMA8451_FF_MT_COUNT,ucBuff,2,MMA8452_I2C_ADDRESS);

        ucBuff = 0x04;
        /* Enable Motion/Freefall Interrupt Function in the System  */
        I2CWriteRegisterVal(ML_ACC_giI2cFd,eMMA8451_CTRL_REG4,ucBuff,2,MMA8452_I2C_ADDRESS);
       ucBuff = 0x04;

        I2CWriteRegisterVal(ML_ACC_giI2cFd,eMMA8451_CTRL_REG5,ucBuff,2,
                            MMA8452_I2C_ADDRESS);
        /* active mode      */
        uiCTRL_REG1 = 0x29;
        I2CWriteRegisterVal(ML_ACC_giI2cFd,eMMA8451_CTRL_REG1,uiCTRL_REG1,1,
                            MMA8452_I2C_ADDRESS);

while(1)

{


        I2CReadRegisterVal(ML_ACC_giI2cFd,eMMA8451_INT_SOURCE,&uiIntSourceSystem,1,
                           MMA8452_I2C_ADDRESS);
        /* Set up Case statement here to service all of the possible interrupts */
      

            /*Perform an Action since Motion Flag has been set
             * Read the Motion/Freefall Function to clear the interrupt
            */
      

            printf("eMMA8451_INT_SOURCE = 0x%x\n",uiIntSourceSystem);

            I2CReadRegisterVal(ML_ACC_giI2cFd,eMMA8451_FF_MT_SRC,&uiMotionStatus,1,
                               MMA8452_I2C_ADDRESS);
            if(isSet(uiMotionStatus,7) == 1)
            {
                printf("PlayAlarm\n");
            }
         printf("uiMotionStatus_ofl = 0x%x\n",uiMotionStatus);

}

}

The output of abov code as below:
uiMotionStatus_ofl = 0x89
eMMA8451_INT_SOURCE = 0x4
PlayAlarm
uiMotionStatus_ofl = 0x89
eMMA8451_INT_SOURCE = 0x4
PlayAlarm
uiMotionStatus_ofl = 0x89
eMMA8451_INT_SOURCE = 0x4
PlayAlarm
uiMotionStatus_ofl = 0x88
eMMA8451_INT_SOURCE = 0x4
PlayAlarm
uiMotionStatus_ofl = 0x89
eMMA8451_INT_SOURCE = 0x4
PlayAlarm
uiMotionStatus_ofl = 0x89
eMMA8451_INT_SOURCE = 0x4
PlayAlarm
uiMotionStatus_ofl = 0x88
eMMA8451_INT_SOURCE = 0x4

Here it is detecting the movement, but I am still confused in output I am getting.. why am I getting the Play alarm in every read?

As per my understanding I should get it after device movement. Please correct me If I am wrong.

Best Regards,

Pallavi Ingole

0 Kudos

1,136 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Pallavi,

What is the orientation of your board? Since the accelerometer also measures the projection of the gravity vector on sensing axes, it is possible that one of the enabled axes (X or Y) is tilted, so exceeding the threshold (312.5mg) and triggering the interrupt permanently. 

That is also why we recommend using the embedded transient detection function that triggers an interrupt when any of the enabled axes has exceeded a set acceleration threshold disregarding the static acceleration (gravity).

Best regards,

Tomas

0 Kudos

1,136 Views
pallaviingole
Contributor I

Hi Tomas,

Thank you for your response.

Your observation is correct. one of the axis is tilted.

Can you provide a sample for transient detection? Or increasing threshold will work?

How shall I decide the value of threshold?

Best Regards,

Pallavi Ingole

0 Kudos

1,136 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Pallavi,

If an accelerometer is tilted, it can experience acceleration in the range of +1g to -1g, so increasing the threshold value above 1g should help. If your application requires lower threshold (“more sensitivity”), then I would recommend using the transient detection function. For more information, have a look at AN4071 or this example code.

Best regards,

Tomas

0 Kudos

1,136 Views
pallaviingole
Contributor I

Hi  Tomas,

I have performed the I2C communication test as per suggestion given by you. Please find the below snippet and output of it

#define MMA8452_I2C_ADDRESS   0x1D  //!< MMA8452 Address
#define WHO_AM_I_REG_ADDR 0x0D     //!< MMA8452 WHO AM I Register Address
#define WHO_AM_I_REG_VAL 0x2A        //!< MMA8452 WHO AM I Register Value
#define I2C_SLAVE_ADDR_ACC 0x1D        //!< MMA8452 I2C Slave Address

void AccelerometerTest(void)
{
    int iI2cFd = -1;
    unsigned char ucRegVal = 0;
    unsigned char usXYZraw[6] = {0} ;
    unsigned char uiCTRL_REG1 = 0;

    unsigned short uiX_Axis = 0xFFFF,uiY_Axis = 0xFFFF,uiZ_Axis = 0xFFFF;
    float Xout_g = 0.0f, Yout_g = 0.0f, Zout_g = 0.0f;

   

    iI2cFd = I2COpen(I2C_DEV_1);
    if(iI2cFd < PASS)
    {
        I2CClose(iI2cFd);
        ires = FAIL;
    }

    /// Read the WHO_AM_I register of MMA8452q
    while(1)
    {
        I2CReadRegisterVal(iI2cFd, WHO_AM_I_REG_ADDR, &ucRegVal,1, I2C_SLAVE_ADDR_ACC);
        if(ucRegVal != WHO_AM_I_REG_VAL)
        {
            printf("Accelerometer Test Failed\n");

            printf("ucRegVal_test_value = 0x%x\n",ucRegVal); 
            I2CClose(iI2cFd);
            ires = FAIL;
        }
        else
        {
          printf("accelerometer test Passed\n");
        }
        printf("ucRegVal_test_value = 0x%x\n",ucRegVal);
        usleep(50000);

        I2CReadRegisterVal(iI2cFd,eMMA8451_OUT_X_MSB,&usXYZraw[0],6,
                MMA8452_I2C_ADDRESS);

        printf("\nusXYZraw[0]_XMSB = %d\n", usXYZraw[0]);
        printf("usXYZraw[1]_XLSB = %d\n", usXYZraw[1]);
        printf("usXYZraw[2]_YMSB = %d\n", usXYZraw[2]);
        printf("usXYZraw[2]_YLSB = %d\n", usXYZraw[3]);
        printf("usXYZraw[2]_ZMSB = %d\n", usXYZraw[4]);
        printf("usXYZraw[2]_ZLSB = %d\n", usXYZraw[5]);


        // 12-bit accelerometer data

        uiX_Axis = ((short) (usXYZraw[0]<<8 | usXYZraw[1])) >> 4;             // Compute 12-bit X-axis acceleration output value
        printf("\nuiX_Axis = 0x%x\n", uiX_Axis);
        uiY_Axis = ((short) (usXYZraw[2]<<8 | usXYZraw[3])) >> 4;             // Compute 12-bit Y-axis acceleration output value
        printf("uiY_Axis = 0x%x\n", uiY_Axis);
        uiZ_Axis = ((short) (usXYZraw[4]<<8 | usXYZraw[5])) >> 4;             // Compute 12-bit Z-axis acceleration output value
        printf("uiZ_Axis = 0x%x\n", uiZ_Axis);

        // Accelerometer data converted to g's

        Xout_g = ((float) uiX_Axis) / SENSITIVITY_2G;              // Compute X-axis output value in g's
        printf("\nXout_g = %f\n", Xout_g);
        Yout_g = ((float) uiY_Axis) / SENSITIVITY_2G;              // Compute Y-axis output value in g's
        printf("Yout_g = %f\n", Yout_g);
        Zout_g = ((float) uiZ_Axis) / SENSITIVITY_2G;              // Compute Z-axis output value in g's
        printf("Zout_g = %f\n", Zout_g);
    }

}

Output of above code :

accelerometer test Passed

ucRegVal_test_value = 0x2a

usXYZraw[0]_XMSB = 81
usXYZraw[1]_XLSB = 212
usXYZraw[2]_YMSB = 145
usXYZraw[2]_YLSB = 252
usXYZraw[2]_ZMSB = 217
usXYZraw[2]_ZLSB = 124

uiX_Axis = 0x51d
uiY_Axis = 0xf91f
uiZ_Axis = 0xfd97

Xout_g = 1.278320
Yout_g = 62.280273
Zout_g = 63.397461
accelerometer test Passed

ucRegVal_test_value = 0x2a

usXYZraw[0]_XMSB = 81
usXYZraw[1]_XLSB = 212
usXYZraw[2]_YMSB = 145
usXYZraw[2]_YLSB = 252
usXYZraw[2]_ZMSB = 217
usXYZraw[2]_ZLSB = 124

uiX_Axis = 0x51d
uiY_Axis = 0xf91f
uiZ_Axis = 0xfd97

Xout_g = 1.278320
Yout_g = 62.280273
Zout_g = 63.397461
accelerometer test Passed

ucRegVal_test_value = 0x2a

usXYZraw[0]_XMSB = 81
usXYZraw[1]_XLSB = 212
usXYZraw[2]_YMSB = 145
usXYZraw[2]_YLSB = 252
usXYZraw[2]_ZMSB = 217
usXYZraw[2]_ZLSB = 124

uiX_Axis = 0x51d
uiY_Axis = 0xf91f
uiZ_Axis = 0xfd97

Xout_g = 1.278320
Yout_g = 62.280273
Zout_g = 63.397461
accelerometer test Passed

ucRegVal_test_value = 0x2a

Output  seems to be correct. Please confirm.

Best Regards,

Pallavi

0 Kudos