MMA8452 interrupt stays high forever

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

MMA8452 interrupt stays high forever

4,707 Views
sreejithchandra
Contributor I

Hi,

I'm using the MMA8452Q for one of my projects and it stays at high at the pin2 (Arduino Uno) (int0?) always. Following are the configurations that we have for the chip. Please note that only one interrupt which is INT_TRANS is enabled. We read the INT_SOURCE register and we can see the corresponding interrupt bit is set. In order to clear the interrupt we are reading the TRANSIENT_SRC register. 

Can you please tell us what is wrong with the our code? Have you ever seen any similar issue with the interrupts on this chips?

Thanks a lot in advance. Would really appreciate a swift response.

Sree

// The SparkFun breakout board defaults to 1, set to 0 if SA0 jumper on the bottom of the board is set

#define MMA8452_ADDRESS 0x1D  // 0x1D if SA0 is high, 0x1C if low

//Define a few of the registers that we will be accessing on the MMA8452

#define OUT_X_MSB 0x01

#define XYZ_DATA_CFG  0x0E

#define WHO_AM_I   0x0D

// Control registers

#define CTRL_REG1  0x2A

#define CTRL_REG2  0x2B

#define CTRL_REG3  0x2C

#define CTRL_REG4  0x2D

#define CTRL_REG5  0x2E

#define ASLP_COUNT  0x29

// Iniitial values of Control Registers

#define ASLP_12_5_HZ  0x40

#define ODR_50_HZ  0x20

#define LNOISE_DEFAULT  0x00

#define F_READ_DEFAULT  0x00

#define SLPE  0x04 

#define SMODS_LOW_POW  0x18

#define MODS_NORMAL_POW  0x00

#define ST_DEFAULT  0x00

#define RST_DEFAULT  0x00

#define WAKE_FF_MT  0x08

#define WAKE_TRANS  0x40 

#define IPOL_DEFAULT 0x00

#define PP_OD_DEFAULT 0x00

#define INT_EN_FF_MT  0x04

#define INT_EN_TRANS  0x20

#define INT_EN_ASLP  0x80

#define INT_CFG_FF_MT  0x04

#define INT_CFG_TRANS  0x20

#define ASLP_COUNT_50_HZ_960_MS  0x03

 

#define ELE  0x80

#define OAE_MOTION  0x40

#define XYZ_EFE 0x18

#define DBCNTM_MOTION  0x00

#define THS_0_2_G  0x0B

#define FF_MT_DEBOUNCE_50_HZ_20_MS  0x0A

#define ELE  0x10

#define XYZ_EFE 0x06

#define HPF_BYP 0x00

#define DBCNTM_TRANS  0x00

#define TRANS_THS_0_5_G  0x05

#define TRANS_DEBOUNCE_50_HZ_20_MS  0x03

//The SRC registers for clearing and reading status of interrupts

#define SYSMOD 0x0B

#define TRANSIENT_SRC 0x1E    

#define FF_MT_SRC 0x16 

// Motion Detection registers

#define FF_MT_CFG  0x15

#define FF_MT_SRC  0x16

#define FF_MT_THS  0x17

#define FF_MT_COUNT  0x18

//Transient registers

#define TRANSIENT_CFG 0x1D

#define TRANSIENT_THS 0x1F

#define TRANSIENT_COUNT 0x20

#define INT_SOURCE  0x0C

void setup()

{

 

  /* ACCELEROMETER setup */

  pinMode(11,OUTPUT);

  pinMode(10,OUTPUT);

  pinMode(9,OUTPUT);

  pinMode(3,OUTPUT);

  pinMode(2,OUTPUT); 

 

  Wire.begin(); //Join the bus as a master

  initMMA8452(); //Test and intialize the MMA8452 

 

  Serial.println("Attaching the interrupt lines");

  attachInterrupt(0, int0_bh, CHANGE);

  attachInterrupt(1, int1_bh, CHANGE);

  Serial.println("Attaching interrupt lines was successful!!!");

}

void initMMA8452()

