MMA8452Q accelerometer

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

MMA8452Q accelerometer

2,966 Views
bryanbennett
Contributor I

I am using the MMA8452Q Breakout Board from Spark Fun (SparkFun Triple Axis Accelerometer Breakout - MMA8452Q - SEN-12756 - SparkFun Electronics)

I have followed the steps exactly on page 11 of "Motion and Freefall Detection Using the MMA8451, 2, 3Q" (http://cache.freescale.com/files/sensors/doc/app_note/AN4070.pdf), but my MMA8452Q accelerometer continues to indicate motion detection even when it is completely still.

My C code is:

#define MMA8452Q_ADDR  0x3A  //0b 0011 1010 (accelerometer device I2C address (0x1D) plus 0 LSb for R/W bit)

#define INT_SOURCE 0x0C  // system interrupt status register

#define FF_MT_CFG  0x15  // motion configuration register address

#define FF_MT_SRC 0x16   // motion source register

#define FF_MT_THS  0x17  // motion threshold register address

#define FF_MT_COUNT 0x18 // motion debounce counter register address

#define CTRL_REG1  0x2A  // system control 1 register address

#define CTRL_REG4  0x2D  // system control 4 register address

#define CTRL_REG5  0x2E  // system control 5 register address

volatile int FFMT_IntSourceReg_data; // holds data from FF_MT_SRC register in accelerometer MMA8452Q

volatile int IntSourceSystemRegData; // holds data from INT_SOURCE register in accelerometer MMA8452Q

int main (void)

{

  consecutive = 0;

  n = 0;

  configI2C1(400); // configure I2C baud rate for 400 KHz

  write2I2C1(MMA8452Q_ADDR, CTRL_REG1, 0x18); // ODR=100Hz, LNOISE=1, F_READ=0, ACTIVE=0

  write2I2C1(MMA8452Q_ADDR, FF_MT_CFG, 0xD8); // ELE=1, OAE=1, ZEFE=0, YEFE=1, XEFE=1

  write2I2C1(MMA8452Q_ADDR, FF_MT_THS, 0x30); // 3g/0.063g=47.6 (round up to 48), Threshold > 3g

  write2I2C1(MMA8452Q_ADDR, FF_MT_COUNT, 0x0A); // set debounce counter to eliminate false readings for 100Hz sample rate with requirement of 100 ms timer

  write2I2C1(MMA8452Q_ADDR, CTRL_REG4, 0x04); // disable auto SLEEP/WAKE interrupt, enable FF_MT interrupt

  write2I2C1(MMA8452Q_ADDR, CTRL_REG5, 0x04); // FF_MT interrupt output signal assigned to INT1 pin of MMA8452Q

  write2I2C1(MMA8452Q_ADDR, CTRL_REG1, 0x19); // put MMA8452Q in ACTIVE mode

if (TimerCount % 1000 == 0)

   {

    write1I2C1(MMA8452Q_ADDR, INT_SOURCE);

    read1I2C1(MMA8452Q_ADDR, &IntSourceSystemRegData);  

    if ((IntSourceSystemRegData & 0x04)==0x04)

     { 

        n++;

        consecutive = -3;

        readRTCC(); // read real time clock and calendar

        printf("MOTION DETECTION n=%d consecutive=%3d %02d:%02d:%02d\n",n,consecutive,HOUR,MIN,SEC);

        write1I2C1(MMA8452Q_ADDR, FF_MT_SRC);

        read1I2C1(MMA8452Q_ADDR, &FFMT_IntSourceReg_data); // read the FF_MT_SRC register to clear the interrupt

     }

       

   }

   

} // end of main

My "TimerCount" variable just assures that the INT_SOURCE register will be read and checked for an indication of motion every second.

I have actually run the above program with 2 different MMA8452Q accelerometers, and I get the same results with both accelerometers: Every second the accelerometer claims that motion has occurred (i.e., "MOTION DETECTION" is printed) even though the accelerometer is perfectly still. I am only trying to detect when motion occurs in a sleeping subject; I am not interested in the specifics of the motion; however, I also ran a program that looked at the values of the OUT_X_MSB, OUT_Y_MSB, and OUT_Z_MSB registers, and they displayed a constant value of 255 even when no motion was occurring.

Can someone please tell me what I am doing wrong?

Thanks,

Bryan Bennett

Labels (1)
0 Kudos
3 Replies

963 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Bryan,

Your code seems to be absolutely correct. To be sure 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 not able to read correct values from these registers, then please post here screenshots illustrating both I2C write and read transactions (as shown in my example code) as well as your complete schematic.

Regards,

Tomas

PS: If my answer helps to solve your question, please mark it as "Correct". Thank you.

0 Kudos

962 Views
bryanbennett
Contributor I

Tomas

thanks for the quick response.

Here is the complete C code that I am running on my Microchip

PIC24HJ64GP502 microcontroller with the MMA8452Q accelerometer (being held

perfectly level and not moving):

#include "pic24_all.h"

#include "stdio.h"

#include "main.h"

#define PERIOD 40000

#define MMA8452Q_ADDR 0x3A //0b 0011 1010 (accelerometer device I2C

address (0x1D) plus 0 LSb for R/W bit)

