I have been working for months on a motion sensing project using the MMA8451Q and now realize that my FIFO full (watermark) interrupts and generating an extra interrupt before the FIFO watermark is achieved (FIFO full). It seems to me that the interrupt is being re-asserted immediately after I check the INT_SOURCE register (0x0C) or after I check the FIFO_STATUS register (0x00). But since I should check the INT_SOURCE register to make sure I have the current interrupt and must check the FIFO_STATUS register to know if the number of samples in the FIFO is correct, how can I avoid getting these "extra" interrupts.
Let me clarify further with a highly instrumented and commented version of my software.
First, the configuration...
pinMode(mmaInt1, INPUT_PULLUP);
attachInterrupt(mmaInt1, handleInterrupt, FALLING);
writeRegister8(MMA8451_REG_CTRL_REG1, 0x00);
// Configure for 2G range (maximum sensitivity)
writeRegister8(MMA8451_REG_XYZ_DATA_CFG, MMA8451_RANGE_2_G); // setting to 2G sets res to 14-bit
// Enable FIFO interrupt on INT1 pin
writeRegister8(MMA8451_REG_CTRL_REG4, MMA8451_INT_EN_FIFO); // Enable FIFO interrupt
writeRegister8(MMA8451_REG_CTRL_REG5, MMA8451_INT_CFG_FIFO_INT1); // Route FIFO to INT1
// Configure FIFO after interrupts
// Fill mode (stop when full)
writeRegister8(MMA8451_F_SETUP, MMA8451_FIFI_MODE_FILL_BUFFER | Jconfig.FIFO_WATERMARK); // 0x80 for fill mode (FMODE = 11), 0x20 for watermark at 32
// Set for highest precision:
// - ignore auto-wake frequency field
// - 400z data rate (0b011) for 80ms of data MMA8451_DATARATE_400_HZ
// - Low-Noise off MMA8451_LNOISE_OFF
// - Normal read mode MMA8451_F_READ_OFF = 0b00
// - Active mode MMA8451_ACTIVE = 0b01
writeRegister8(MMA8451_REG_CTRL_REG1, MMA8451_DATARATE_200_HZ | MMA8451_LNOISE_OFF | MMA8451_F_READ_OFF | MMA8451_ACTIVE); // Changed from 0x19 to 0x15 for 400Hz
// Add a small delay to let the device stabilize
delay(10);
volatile bool movementInterrupt = false;
void IRAM_ATTR handleInterrupt() {
// Only set a flag - no I2C communication in ISR!
portENTER_CRITICAL_ISR(&mux);
movementInterrupt = true;
portEXIT_CRITICAL_ISR(&mux);
}
bool checkForMovementAndReadFIFO() {
static const char* TAG = "checkForMovementAndReadFIFO";
// if (movementInterrupt > 0) {
checkForMovementAndReadFIFO_startTime = millis();
if (movementInterrupt) {
portENTER_CRITICAL(&mux);
movementInterrupt = false;
portEXIT_CRITICAL(&mux);
...
ESP_LOGD(TAG, "\n\n");
ESP_LOGD(TAG, "Interrupt!");
// According to datasheet... the FIFO interrupt is automatically cleared when you read the F_STATUS register (which we're doing in getFIFOStatus()
uint8_t Int_SourceSystem = mma.getIntSourceReg();
ESP_LOGD(TAG, "***Int_SourceSystem: 0x%02X", Int_SourceSystem);
// Read interrupt status registers
uint8_t fifoStatus = mma.getFIFOStatus();
ESP_LOGD(TAG, "FIFO Status: 0x%02X", fifoStatus);
ESP_LOGD(TAG, " Overflow: %d", (fifoStatus & 0x80) ? 1 : 0);
ESP_LOGD(TAG, " Watermark: %d", (fifoStatus & 0x40) ? 1 : 0);
ESP_LOGD(TAG, " Sample Count: %d", fifoStatus & 0x3F);
// Check if FIFO watermark caused the interrupt
if (fifoStatus & 0x40) // Check F_WMRK_FLAG bit if set, FIFO watermark event detected. FIFO sample count is equal to watermark value.
{
ESP_LOGD(TAG, "Valid FIFO interrupt");
// Read in 32 14-bit raw values
bool errorcode = (i2c_dev->write_then_read(targetRegister, 1, FIFObuffer, use14bit ? BYTES_IN_14_BIT_FIFO : BYTES_IN_8_BIT_FIFO)); // this converts to (i2c_dev->write_then_read(targetRegister, 1, FIFObuffer,6)
...
// NOW, THE FIFO FULL STATUS SHOULD BE CLEARED AS SOON AS WE READ THE FIRST ITEM IN THE FIFO BUFFER (per the datasheet)
// then my math on the data
// check is we have accumulated > 500ms worth of samples
}
else {
if (fifoStatus == 0x00) // check for no FIFO watermark or overflow
{
ESP_LOGD(TAG, "no FIFO watermark or overflow event");
}
else {
ESP_LOGD(TAG, "Invalid interrupt: %d\n", Int_SourceSystem);
ESP_LOGD(TAG, "Unexpected FIFO status: 0x%02X\n", fifoStatus);
}
ESP_LOGD(TAG, "checkForMovementAndReadFIFO elapsed time: %dms", millis() - checkForMovementAndReadFIFO_startTime);
return false;
}
} // if (movementInterrupt > 0)
ESP_LOGD(TAG, "checkForMovementAndReadFIFO elapsed time: %dms", millis() - checkForMovementAndReadFIFO_startTime);
return false;
}
D (41928) checkForMovementAndReadFIFO: [MEMS_Support.cpp:282] checkForMovementAndReadFIFO(): >> WE CHECK FOR INTERRUPT FLAG
D (41928) checkForMovementAndReadFIFO: [MEMS_Support.cpp:283] checkForMovementAndReadFIFO(): Interrupt! >> AND WE FIND IT
D (41939) checkForMovementAndReadFIFO: [MEMS_Support.cpp:287] checkForMovementAndReadFIFO(): ***Int_SourceSystem: 0x40 >> IT IS A FIFO FULL INTERRUPT
D (41949) checkForMovementAndReadFIFO: [MEMS_Support.cpp:291] checkForMovementAndReadFIFO(): FIFO Status: 0xE0
D (41960) checkForMovementAndReadFIFO: [MEMS_Support.cpp:292] checkForMovementAndReadFIFO(): Overflow: 1
D (41970) checkForMovementAndReadFIFO: [MEMS_Support.cpp:293] checkForMovementAndReadFIFO(): Watermark: 1 >> THE WATERMARK BIT **IS** SET
D (41980) checkForMovementAndReadFIFO: [MEMS_Support.cpp:294] checkForMovementAndReadFIFO(): Sample Count: 32 >> AND INDEED, THE FIFO SAMPLE COUNT IS CORRECT AT 32
D (41991) checkForMovementAndReadFIFO: [MEMS_Support.cpp:300] checkForMovementAndReadFIFO(): Valid FIFO interrupt
D (42006) checkForMovementAndReadFIFO: [MEMS_Support.cpp:303] checkForMovementAndReadFIFO(): FIFO read successful >> ALL DATA FROM FIFO RETRIEVED AND PROCESSED
D (42006) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 78ms >> DONE WITH PLENTY OF TIME TO SPARE
D (42029) checkForMovementAndReadFIFO: [MEMS_Support.cpp:282] checkForMovementAndReadFIFO(): >> NEXT CHECK FOR INTERRUPT FLAG (23MS LATER)
D (42029) checkForMovementAndReadFIFO: [MEMS_Support.cpp:283] checkForMovementAndReadFIFO(): Interrupt! >> AND WE FIND IT
D (42040) checkForMovementAndReadFIFO: [MEMS_Support.cpp:287] checkForMovementAndReadFIFO(): ***Int_SourceSystem: 0x00 >> BUT THE FIFO FULL FLAG IS **NOT** SET
D (42050) checkForMovementAndReadFIFO: [MEMS_Support.cpp:291] checkForMovementAndReadFIFO(): FIFO Status: 0x0A
D (42061) checkForMovementAndReadFIFO: [MEMS_Support.cpp:292] checkForMovementAndReadFIFO(): Overflow: 0
D (42071) checkForMovementAndReadFIFO: [MEMS_Support.cpp:293] checkForMovementAndReadFIFO(): Watermark: 0 >> THE WATERMARK BIT **IS NOT** SET
D (42081) checkForMovementAndReadFIFO: [MEMS_Support.cpp:294] checkForMovementAndReadFIFO(): Sample Count: 10 >> AND INDEED, THE FIFO IS NOT FULL
D (42091) checkForMovementAndReadFIFO: [MEMS_Support.cpp:350] checkForMovementAndReadFIFO(): Invalid interrupt: 0
D (42102) checkForMovementAndReadFIFO: [MEMS_Support.cpp:351] checkForMovementAndReadFIFO(): Unexpected FIFO status: 0x0A
D (42112) checkForMovementAndReadFIFO: [MEMS_Support.cpp:353] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 83ms
D (42124) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 0ms >> WE CHECK FOR THE INTERRUPT FLAG...AND DON'T FIND ONE
D (42136) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 0ms >> WE CHECK FOR THE INTERRUPT FLAG...AND DON'T FIND ONE
D (42148) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 0ms >> WE CHECK FOR THE INTERRUPT FLAG...AND DON'T FIND ONE
D (42160) checkForMovementAndReadFIFO: [MEMS_Support.cpp:282] checkForMovementAndReadFIFO(): >> NEXT CHECK FOR INTERRUPT FLAG
D (42170) checkForMovementAndReadFIFO: [MEMS_Support.cpp:283] checkForMovementAndReadFIFO(): Interrupt! >> AND WE FIND IT
D (42171) checkForMovementAndReadFIFO: [MEMS_Support.cpp:287] checkForMovementAndReadFIFO(): ***Int_SourceSystem: 0x40 >> IT IS A FIFO FULL INTERRUPT
D (42181) checkForMovementAndReadFIFO: [MEMS_Support.cpp:291] checkForMovementAndReadFIFO(): FIFO Status: 0xE0
D (42191) checkForMovementAndReadFIFO: [MEMS_Support.cpp:292] checkForMovementAndReadFIFO(): Overflow: 1
D (42202) checkForMovementAndReadFIFO: [MEMS_Support.cpp:293] checkForMovementAndReadFIFO(): Watermark: 1 >> THE WATERMARK BIT **IS** SET
D (42212) checkForMovementAndReadFIFO: [MEMS_Support.cpp:294] checkForMovementAndReadFIFO(): Sample Count: 32 >> AND INDEED, THE FIFO SAMPLE COUNT IS CORRECT AT 32
D (42222) checkForMovementAndReadFIFO: [MEMS_Support.cpp:300] checkForMovementAndReadFIFO(): Valid FIFO interrupt
D (42237) checkForMovementAndReadFIFO: [MEMS_Support.cpp:303] checkForMovementAndReadFIFO(): FIFO read successful >> ALL DATA FROM FIFO RETRIEVED AND PROCESSED
D (42248) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 88ms
D (42260) checkForMovementAndReadFIFO: [MEMS_Support.cpp:282] checkForMovementAndReadFIFO(): >> NEXT CHECK FOR INTERRUPT FLAG
D (42260) checkForMovementAndReadFIFO: [MEMS_Support.cpp:283] checkForMovementAndReadFIFO(): Interrupt! >>****AND THE PATTERN REPEATS....****
D (42271) checkForMovementAndReadFIFO: [MEMS_Support.cpp:287] checkForMovementAndReadFIFO(): ***Int_SourceSystem: 0x00
D (42281) checkForMovementAndReadFIFO: [MEMS_Support.cpp:291] checkForMovementAndReadFIFO(): FIFO Status: 0x09
D (42291) checkForMovementAndReadFIFO: [MEMS_Support.cpp:292] checkForMovementAndReadFIFO(): Overflow: 0
D (42302) checkForMovementAndReadFIFO: [MEMS_Support.cpp:293] checkForMovementAndReadFIFO(): Watermark: 0
D (42312) checkForMovementAndReadFIFO: [MEMS_Support.cpp:294] checkForMovementAndReadFIFO(): Sample Count: 9
D (42322) checkForMovementAndReadFIFO: [MEMS_Support.cpp:350] checkForMovementAndReadFIFO(): Invalid interrupt: 0
D (42333) checkForMovementAndReadFIFO: [MEMS_Support.cpp:351] checkForMovementAndReadFIFO(): Unexpected FIFO status: 0x09
D (42343) checkForMovementAndReadFIFO: [MEMS_Support.cpp:353] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 83ms
D (42355) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 0ms
D (42367) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 0ms
D (42379) checkForMovementAndReadFIFO: [MEMS_Support.cpp:357] checkForMovementAndReadFIFO(): checkForMovementAndReadFIFO elapsed time: 0ms
Dear Pete,
you're encountering a common issue with the MMA8451Q FIFO interrupt behavior, where an extra interrupt is triggered even though the FIFO watermark condition is no longer valid.
Here are a few strategies to try:
1. Make sure you read the FIFO buffer immediately after confirming the interrupt source and before any other I2C operations. This ensures the FIFO interrupt flag is cleared as early as possible.
2. Mask Interrupt During Processing
Temporarily disable the FIFO interrupt in CTRL_REG4
or mask it in CTRL_REG5
during processing, then re-enable it after reading the FIFO:
3. Use FIFO in Circular Mode Instead of Fill Mode
In Circular Mode, the FIFO continues to collect data and overwrite old samples. This can help avoid the "stuck" interrupt condition that sometimes occurs in Fill Mode.
4. Debounce or Delay Interrupt Handling
Add a short delay (e.g., 5–10 ms) before re-enabling the interrupt or checking the FIFO again. This gives the sensor time to stabilize and avoids catching a transient state.
With Best Regards,
Jozef
Thanks @ JosefKozen.
I have in fact tried all of those things.
Accomplishing #1 while still gaining (and printing) some diagnostics is a like a quantum physics problem... you disturb the system by observing it. If you don't "observe" it with the diagnostics, it might be working correctly but with "observing" it, you don't know. Schrödinger lives...
I am really trying not to leave any time slices unsampled. I am playing with how I allocate the tasks between cores and the time slice priorities in FreeRTOS to see if I can "get around" to checking the interrupt more promptly. That might be my biggest problem.
I know see that the MMA 8451Q is going out of production so will need to change chips for production. I need to maintain 14-bit resolution for my application. I found some non-NXP accelerometer chips with 14-bit resolution at 2g AND 512 sample FIFOs. A larger FIFO would allow me to grab my 500ms worth of samples in a single (long) I2C fetch. That would dramatically improve my timing issues. Does NXP offer such a chip? (even a 256 sample FIFO, or possibly a 128 sample FIFO, would do the trick)
Thanks again!
Dear Pete,
As of the latest available information, NXP does not currently offer a direct replacement for the MMA8451Q with both:
However, here are a few NXP accelerometers that come close and might be worth evaluating:
With Best Regards,
Jozef