Help with low power mode MMA8452Q

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

Help with low power mode MMA8452Q

1,864 Views
chrisspregnan
Contributor II

Hi Everyone,

I have a problem at hand that is confusing me quite a bit. So here is a general description of my setup:

ATMega328P at 3.3v and 8mhz hooked up to a MMA8452Q breakout from sparkfun via i2c and interrupt (INT0).

The 328p sets up the 8452Q accelerometer and then goes into sleep. The 8452q will send an interrupt signal via INT0 when it detects a tap. The 328p wakes up when it detects an interrupt (rising) on a external interrupt. It will then access register 0x0C to determine that the interrupt is generated by a tap. Then, it reads register 0x22 to see which direction the tap came from (XYZ). If the direction is X, Y, or Z, it will trigger a LED to turn on for 50ms and go back to sleep.

The 328p is functioning correctly. It sleeps at around 0uA(it's probably somewhere around 1uA, but my multimeter can't measure it). However, the 8452q is not. I have set the rate at 50hz and the datasheet says that the current draw should be ~24uA. When first powered up, the total current draw of the MCU and the 8452Q is 26uA. But if I tap it once, the LED turns on, then off, and the current of the whole system no longer goes back down to 26 uA. It stays at around 351 uA. I am very confused at what is causing this.

I think that the 8452Q is still waiting for the MCU to read some register, which causes it to use so much current. The problem is that I don't know what register.

Can anyone explain what is going wrong and maybe help me figure out a solution? If you need anymore info, just ask.

Labels (1)
8 Replies

1,301 Views
david_diaz
NXP Employee
NXP Employee

Hello Chriss,

How are you measuring this current consumption? Are there other devices drawing current as well?

Please be aware that the current consumption stated in the datasheet applies for VDD = 2.5 V, VDDIO = 1.8 V, T = 25 °and has been measured with an amperemeter between 2.5V voltage rail and VDD input only.

Have a great day.

David Diaz.

0 Kudos

1,301 Views
chrisspregnan
Contributor II

Hi David, thanks a lot for replay. I´have Vdd=3.3 and VDDIO=3.3v, I'm using a sparkfun breakout. My layout is like this:

20160808_155222.jpg

the amperimeter is 350 uA when the device enter to sleep. I have used Vdd=2.5V, but just down a bit.

Is there something wrong on my code? Is possible to get less than 30 uA as datasheet says?

Thank you!!

0 Kudos

1,301 Views
david_diaz
NXP Employee
NXP Employee

Hello Chriss,

Please accept my apologies for the delay.

How are you setting the MMA8452Q? Can you share your source code?

At any point, does the accelerometer goes to High Resolution Mode?

Regards,

David

0 Kudos

1,301 Views
chrisspregnan
Contributor II

Hi David! Thanks again!,

this is my code, the only thing it do is wait for a TAP and after 18 seconds it go to sleep. In WAKE mode I read about 500 uA, when it go to sleep current down to 350 uA aprox, but never so low as the data sheet says, arround 20 uA:

CODE:

#include "i2c.h" 

#include <VirtualWire.h>

#include "LowPower.h"

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

#define SA0 1

#if SA0

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

#else

#define MMA8452_ADDRESS 0x1C

#endif

#define SYSMOD           0x0B

#define INT_SOURCE       0x0C

#define FF_MT_CFG        0x15

#define FF_MT_SRC        0x16

#define FF_MT_THS        0x17

#define FF_MT_COUNT      0x18

#define CTRL_REG1        0x2A

#define CTRL_REG2        0x2B

#define CTRL_REG3        0x2C

#define CTRL_REG4        0x2D

#define CTRL_REG5        0x2E

bool sleepMode = false;

int count = 0;

const char *msg = "Mentita";

// Set the scale below either 2, 4 or 8

const byte SCALE = 2;  // Sets full-scale range to +/-2, 4, or 8g. Used to calc real g values.

// Set the output data rate below. Value should be between 0 and 7

const byte dataRate = 0;  // 0=800Hz, 1=400, 2=200, 3=100, 4=50, 5=12.5, 6=6.25, 7=1.56

// Pin definitions

int int1Pin = 2;  // These can be changed, 2 and 3 are the Arduinos ext int pins

int int2Pin = 3;

const int wakeUpPin = 3; //Pin para despertar cuando hay TAP

int PinVccTransmisor = 9;

int PinDatosTransmisor = 10;

int VoltajeBateria = 11;

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

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

void setup()

