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!