{

  byte val = readRegister(WHO_AM_I);  // Read WHO_AM_I register

  if (val == 0x2A) // WHO_AM_I should always be 0x2A

  { 

    Serial.println("M is online...");

  }

  else

  {

    Serial.print("Could not connect to MMA8452Q: 0x");

    Serial.println(val, HEX);

    while(1) ; // Loop forever if communication doesn't happen

  }

  MMA8452Standby();  // Must be in standby to change registers

  // Initialize GSCALE

  val = GSCALE;

  if(val > 8) val = 8; //Easy error check

  val >>= 2; // Neat trick, see page 22. 00 = 2G, 01 = 4A, 10 = 8G

  writeRegister(XYZ_DATA_CFG, val);

  val = (ASLP_12_5_HZ | ODR_50_HZ | LNOISE_DEFAULT | F_READ_DEFAULT);

  writeRegister(CTRL_REG1, val);

 

  val = (ST_DEFAULT | RST_DEFAULT | SMODS_LOW_POW | SLPE | MODS_NORMAL_POW);

  writeRegister(CTRL_REG2, val);

  val = (WAKE_TRANS | 0x02 | PP_OD_DEFAULT);

  writeRegister(CTRL_REG3, val);

 

  val = 0;

  writeRegister(CTRL_REG5, val); 

 

  val = ASLP_COUNT_50_HZ_960_MS;

  writeRegister(ASLP_COUNT, val);

  val = (ELE | XYZ_EFE | HPF_BYP);

  writeRegister(TRANSIENT_CFG, val);

  val = (DBCNTM_TRANS | TRANS_THS_0_5_G);

  writeRegister(TRANSIENT_THS, val);

  val = TRANS_DEBOUNCE_50_HZ_20_MS;

  writeRegister(TRANSIENT_COUNT, val);   

  //The default data rate is 800Hz and we don't modify it in this example code

 

  val = (INT_EN_TRANS);

  writeRegister(CTRL_REG4, val);

  MMA8452Active();  // Set to active to start reading

}

// Sets the MMA8452 to standby mode. It must be in standby to change most register settings

void MMA8452Standby()

{

  byte c = readRegister(CTRL_REG1);

  writeRegister(CTRL_REG1, c & ~(0x01)); //Clear the active bit to go into standby

}

// Sets the MMA8452 to active mode. Needs to be in this mode to output data

void MMA8452Active()

{

  byte c = readRegister(CTRL_REG1);

  writeRegister(CTRL_REG1, c | 0x01); //Set the active bit to begin detection

}

Labels (1)
0 Kudos
Reply
6 Replies

1,881 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Hi Sree,

Could you please post here your complete source code? The configuration of the MMA8452Q seems to be correct, but it is not clear when you read the TRANSIENT_SRC register (0x1E) in order to deassert the INT2 pin that is assigned to the transient detection function. Did you try to read back the INT_SOURCE register (0x0C) to make sure the SRC_TRANS bit is cleared after reading the TRANSIENT_SRC register?

It might be useful to post your question at the Arduino forum as well.

Regards,

Tomas

0 Kudos
Reply

1,881 Views
sreejithchandra
Contributor I

Hi Tomas,

Yes, as I already mentioned in order to clear the interrupt I'm reading the TRANSIENT_SRC register.

Do you think there is another reason for the accelerator chip keeping the interrupt pin 'high' always?

0 Kudos
Reply

1,881 Views
TomasVaverka
NXP TechSupport
NXP TechSupport

Sree,

I have just tried to reproduce your settings on the FRDM-KL25Z board (see the attached code) and I had no problems to deassert the transient interrupt by reading the TRANSIENT_SRC register (0x1E). I am not really sure why you cannot deassert the interrupt pin, but I suppose that it might be related to the rest of your complete Arduino code or to the Arduino hardware.


Regards,

Tomas

0 Kudos
Reply

1,881 Views
sreejithchandra
Contributor I

Hey Tomas,

Thank you very much for the code. I was trying a few things in the mean time but couldn't make it working for Arduino.

I can see the INC_SOURCE is cleared after reading TRANS_SOURCE. Still the interrupt holds high after the first one is fired.

I'm sending out the whole code here. Can you please have a look at it?

//------------------------------------------------------------------------------------------------------------------------------------------------//

#include <boards.h>

#include <SPI.h>

#include <Wire.h>

#include <services.h>

/*==============================================================================

* MACROS

*============================================================================*/

// Bit-wise macros

#define SETBIT(x,y)   (x |= (y))  //Set bit y in byte x

#define CLEARBIT(x,y) (x &= (~y)) //Clear bit Y in byte x

#define CHECKBIT(x,y) (x & (y))   //True if bit y of byte x=1.

/*==============================================================================

* ACCELEROMETER GLOBAL VARIABLES + CONSTANTS

*============================================================================*/

// The SparkFun breakout board defaults to 1, set to 0 if SA0 jumper on the bottom of the board is set

#define MMA8452_ADDRESS 0x1D  // 0x1D if SA0 is high, 0x1C if low

// Define a few of the registers that we will be accessing on the MMA8452

#define OUT_X_MSB 0x01