#define OUT_X_MSB 0x01 // X-axis output data

#define OUT_X_LSB 0x02 // X-axis output data

#define OUT_Y_MSB 0x03 // Y-axis output data

#define OUT_Y_LSB 0x04 // Y-axis output data

#define OUT_Z_MSB 0x05 // Z-axis output data

#define OUT_Z_LSB 0x06 // Z-axis output data

#define INT_SOURCE 0x0C // system interrupt status register

#define WHO_AM_I 0x0D // MMA8452Q ID register

#define FF_MT_CFG 0x15 // motion configuration register address

#define FF_MT_SRC 0x16 // motion source register

#define FF_MT_THS 0x17 // motion threshold register address

#define FF_MT_COUNT 0x18 // motion debounce counter register address

#define CTRL_REG1 0x2A // system control 1 register address

#define CTRL_REG2 0x2B // system control 2 register address

#define CTRL_REG3 0x2C // system control 3 register address

#define CTRL_REG4 0x2D // system control 4 register address

#define CTRL_REG5 0x2E // system control 5 register address

volatile int FFMT_IntSourceReg_data; // holds data from FF_MT_SRC register

in accelerometer MMA8452Q

volatile int IntSourceSystemRegData; // holds data from INT_SOURCE register

in accelerometer MMA8452Q

volatile int XrawData1, XrawData2, YrawData3, YrawData4, ZrawData5,

ZrawData6;

volatile int TimerCount;

volatile int Xout_12_bit, Yout_12_bit, Zout_12_bit;

int n, Accel_ID,year, month_date, wday_hour, min_sec, HOUR, HRTEN, HRONE,

MIN, MINTEN, MINONE, SEC, SECTEN, SECONE,MTH, MTHTEN, MTHONE, DAY, DAYTEN,

DAYONE, YR, YRTEN, YRONE;

void setRTCC(void) // set real time clock & calendar

{

NVMKEY = 0x55; // unlock write to RTCC

NVMKEY = 0xAA;

RCFGCALbits.RTCWREN = 1; //enable write to RTCC

RCFGCALbits.RTCEN = 0; // disable RTCC

RCFGCALbits.RTCOE = 1; // enable RTCC output to pin #25

PADCFG1bits.RTSECSEL = 1; // seconds clock is selected for RTCC pin #25

RCFGCALbits.RTCPTR = 3; // set RTCC pointer to start

RTCVAL = 0x0015; // set year in BCD

RTCVAL = 0x0528; // set month_date in BCD

RTCVAL = 0x0401; // set wday_hour in BCD

RTCVAL = 0x1100; // set min_sec in BCD

RCFGCALbits.RTCEN = 1; // enable RTCC

RCFGCALbits.RTCWREN = 0; // disable write to RTCC

}

void readRTCC(void) // read real time clock & calendar