{

  byte c;

  Serial.begin(9600);

  // Set up the interrupt pins, they're set as active high, push-pull

  pinMode(int1Pin, INPUT);

  digitalWrite(int1Pin, LOW);

  pinMode(int2Pin, INPUT);

  digitalWrite(int2Pin, LOW);

 

  pinMode(PinVccTransmisor, OUTPUT);

  pinMode(PinDatosTransmisor, OUTPUT);

  pinMode(VoltajeBateria, INPUT);

  //Define velocidad de envio datos al receptor

  {

   vw_setup(2000); // Bits per sec

   vw_set_tx_pin(PinDatosTransmisor);

}

  // Read the WHO_AM_I register, this is a good test of communication

  c = readRegister(0x0D);  // Read WHO_AM_I register

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

  { 

    initMMA8452(SCALE, dataRate);  // init the accelerometer if communication is OK

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

  }

  else

  {

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

    Serial.println(c, HEX);

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

  }

}

// 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

// Feel free to modify any values, these are settings that work well for me.

void initMMA8452(byte fsr, byte dataRate)

{

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

  // Set up the full scale range to 2, 4, or 8g.

  if ((fsr==2)||(fsr==4)||(fsr==8))

    writeRegister(0x0E, fsr >> 2); 

  else

    writeRegister(0x0E, 0);

  // Setup the 3 data rate bits, from 0 to 7

  writeRegister(0x2A, readRegister(0x2A) & ~(0x38));

  if (dataRate <= 7)

    writeRegister(0x2A, readRegister(0x2A) | (dataRate << 3)); 

  // Set up portrait/landscap registers - 4 steps:

  // 1. Enable P/L

  // 2. Set the back/front angle trigger points (z-lock)

  // 3. Set the threshold/hysteresis angle

  // 4. Set the debouce rate

  // For more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4068.pdf

  writeRegister(0x11, 0x40);  // 1. Enable P/L

  writeRegister(0x13, 0x44);  // 2. 29deg z-lock (don't think this register is actually writable)

  writeRegister(0x14, 0x84);  // 3. 45deg thresh, 14deg hyst (don't think this register is writable either)

  writeRegister(0x12, 0x50);  // 4. debounce counter at 100ms (at 800 hz)

  /* Set up single and double tap - 5 steps:

   1. Set up single and/or double tap detection on each axis individually.

   2. Set the threshold - minimum required acceleration to cause a tap.

   3. Set the time limit - the maximum time that a tap can be above the threshold

   4. Set the pulse latency - the minimum required time between one pulse and the next

   5. Set the second pulse window - maximum allowed time between end of latency and start of second pulse

   for more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4072.pdf */

  // writeRegister(0x21, 0x7F);  // 1. enable single/double taps on all axes

  writeRegister(0x21, 0x55);  // 1. single taps only on all axes

  // writeRegister(0x21, 0x6A);  // 1. double taps only on all axes

  writeRegister(0x23, 0x04);  // 2. x thresh at .5g, multiply the value by 0.0625g/LSB to get the threshold

  writeRegister(0x24, 0x04);  // 2. y thresh at .5g, multiply the value by 0.0625g/LSB to get the threshold

  writeRegister(0x25, 0x04);  // 2. z thresh at .5g, multiply the value by 0.0625g/LSB to get the threshold

  writeRegister(0x26, 0x30);  // 3. 30ms time limit at 800Hz odr, this is very dependent on data rate, see the app note

  writeRegister(0x27, 0xA0);  // 4. 200ms (at 800Hz odr) between taps min, this also depends on the data rate

  writeRegister(0x28, 0xFF);  // 5. 318ms (max value) between taps max

  // Set up interrupt 1 and 2

  writeRegister(0x2C, 0x02);  // Active high, push-pull interrupts

  writeRegister(0x2D, 0x08);  // Interrupción sólo con TAP (Pulse)

  writeRegister(0x2E, 0x01);  // DRDY on INT1, P/L and taps on INT2

// These settings have to do with setting up the sleep mode and should probably be broken up into a separate function

// set Auto-WAKE sample frequency when the device is in sleep mode

     writeRegister(0x29, 0x20 ); // sleep after ~36 seconds of inactivity at 6.25 Hz ODR

  // Set Wake Oversampling mode to High resolutio (10 y Sleep Oversamplin to Low Power (11), SLPE=1

     writeRegister(CTRL_REG2, readRegister(CTRL_REG2) & (0xE4)|(0x1A));

    

  // set sleep mode interrupt scheme,// select wake on transient, orientation change, pulse, or freefall/motion detect

     writeRegister(CTRL_REG3, readRegister(CTRL_REG3) & ~(0x3E)|(0x3E)); // clear bits 3, 4, 5, and 6, "Decia 3C"

   // Enable Auto-SLEEP/WAKE interrupt

     writeRegister(CTRL_REG4, readRegister(CTRL_REG4) & ~(0x88)|(0x88)); // clear bit 7 and select  Auto-SLEEP/WAKE interrupt enable"Decia 80, se activa bit 3, PULSE"

    

  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(0x2A);

  writeRegister(0x2A, c & ~(0x01));

}

// Sets the MMA8452 to active mode.

// Needs to be in this mode to output data

void MMA8452Active()