#define XYZ_DATA_CFG  0x0E

#define WHO_AM_I   0x0D

// Control registers

#define CTRL_REG1  0x2A

#define CTRL_REG2  0x2B

#define CTRL_REG3  0x2C

#define CTRL_REG4  0x2D

#define CTRL_REG5  0x2E

#define ASLP_COUNT  0x29

// Iniitial values of Control Registers

#define ASLP_12_5_HZ  0x40

#define ODR_50_HZ  0x20

#define LNOISE_DEFAULT  0x00

#define F_READ_DEFAULT  0x00

#define SLPE  0x04 

#define SMODS_LOW_POW  0x18

#define MODS_NORMAL_POW  0x00

#define ST_DEFAULT  0x00

#define RST_DEFAULT  0x00

#define WAKE_FF_MT  0x08

#define WAKE_TRANS  0x40 

#define IPOL_DEFAULT 0x00

#define PP_OD_DEFAULT 0x00

#define INT_EN_FF_MT  0x04

#define INT_EN_TRANS  0x20

#define INT_EN_ASLP  0x80

#define INT_CFG_FF_MT  0x04

#define INT_CFG_TRANS  0x20

#define ASLP_COUNT_50_HZ_960_MS  0x03

#define ELE  0x80

#define OAE_MOTION  0x40

#define XYZ_EFE 0x18

#define DBCNTM_MOTION  0x00

#define THS_0_2_G  0x0B

#define FF_MT_DEBOUNCE_50_HZ_20_MS  0x0A

#define ELE  0x10

#define XYZ_EFE 0x06

#define HPF_BYP 0x00

#define DBCNTM_TRANS  0x00

#define TRANS_THS_0_5_G  0x05

#define TRANS_DEBOUNCE_50_HZ_20_MS  0x03

//The SRC registers for clearing and reading status of interrupts

#define SYSMOD 0x0B

#define TRANSIENT_SRC 0x1E    

#define FF_MT_SRC 0x16 

// Motion Detection registers

#define FF_MT_CFG  0x15

#define FF_MT_SRC  0x16

#define FF_MT_THS  0x17

#define FF_MT_COUNT  0x18

//Transient registers

#define TRANSIENT_CFG 0x1D

#define TRANSIENT_THS 0x1F

#define TRANSIENT_COUNT 0x20

#define INT_SOURCE  0x0C

#define GSCALE 2 // Sets full-scale range to +/-2, 4, or 8g. Used to calc real g values.

/* Interrupt Status */

volatile unsigned int int_status1 = 0;

volatile unsigned int int_status2 = 0;

float threshX = 0.5;

float threshY = 0.3;

float threshZ = 0.5;

boolean accelConfgd = false;

boolean deviceSecurityEnabled = true;

int accelCount[3];  // Stores the 12-bit signed value

float initAccelG[3];

// Now we'll calculate the accleration value into actual g's

float accelG[3];  // Stores the real accel value in g's

int baudRate = 9600;

/*==============================================================================

* SETUP()

*============================================================================*/

// Interrupt Service Routines

void int0_bh()

{

  int_status1 = 1;

}

void int1_bh()

{

  int_status2 = 1;

}

void setup()

{

  // Enable serial debug

  Serial.begin(baudRate);

   

  Wire.begin(); //Join the bus as a master

  initMMA8452(); //Test and intialize the MMA8452 

  // Attach Interrupts for accelerometer

  pinMode(2,OUTPUT);

  pinMode(3,OUTPUT);

  attachInterrupt(0, int0_bh, CHANGE);

  attachInterrupt(1, int1_bh, CHANGE); 

}

void readAndSaveAccelValues()

{

  memset(accelCount,0,sizeof(accelCount));

  readAccelData(accelCount);  // Read the x/y/z adc values

  for (int i = 0 ; i < 3 ; i++) {

    accelG[i] = (float) accelCount[i] / ((1<<12)/(2*GSCALE));  // get actual g value, this depends on scale being set

  } 

}

void printAccelValues()

{

  Serial.print(accelG[0]);

  Serial.print('|');

  Serial.print(accelG[1]);

  Serial.print(':');

  Serial.println(accelG[2]);

}

/*==============================================================================

* LOOP()

*============================================================================*/

void loop()

