Problem with Arduino & MMA8451 interrupt settings

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

Problem with Arduino & MMA8451 interrupt settings

4,098 Views
markross-smith
Contributor I

Hi. I am building a game using a MMA8451Q breakout board connected to an Arduino Uno.  The standalone device, powered by battery, must create an interrupt if z-axis acceleration exceeds a value (say, 2g) AND the vertical movement exceeds a value (say, 30mm).  I calculate the vertical movement by double-integrating the positive acceleration readings.

My problem is that tell-tales I have in the software show inconsistent results between vertical lifts.  Even when it appears to work, the vertical acceleration required to get it to wake up and fire is way more than the threshold I have set.  I have been struggling with this problem for weeks now.  The Application Notes for the MMA are confusing for me, and I would really appreciate some feedback on my software, and particularly the register settings, which I attach.

Many thanks in anticipation!

Labels (1)
0 Kudos
7 Replies

2,419 Views
markross-smith
Contributor I

Hi Anthony,

Thanks you for your detailed explanation and comments!  I certainly see the places I have gone wrong, and I will work through each of your suggestions and see how I go.

I will respond to this forum when I have some (good!) news.

Thanks, again,

Mark

0 Kudos

2,419 Views
markross-smith
Contributor I

Hi again.

Following on from my previous issues, I have realised that I need to use the FIFO interrupt method to extend battery life.  I have been successful in setting up the FIFO and the wake interrupt but I realise I don't know how to read the 32 samples from the FIFO registers.  I have read that the FIFO buffer can be read as a "burst" or a "flush" of 196 bytes, but I cannot see whether it is one read or 32 reads in a loop.

I found the following note:

The whole FIFO content is retrieved by performing thirty-two reads from the accelerometer output registers, every other read returns the same last value until a new sample set is available in the FIFO buffer.
Data can be retrieved from FIFO using every reading byte combination in order to increase the application flexibility (ex: 196 single byte reads, 32 reads of 6 bytes, 1 multiple read of 196 bytes, etc.).
It is recommended to read all FIFO slots in a multiple byte read of 196 bytes (6 output registers by 32 slots) faster than 1*ODR. In order to minimize communication between the master and slave the read address is automatically updated by the device; it rolls back to 0x28 when register 0x2D is reached.

I don't really understand all of that! Please would someone help me with some sample code how these reads would be done.

Many thanks,

Mark

0 Kudos

2,419 Views
markross-smith
Contributor I

Hi,

I have no responses to my query from 2 weeks ago.  I would like to ask:

In AN4073 (Using FIFO in the MA8451Q) I see in the example 5.1 the following line to "burst out 14 bit data" in the ISR:

ComObj.ReadDataBurst(CurDeviceAddress,0x0q,ref databuf14,192)

I am using an Arduino Uno as my processor, and I am trying to use the various commands from the Wire.h library such as Wire.requestFrom(), Wire.Available() and Wire.Read().  However, I am getting error results, and I think it is because these Wire commands do not include the FIFO start address in the MMA8451Q.

Can anyone help me please?

Thanks,

Mark

0 Kudos

2,419 Views
david_diaz
NXP Employee
NXP Employee

Hello Mark,

First of all, I recommend using the example project below as a reference for your project in terms of the device initial configuration:

MMA8451Q - Bare metal example project

 

In order to detect a quick jerk in the Z-axis, have you considered using the transient detection function of the device? The transient detection mechanism can be configured to raise an interrupt when the magnitude of the acceleration threshold is exceeded, so I recommend using it.

Please review the application note below in order to get more information:

High-Pass Filtered Data and Transient Detection Using the MMA8451

 

Please let me know if you have any further question.

Regards,

David

0 Kudos

2,419 Views
markross-smith
Contributor I

Hi David,

Thanks for your prompt reply.  Unfortunately, I have already tried both of your suggestions.  In fact, I started out using Transient Detection but had no success with that at all.  I'm sure my code problem stems from the Loop where variables are not being reset, or g readings are being stored somewhere and printed out in the serial screen at the next lift.

