MMA8451Q FIFO Interrupt... getting extra interrupts without FIFO flag

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

MMA8451Q FIFO Interrupt... getting extra interrupts without FIFO flag

637 次查看
peteDDD
Contributor II

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

  • FIFO FULL interrupt with watermark at 32 samples
  • Range: 2G, 14-bit
  • 200hz sample rate, low-noise off, fast read off, active mode
Set up interrupt for ESP32-S3
    pinMode(mmaInt1, INPUT_PULLUP);
    attachInterrupt(mmaInt1, handleInterrupt, FALLING);
Incidentally, yes, I have tried RISING as well...)
 
Then configure the MMA8451Q
 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);
 
Now, I set a flag when I catch the interrupt
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);
}
and I look for the interrupt in my state machine
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;
}
 
And now the output...  I have added comments to the output which are preceded with ">>"
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
 
So you can see a pattern of one correct FIFO FULL interrupt followed by an "extra" and "false" interrupt in which the FIFO is not actually full. And this repeats over and over.
 
It seems I need to be able to check the interrupt and fifo status but somehow not let the interrupt be reasserted before I read the FIFO data.  Other than turning off the MMA8451Q interrupt and then restarting it after the read, is there another way to accomplish this checking and reading of the *full* FIFO without having the interrupt re-asserted?  Is there a "normal" way to do this that I am just not getting?
 
Many thanks!
 
 
0 项奖励
回复
3 回复数

585 次查看
JozefKozon
NXP TechSupport
NXP TechSupport

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.

uint8_t intSource = mma.getIntSourceReg();
if (intSource & 0x40) {
    uint8_t fifoStatus = mma.getFIFOStatus();
    if (fifoStatus & 0x40) {
        // Immediately read FIFO here
    }
}

 

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:

// Disable FIFO interrupt
writeRegister8(MMA8451_REG_CTRL_REG4, 0x00);

 

// Read FIFO...

 

// Re-enable FIFO interrupt
writeRegister8(MMA8451_REG_CTRL_REG4, MMA8451_INT_EN_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.

writeRegister8(MMA8451_F_SETUP, 0xC0 | watermark); // FMODE = 10 (circular)

 

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

0 项奖励
回复

576 次查看
peteDDD
Contributor II

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!

标记 (1)
0 项奖励
回复

558 次查看
JozefKozon
NXP TechSupport
NXP TechSupport

Dear Pete,

As of the latest available information, NXP does not currently offer a direct replacement for the MMA8451Q with both:

  • 14-bit resolution at ±2g, and
  • a FIFO buffer of 128 samples or more.

However, here are a few NXP accelerometers that come close and might be worth evaluating:

 FXLS8974CF

  • Resolution: 14-bit
  • Range: ±2g to ±16g
  • FIFO: 32 samples
  • Interface: I²C/SPI
  • Power: Ultra-low power
  • Notes: Designed for industrial and consumer applications. FIFO is smaller than your target, but otherwise a solid performer.

FXLS8964AF

  • Resolution: 14-bit
  • Range: ±2g to ±16g
  • FIFO: 32 samples
  • Interface: I²C/SPI
  • Notes: Similar to FXLS8974CF, with slightly different packaging and power profiles.

 

With Best Regards,

Jozef

0 项奖励
回复