{

  static byte val = 0;

  static byte val1 = 0;

  static byte val2 = 0;

 

  if (int_status1 > 0) {

    readRegisters(TRANSIENT_SRC, sizeof(byte), &val1);         

    readRegisters(INT_SOURCE, sizeof(byte), &val2);

    Serial.print("TRANSIENT_SRC: ");

    Serial.println(val1);

    Serial.print("IIIIINT_SOURCE1: ");

    Serial.println(val2);

    

    readRegisters(CTRL_REG4, sizeof(byte), &val);

    Serial.print("CTRL_REG4: ");

    Serial.println(val);

   

    readRegisters(CTRL_REG5, sizeof(byte), &val);

    Serial.print("CTRL_REG5: ");

    Serial.println(val);

   

   readAndSaveAccelValues();

   printAccelValues();

   

    int_status1=0;

  }

 

  if (int_status2 > 0) {

    readRegisters(SYSMOD, sizeof(byte), &val);

    readRegisters(INT_SOURCE, sizeof(byte), &val);

   

    Serial.print("SYSMOD: ");

    Serial.println(val1);

   

    Serial.print("IIIINT_SOURCE2: ");

    Serial.println(val2);

   

    int_status2=0;          

  } 

  delay(100);

}

/*==============================================================================

* ACCELEROMETER METHODS

*============================================================================*/

void readAccelData(int *destination)

{

  byte rawData[6];  // x/y/z accel register data stored here

  readRegisters(OUT_X_MSB, 6, rawData);  // Read the six raw data registers into data array

  // Loop to calculate 12-bit ADC and g value for each axis

  for (int i = 0; i < 3 ; i++) {

    int gCount = (rawData[i*2] << 8) | rawData[(i*2)+1];  //Combine the two 8 bit registers into one 12-bit number

    gCount >>= 4; //The registers are left align, here we right align the 12-bit integer

    // If the number is negative, we have to make it so manually (no 12-bit data type)

    if (rawData[i*2] > 0x7F) { 

      gCount = ~gCount + 1;

      gCount *= -1;  // Transform into negative 2's complement #

    }

    destination[i] = gCount; //Record this gCount into the 3 int array

  }

}

// Initialize the MMA8452 registers

// See the many application notes for more info on setting all of these registers:

// http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MMA8452Q

void initMMA8452()

{

  byte val = readRegister(WHO_AM_I);  // Read WHO_AM_I register

  if (val == 0x2A) // WHO_AM_I should always be 0x2A

  { 

    Serial.println("M is online...");

  }

  else

  {

    Serial.print("Could not connect to MMA8452Q: 0x");

    Serial.println(val, HEX);

    while(1) ; // Loop forever if communication doesn't happen

  }

  MMA8452Standby();  // Must be in standby to change registers

  // Initialize GSCALE

  val = GSCALE;

  if (val > 8) val = 8; //Easy error check

  val >>= 2; // Neat trick, see page 22. 00 = 2G, 01 = 4A, 10 = 8G

  writeRegister(XYZ_DATA_CFG, val);

  val = (ASLP_12_5_HZ | ODR_50_HZ | LNOISE_DEFAULT | F_READ_DEFAULT);

  writeRegister(CTRL_REG1, val);

 

  val = (ST_DEFAULT | RST_DEFAULT | SMODS_LOW_POW | SLPE | MODS_NORMAL_POW);

  writeRegister(CTRL_REG2, val);

  val = (WAKE_TRANS | 0x02 | PP_OD_DEFAULT);

  writeRegister(CTRL_REG3, val);

//interrupt INT TRANS comes on pin 2 

  val = 0; //INT_CFG_TRANS;

  writeRegister(CTRL_REG5, val); 

 

  val = ASLP_COUNT_50_HZ_960_MS;

  writeRegister(ASLP_COUNT, val);

 

  val = (ELE | XYZ_EFE | HPF_BYP);

  writeRegister(TRANSIENT_CFG, val);

 

  val = 0; //(DBCNTM_TRANS | TRANS_THS_0_5_G);

  writeRegister(TRANSIENT_THS, val);

 

  val = 0; //TRANS_DEBOUNCE_50_HZ_20_MS;

  writeRegister(TRANSIENT_COUNT, val);   

 

  val = (INT_EN_TRANS);

  writeRegister(CTRL_REG4, val);

------------------------------------------------------------------------------------------------------------------------------------------------

  MMA8452Active();  // Set to active to start reading

}

// Sets the MMA8452 to standby mode. It must be in standby to change most register settings

void MMA8452Standby()

{

  byte c = readRegister(CTRL_REG1);

  writeRegister(CTRL_REG1, c & ~(0x01)); //Clear the active bit to go into standby

}

// Sets the MMA8452 to active mode. Needs to be in this mode to output data

void MMA8452Active()

{

  byte c = readRegister(CTRL_REG1);

  writeRegister(CTRL_REG1, c | 0x01); //Set the active bit to begin detection

}