An earlier version of my program - before I started Sleep/Wake/Interrupt - worked very well with slow lifts and gave accurate upward displacements.  The same Motion Detection settings on the latest version now require a significant upwards jerk to record anything, and the displacement is totally inaccurate.  This makes me think that data is being lost or saved during the sleep/wake cycles.

Do you have any other suggestions for me please?

Thanks and regards,

Mark

0 Kudos

2,419 Views
anthonyduhamel
NXP Employee
NXP Employee

Hi Mark,

First of all, let me check with you your program. If I well understand:

- The arduino init the sensor and then goes into sleep mode (the sensor is also in sleep mode).

- When the transient function is triggered, the MMA8451 switches to normal mode.

- I guess the sensor interrupt is catched by your arduino and this wake it up. This is just strange how you coded it. It should be an external interrupt handler and not called in a loop.

         

void setup()
{
// your init

}

void pin2Interrupt(void)
{
  detachInterrupt(digitalPinToInterrupt(pin2));   // stop firing while interrupt pin is low
  Serial.println("ISR Arduino Awake!");
  exitSleep();
}
void exitSleep(void)
{
  sleep_disable(); // I think this is automaticaly done by your LPWU pin)
  Serial.println("Arduino exiting sleep");
}

void enterSleep(void)
{
  Serial.println("Loop Arduino entering sleep");
 attachInterrupt(digitalPinToInterrupt(pin2), pin2Interrupt, LOW);   // Setup pin2 as an interrupt and attach handler
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  
}
void loop()
{
 enterSleep();
 // when wake up interrupt goes there
  while ((x <= reps) && (cumS < minLift))      // while loop with 2 conditions
  {
     //
  }
 
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

- then the arduino try to compute the displacement from the acceleration 

Am I wrong?

About your MMA8451 configuration:

RegisterValueDescription
CRTL_REG10x21Active mode, Normal ODR=50Hz, Sleep ODR=50Hz
CRTL_REG20x1ESleepMode= Low Power, NormalMode=High Resolution, AutoSleep enabled
CRTL_REG30x40Transient function wakes the system
CRTL_REG40x20Transient Interrupt enabled
CRTL_REG50x20Interrupt routed on INT1
XYZ_DATA_CFG0x00FSR to +/-2g
ASLP_COUNT0x03Minimum period of activity = 3 / SleepODR =  60ms
TRANSIENT_CFG0x08Transient detection on Z axis enabled
TRANSIENT_THS0x05Threshold set to 0.063*5 = 315 mg
TRANSIENT_COUNT0x03Debounce set to 3/SleepODR  = 60ms (Sleep mode to normal mode wake up)

According to your application, I'm not sure the MMA8451 settings are well chosen. 

Firstly, the sleep mode/active mode option is not really valuable as you only change the Power/Resolution Mode and not the ORD. In fact your ODR in normal mode seems pretty slow, I would recommend you to increase it to  have a better resolution for the displacement calculation.

The threshold is set to 315mg. This will not work as the Z-axis see the 1-g Earth gravity. If you want to use the function in a "relative" mode, you need to enable the internal High-Pass filter to remove it.

The debounce (TRANSIENT_COUNT) value of the transient function can be an obstacle for the Z motion detection. With the current parameter, the Z-acceleration must be higher than the threshold during at least 60 ms. You have to make sure it is. It could be better to increase the threshold and reduce the debounce value.

I highly recommend you to collect data in a real use case. This can help you to well set the transient function.  Below an example of datalog of the Z-axis in a "lift" case. 

pastedImage_7.png

About the displacement calculation, usually, we don't recommend our customer to play with that. The double integration of the g value is pretty dangerous, as is can bring a high error and make your result not accurate at all.

In order to make it more reliable, you should sample it at a high rate (interval value as small as possible) and also use the trapezoidal rule approximation for the integration instead of the rectangular methods.

I hope this will help you.

Regards,

Anthony

0 Kudos

2,419 Views
markross-smith
Contributor I

Hi againAnthony,

Quick question: what application do you use to graph the acceleration vs. time in your response above?  It would be a very useful tool for me to understand what my settings changes are doing.

Thanks,

Mark

0 Kudos