{

  byte c = readRegister(0x2A);

  writeRegister(0x2A, c | 0x01);

}

// Read i registers sequentially, starting at address into the dest byte array

void readRegisters(byte address, int i, byte * dest)

{

  i2cSendStart();

  i2cWaitForComplete();

  i2cSendByte((MMA8452_ADDRESS<<1)); // write 0xB4

  i2cWaitForComplete();

  i2cSendByte(address); // write register address

  i2cWaitForComplete();

  i2cSendStart();

  i2cSendByte((MMA8452_ADDRESS<<1)|0x01); // write 0xB5

  i2cWaitForComplete();

  for (int j=0; j<i; j++)

  {

    i2cReceiveByte(TRUE);

    i2cWaitForComplete();

    dest[j] = i2cGetReceivedByte(); // Get MSB result

  }

  i2cWaitForComplete();

  i2cSendStop();

  cbi(TWCR, TWEN); // Disable TWI

  sbi(TWCR, TWEN); // Enable TWI

}

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

byte readRegister(uint8_t address)

{

  byte data;

  i2cSendStart();

  i2cWaitForComplete();

  i2cSendByte((MMA8452_ADDRESS<<1)); // Write 0xB4

  i2cWaitForComplete();

  i2cSendByte(address); // Write register address

  i2cWaitForComplete();

  i2cSendStart();

  i2cSendByte((MMA8452_ADDRESS<<1)|0x01); // Write 0xB5

  i2cWaitForComplete();

  i2cReceiveByte(TRUE);

  i2cWaitForComplete();

  data = i2cGetReceivedByte(); // Get MSB result

  i2cWaitForComplete();

  i2cSendStop();

  cbi(TWCR, TWEN); // Disable TWI

  sbi(TWCR, TWEN); // Enable TWI

  return data;

}

// Writes a single byte (data) into address

void writeRegister(unsigned char address, unsigned char data)

{

  i2cSendStart();

  i2cWaitForComplete();

  i2cSendByte((MMA8452_ADDRESS<<1)); // Write 0xB4

  i2cWaitForComplete();

  i2cSendByte(address); // Write register address

  i2cWaitForComplete();

  i2cSendByte(data);

  i2cWaitForComplete();

  i2cSendStop();

}

void tapHandler()

{

  byte source = readRegister(0x22);  // Reads the PULSE_SRC register

  if (((source & 0x10)==0x10) || ((source & 0x20)==0x20) || ((source & 0x40)==0x40))  // If X o Y o Z bit is set

  {

    digitalWrite(PinVccTransmisor, HIGH);  // Activa emisor

    Serial.println("TAP    Enviando Datos ");     

    vw_send((uint8_t *)msg, strlen(msg));  //Envia datos

    vw_wait_tx(); // Wait until the whole message is gone

    digitalWrite(PinVccTransmisor, LOW);  //Apaga emisor

   

  }

}

void loop()

{

     static byte source;

    source = readRegister(0x0C);  // Read the interrupt source reg.

 

    if ((source & 0x08)==0x08)  // Otherwise, if tap register is set go check that

      {

      tapHandler();

      }

     

  // Manage sleep/wake interrupts

  if((readRegister(INT_SOURCE) & 0x80) == 0x80) { // Check if interrupt source is sleep/wake interrupt

  if(!sleepMode) {

  Serial.println("entering sleep mode");

    sleepMode = TRUE;

   

//    attachInterrupt(0, wakeUp, HIGH);

//    LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);

//    detachInterrupt(0);

   }

  else {

  Serial.println("exiting sleep mode");

    sleepMode = FALSE;

  }

  readRegister(SYSMOD); // clear sleep interrupt

  }

delay(10);  // Delay here for visibility

}

Thanks for your comments!

0 Kudos

1,301 Views
david_diaz
NXP Employee
NXP Employee

Hello Chriss,

Once again, accept my apologies for the delay.

I created a sample project in order to demonstrate the current consumption of the NXP accelerometers, included the MMA845x and MMA865x.

Please find the sample project mentioned above at:

https://community.nxp.com/docs/DOC-332453

I recommend using this material as a reference for your design and comparing the registers value.

I hope this information will be useful for you.

If I misunderstood your question, feel free to let me know.  I will be glad to help.

Have a great day.

David Diaz.

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

1,301 Views
chrisspregnan
Contributor II

Hi David,

thanks a lot for you job!!, You are a real master.  I´m sure that will help me with my problem and it will be very apreciated for the community

Thanks again!

Chriss. :smileyhappy:

0 Kudos

1,301 Views
david_diaz
NXP Employee
NXP Employee

Hello Chriss,

Thank you very much for your comments. I am glad to help :smileyhappy:

Please let me know if you have any further questions about this or some other topics related with the NXP sensors.

Have an excellent day.

David

0 Kudos

1,301 Views
chrisspregnan
Contributor II

Plaese!, Help!

0 Kudos