// Read bytesToRead sequentially, starting at addressToRead into the dest byte array

void readRegisters(byte addressToRead, int bytesToRead, byte * dest)

{

  Wire.beginTransmission(MMA8452_ADDRESS);

  Wire.write(addressToRead);

  Wire.endTransmission(false); //endTransmission but keep the connection active

  Wire.requestFrom(MMA8452_ADDRESS, bytesToRead); //Ask for bytes, once done, bus is released by default

  while (Wire.available() < bytesToRead); //Hang out until we get the # of bytes we expect

  for (int x = 0 ; x < bytesToRead ; x++) {

    dest[x] = Wire.read(); 

  }

 

  Wire.endTransmission(true); //endTransmission but keep the connection active 

}

// Read a single byte from addressToRead and return it as a byte

byte readRegister(byte addressToRead)

{

  Wire.beginTransmission(MMA8452_ADDRESS);

  Wire.write(addressToRead);

  Wire.endTransmission(false); //endTransmission but keep the connection active

  Wire.requestFrom(MMA8452_ADDRESS, 1); //Ask for 1 byte, once done, bus is released by default

  while(!Wire.available()) ; //Wait for the data to come back

  return Wire.read(); //Return this one byte

}

// Writes a single byte (dataToWrite) into addressToWrite

void writeRegister(byte addressToWrite, byte dataToWrite)

{

  Wire.beginTransmission(MMA8452_ADDRESS);

  Wire.write(addressToWrite);

  Wire.write(dataToWrite);

  Wire.endTransmission(); //Stop transmitting

}

//------------------------------------------------------------------------------------------------------------------------------------------------//

Thanks,

Sree

0 Kudos
Reply

1,881 Views
haroldmccabe
Contributor I

Was there a resolution to this issue? I am having a similar issue with the MMA8652: after first transient event I get repeated interrupts despite reading the transient source register.

0 Kudos
Reply

1,881 Views
anthonyduhamel
NXP Employee
NXP Employee

Hi Harold,

Did you configure the High Pass Filter? In fact, if you don't use it, TRANSIENT event is always set to "High" because of the 1g gravity earth acceleration.

Here a sample of MMA8652FC configuration for motion detection.

#define MMA8652FC_CTRL_REG1                   0x2A

#define MMA8652FC_CTRL_REG2                   0x2B

#define MMA8652FC_CTRL_REG3                   0x2C

#define MMA8652FC_CTRL_REG4                   0x2D

#define MMA8652FC_CTRL_REG5                   0x2E

#define MMA8652FC_TRANSIENT_CFG          0x1D

#define MMA8652FC_TRANSIENT_SRC          0x1E

#define MMA8652FC_TRANSIENT_THS          0x1F

#define MMA8652FC_TRANSIENT_COUNT     0x20

#define MMA8652FC_HP_FILTER_CUTOFF   0x0F

#define MMA8652FC_WHO_AM_I                    0x0D

#define MMA8652FC_WHO_AM_I_VAL           0x4A

bool MMA8652FC::init(uint8_t __u8_7BitAddress)

{

    bool __b_result=false;

    uint8_t __u8_temp=0xFF;

    _u8_I2CAddress=__u8_7BitAddress<<1;

    if(bRead(MMA8652FC_WHO_AM_I,&__u8_temp,1)) {    //Check presence of the sensor

        if(__u8_temp == MMA8652FC_WHO_AM_I_VAL) {   //Check Sensor ID answer

            if(bWrite(MMA8652FC_CTRL_REG3       ,0x02   )) //Wake from Transient interrupt

                if(bWrite(MMA8652FC_CTRL_REG4       ,0x20   )) //Enable Transient Interrupt

                    if(bWrite(MMA8652FC_CTRL_REG5       ,0x20   )) //Interrupt on INT1

                        if(bWrite(MMA8652FC_TRANSIENT_CFG   ,0x1E   )) //Enable latchedevent flag and transient detection on all 3 axis

                            if(bWrite(MMA8652FC_TRANSIENT_THS   ,0x02   )) //Set transient threshold to 0.126mg (2x0.063)

                                if(bWrite(MMA8652FC_TRANSIENT_COUNT ,0x04   )) //Set transient count

                                    if(bWrite(MMA8652FC_HP_FILTER_CUTOFF,0x03   )) //Select HPF cut-off frequency

                                        if(bWrite(MMA8652FC_CTRL_REG1       ,0x21   )) { //Set ODR to 200Hz & active mode

                                            __b_result= true;

                                        }

        }

    }

    return __b_result;

}

Anthony

0 Kudos
Reply