{

RCFGCALbits.RTCPTR = 3; // set RTCC pointer to start

year = RTCVAL;

month_date = RTCVAL;

wday_hour = RTCVAL;

min_sec = RTCVAL;

YRTEN = ((year & 0xF0) >> 4) * 10;

YRONE = year & 0x0F;

YR = YRTEN + YRONE;

MTH = (month_date & 0xFF00) >> 8;

MTHTEN = ((MTH & 0xF0) >> 4) * 10;

MTHONE = MTH & 0x0F;

MTH = MTHTEN + MTHONE;

DAY = month_date & 0x00FF;

DAYTEN = ((DAY & 0xF0) >> 4) * 10;

DAYONE = DAY & 0x0F;

DAY = DAYTEN + DAYONE;

HOUR = wday_hour & 0x00FF;

HRTEN = ((HOUR & 0xF0) >> 4) * 10;

HRONE = HOUR & 0x0F;

HOUR = HRTEN + HRONE;

MIN = (min_sec & 0xFF00) >> 8;

MINTEN = ((MIN & 0xF0) >> 4) * 10;

MINONE = MIN & 0x0F;

MIN = MINTEN + MINONE;

SEC = min_sec & 0x00FF;

SECTEN = ((SEC & 0xF0) >> 4) * 10;

SECONE = SEC & 0x0F;

SEC = SECTEN + SECONE;

}

void configTimer1( void )

{

//This code should be written to do the interrupt rate at 1 msec (1 kHz

rate).

T1CON = 0; /* ensure Timer 1 is in reset state */

IFS0bits.T1IF = 0; /* reset Timer 1 interrupt flag */

IPC0bits.T1IP = 4; /* set Timer1 interrupt priority level to 4 */

IEC0bits.T1IE = 1; /* enable Timer 1 interrupt */

PR1 = PERIOD; /* set Timer 1 period register */

T1CONbits.TCKPS1 = 0; /* select Timer1 Input Clock Prescale */

T1CONbits.TCS = 0; /* select internal timer clock */

T1CONbits.TON = 1; /* enable Timer 1 and start the count */

}

void _ISR _T1Interrupt (void) {

TimerCount++; // increment TimerCount each millisecond

_T1IF = 0; // clear T1 interrupt flag

}

int main (void)

{

__builtin_write_OSCCONL(OSCCON | 0x02); // unlock OSCCON register and set

LPOSCEN bit (enable secondary oscillator)

setRTCC();

configTimer1();

configBasic(HELLO_MSG);

TimerCount = 0;

n = 0;

configI2C1(400); // configure I2C baud rate for 400 KHz

write1I2C1(MMA8452Q_ADDR, WHO_AM_I); // read device ID register

read1I2C1(MMA8452Q_ADDR, &Accel_ID);

write2I2C1(MMA8452Q_ADDR, CTRL_REG1, 0x18); // ODR=100Hz, LNOISE=0,

F_READ=0, ACTIVE=0

write2I2C1(MMA8452Q_ADDR, FF_MT_CFG, 0xD8); // ELE=1, OAE=1, ZEFE=0,

YEFE=1, XEFE=1

write2I2C1(MMA8452Q_ADDR, FF_MT_THS, 0x30); // 3g/0.063g=47.6 (round up

to 48), Threshold > 3g

write2I2C1(MMA8452Q_ADDR, FF_MT_COUNT, 0x0A); // set debounce counter to

eliminate false readings for 100Hz sample rate with requirement of 100 ms

timer

write2I2C1(MMA8452Q_ADDR, CTRL_REG4, 0x04); // disable auto SLEEP/WAKE

interrupt, enable FF_MT interrupt

write2I2C1(MMA8452Q_ADDR, CTRL_REG5, 0x04); // FF_MT interrupt output

signal assigned to INT1 pin of MMA8452Q

write2I2C1(MMA8452Q_ADDR, CTRL_REG1, 0x19); // put MMA8452Q in ACTIVE

mode

printf("WHO_AM_I = %#5x\n",Accel_ID);

readRTCC();

printf("The Time is: %02d:%02d:%02d\n",HOUR,MIN,SEC);

printf("The Date Is: %02d/%02d/%02d\n", MTH,DAY,YR);

while(1)

