MAX30105 Particle & SpO2 sensor - DATA_RDY interrupt works but A_FULL interrupt does not work

Hello everyone,

my problem is as simple and as confusing as the title. I have two MAX30105 V10. I use them with an ESP32 (“Feather”). I have a test program that reads all available samples when an interrupt occured. It works when I use the DATA_RDY interrupt but it does nothing when I change the one bit in the setup that changes the DATA_RDY interrupt to the A_FULL interrupt.

My wiring is as simple as the sensor requires; i have all five wires connected to the appropriate pins of the ESP32 (SDL => SDL, SDC => SDC, 5V => USB, GND => GND, INT => A2), I have an additional 4.7k resistor on the INT and additional 1k resistors on the I2C connectors to improve the I2C signal. I only use one MAX30105 at a time but both have the same problem.

My program is attached. I used the Arduino IDE. I documented all the configs in the code, it should be pretty obvious what I did. (It starts in the setup() routine from the “max30105 config” comment.)

What am I missing? Are there any requirements to use the A_FULL interrupt? Is this a hardware problem?

Thank you in advance.

Christian

#include <Wire.h>          // I2C library   

#define max30105 0x57 // I2C Address MAX30101
#define bufferlength 200 // length of buffer to be filled by the interrupt routine
const byte interruptPin = 36;
volatile int interruptCounter = 0;
int nrofirqs = 0;

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;  // a mechanisms to prevent clossions during interrupt handling

//Set array for real measured values and imaginary. NOTE: LED1 = RED LED
double redLEDbuffer[bufferlength];
double irLEDbuffer[bufferlength];

volatile unsigned int fifo_wr_pt; // FIFO pointers
volatile unsigned int ovf_counter;
volatile unsigned int fifo_rd_pt;
volatile int availablesamples;

volatile unsigned int redvalue;
volatile unsigned int irvalue;

int i;
int error, nbytes;

// interrupt handling routine
void IRAM_ATTR handleInterrupt() {

  portENTER_CRITICAL_ISR(&mux);         // do not allow other interrupts to happen while this is being worked on (causes crashes when timing fails)
  interruptCounter++;
  portEXIT_CRITICAL_ISR(&mux);
}

void setup() {

  Wire.begin();
  Wire.setClock(100000); //set Frequency for SCLK clock at 100kHz

  Serial.begin(115200); // USB Baud Rate

  // max30105 reset
  Wire.beginTransmission(max30105);
  Wire.write(0x09);
  Wire.write(0b01000000);  //reset MAX30105 device(data to register)
  error = Wire.endTransmission();
  if (error == 0) Serial.println("MAX30101 communication o.k.");

  delay(200); //maybe unneccessary or too long (give MAX30105 some time for internal reset)

  // max30105 config
  Wire.beginTransmission(max30105);
  Wire.write(0x08);
  Wire.write(0b00011111); // Mode Configuration register: 000 = 1 samples average, 1 = enable FIFO rollover, 1111 = FIFO_A_FULL on 15 samples left (was: 0111)
  Wire.write(0b00000011); // set mode to 2-LED particle sensing mode using IR and red LEDs (last 3 Bits = 011)
  Wire.write(0b01100011); // 0 = reserved, 11 = 16384 nA full scale, 000 = 50 samples/second; 11 = 18 bit ADC resolution
  error = Wire.endTransmission(); // skip reserved register
  if (error == 0)  Serial.println("MAX30101 registers 8 through A initialized");
  Wire.beginTransmission(max30105);
  Wire.write(0x0C);
  Wire.write(0x7F); // red LED set current to 25.4 mA
  Wire.write(0x7F); //IR LED set current to 25.4 mA
  error = Wire.endTransmission(); // skip green LED register, reserved and proximity settings
  if (error == 0)  Serial.println("MAX30101 registers C through D initialized");
  Wire.beginTransmission(max30105);
  Wire.write(0x11);
  Wire.write(0b00100001); // 0 = reserved, 010 = IR LED in slot 2, 0 = reserved, 001 = red LED in slot 1,
  Wire.write(0b00000000); // nothing in slot 4, nothing in slot 3
  error = Wire.endTransmission();
  if (error == 0)  Serial.println("MAX30101 registers initialized");
  // temp and proximity have been skipped

  // max30105 Interrupt enable Register setzen
  Wire.beginTransmission(max30105);
  Wire.write(0x02);
  Wire.write(0b10000000); // 0 = A_FULL off, 1 = DATA_RDY on, all others off
  Wire.write(0b00000000);
  error = Wire.endTransmission();
  if (error == 0)  Serial.println("MAX30101 interrupt enable registers initialized");

  //  reset FIFO
  Wire.beginTransmission(max30105);
  Wire.write(0x04); // clear FIFO pointers
  Wire.write(0x00); // see page 15
  Wire.write(0x00);
  Wire.write(0x00);
  error = Wire.endTransmission();
  if (error == 0)  Serial.println("MAX30101 FIFO reset");

  Wire.beginTransmission(max30105);
  Wire.write(0x00);
  error = Wire.endTransmission();
  nbytes = Wire.requestFrom(max30105, 2, true);  // read and clear both interrupt registers
  if (error == 0 && nbytes == 2)  Serial.println("MAX30101 interrupt registers cleared");

  // interrupt setup on microcontroller
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING);

  Serial.println("End of setup ... entering loop.");
}

