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 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 IntSourceSystemRegData; // holds data from INT_SOURCE register in accelerometer MMA8452Q
int main (void)
{
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
{
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
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.
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
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