{

if (TimerCount % 1000 == 0)

{

write1I2C1(MMA8452Q_ADDR, OUT_X_MSB);

read1I2C1(MMA8452Q_ADDR, &XrawData1);

write1I2C1(MMA8452Q_ADDR, OUT_X_LSB);

read1I2C1(MMA8452Q_ADDR, &XrawData2);

write1I2C1(MMA8452Q_ADDR, OUT_Y_MSB);

read1I2C1(MMA8452Q_ADDR, &YrawData3);

write1I2C1(MMA8452Q_ADDR, OUT_Y_LSB);

read1I2C1(MMA8452Q_ADDR, &YrawData4);

write1I2C1(MMA8452Q_ADDR, OUT_Z_MSB);

read1I2C1(MMA8452Q_ADDR, &ZrawData5);

write1I2C1(MMA8452Q_ADDR, OUT_Z_LSB);

read1I2C1(MMA8452Q_ADDR, &ZrawData6);

Xout_12_bit = (XrawData1<<8 | XrawData2)>>4;
Yout_12_bit = (YrawData3<<8 | YrawData4)>>4;
Zout_12_bit = (ZrawData5<<8 | ZrawData6)>>4;

printf("Xout_12_bit = %#6x\n", Xout_12_bit);

printf("Yout_12_bit = %#6x\n", Yout_12_bit);

printf("Zout_12_bit = %#6x\n", Zout_12_bit);

write1I2C1(MMA8452Q_ADDR, INT_SOURCE);

read1I2C1(MMA8452Q_ADDR, &IntSourceSystemRegData);

if ((IntSourceSystemRegData & 0x04)==0x04)

{

n++;

readRTCC(); // read real time clock and calendar

printf("MOTION DETECTION n=%d %02d:%02d:%02d\n",n,HOUR,MIN,SEC);

write1I2C1(MMA8452Q_ADDR, FF_MT_SRC);

read1I2C1(MMA8452Q_ADDR, &FFMT_IntSourceReg_data); // read the

FF_MT_SRC register to clear the interrupt

}

}

} // end of while(1)

} // end of main

Here is the screenshot of what my PC displays when I run the above

algorithm (while keeping the MMA8452Q perfectly level and still):

Reset cause: Power-on.

Device ID = 0x00000675 (PIC24HJ64GP502), revision 0x00003003 (A3)

Fast RC Osc with PLL

main.c, built on May 28 2015 at 01:29:52

WHO_AM_I = 0xff

The Time is: 01:30:00

The Date Is: 05/28/15

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

MOTION DETECTION n=1, time is 01:30:01

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

MOTION DETECTION n=2, time is 01:30:02

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

MOTION DETECTION n=3, time is 01:30:03

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

MOTION DETECTION n=4, time is 01:30:04

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

MOTION DETECTION n=5, time is 01:30:05

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

MOTION DETECTION n=6, time is 01:30:06

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

MOTION DETECTION n=7, time is 01:30:07

Xout_12_bit = 0xffff

Yout_12_bit = 0xffff

Zout_12_bit = 0xffff

As you can see, the WHO_AM_I register reads 0xff and not 0x2a, and the 12

bit acceleration registers all read 0xffff (indicating -0.002g). The I1

interrupt pin read 3.3 volts constantly. My PIC microcontroller operates at

3.3 volts just as does the MMA8452Q accelerometer.

Any advice that you could offer would be greatly appreciated.

Thanks,

Bryan Bennett

On Wed, May 27, 2015 at 5:18 AM, TomasVaverka <admin@community.freescale.com

0 Kudos

962 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Bryan,

While looking at the definition of the write1I2C1() function you are using to read MMA8452Q registers, I realized that the problem most likely comes from a stop condition, that is generated instead of a repeated start condition, between the second (register address) and third byte (0x3B if SA0 = 1). So try to remove the stopI2C1() routine from the definition of the write1I2C1() function and also make sure that the third byte is really 0x3B ((0x1D << 1 ) | 0x01) and not 0x3A.  

If the problem still persists, I will need a screenshot illustrating the complete read transaction to see what is going on on the bus.

Regards,

Tomas

0 Kudos