void loop() {
  if (interruptCounter > 0)
  {
    portENTER_CRITICAL(&mux);
    nrofirqs = interruptCounter;
    interruptCounter = 0;
    portEXIT_CRITICAL(&mux);

    // read FIFO pointers
    Wire.beginTransmission(max30105);
    Wire.write(0x04);
    error = Wire.endTransmission();
    nbytes = Wire.requestFrom(max30105, 3, true);  //read 3 bytes for the two FIFO pointers and overflow counter
    if (error != 0 || nbytes != 3)  Serial.println("Could not read FIFO pointers");

    fifo_wr_pt = Wire.read();
    ovf_counter = Wire.read();
    fifo_rd_pt = Wire.read();

    availablesamples = (fifo_wr_pt - fifo_rd_pt) & 0b00011111;    // no of avail samples calculated from pointers

    if (availablesamples > 0) {     
      //Reading from FIFO
      Wire.beginTransmission(max30105);
      Wire.write(0x07);       //  FIFO register
      error = Wire.endTransmission();
      nbytes = Wire.requestFrom(max30105, 6 * availablesamples, true); // request 6*nsamples Bytes (3 * 2 - Red & IR)
      if (error != 0 || nbytes != 6 * availablesamples)  Serial.println("Could not read FIFO data");

      for (int i = 0; i < availablesamples; i++) {
        // Clear first 6 bits because they are defined as "unused" which does not necessarily mean zero
        // Shift the others to combine the three bytes
        redvalue = (Wire.read() & 0b00000011) * 65536 + Wire.read() * 256 + Wire.read();
        irvalue = (Wire.read() & 0b00000011) * 65536 + Wire.read() * 256 + Wire.read();
        Serial.print("Rot: ");
        Serial.print(redvalue);
        Serial.print(" Infrarot: ");
        Serial.println(irvalue);
      }
    }

    // read interrupt register to reset interrupt
    // commented out because it is unnecessary according to documentation
    //Wire.beginTransmission(max30105);
    //Wire.write(0x00);
    //Wire.endTransmission();
    //Wire.requestFrom(max30105, 1, true);

    Serial.print("Interrupt triggered...");
    Serial.println(nrofirqs);

    Serial.print("Pointer & samples:  ");
    Serial.print(fifo_wr_pt);
    Serial.print("  ");
    Serial.print(ovf_counter); // should always be 0 but is not
    Serial.print("  ");
    Serial.print(fifo_rd_pt);
    Serial.print("  ");
    Serial.println(availablesamples);
  }
}