TCA9548A i2c multiplexer and MAX30102 Sensors

Hopfully someone on here can assist with an odd problem I have run into. I am using a TCA9548A i2c multiplexer with 3 MAX30102 sensors. I have everything wired up and my code works when testing the infrared and red lights on each sensor. My issue is when I try to change the code to read other signals using these infrared and red lights. My code will only read the last sensor. I have the first sensor reading heart rate, the second senor reading blood oxygen saturation, and the third sensor reading temperature. When I test the code the output is all 3 reading from the third sensor and not one from each. Has anyone else came across this problem? My code is attached.

Best,

sketch_oct26a.ino (3.92 KB)

Please post your code.

#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"

MAX30105 sensor1;
MAX30105 sensor2;
MAX30105 sensor3;
const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; //Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; //Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;
int perCent1;
int irOffset1 = 2100;

#define TCAADDR 0x70
void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Initializing...");
  Wire.begin();
  delay(0);

  // Initialize sensor One
  tcaselect(0);
  if (!sensor1.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }
  Serial.println("Place your index finger on the sensor with steady pressure.");
  sensor1.setup(); //Configure sensor with default settings
  sensor1.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  sensor1.setPulseAmplitudeGreen(0); //Turn off Green LED


// Initialize sensor Two
  tcaselect(1);
  if (!sensor2.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }
  Serial.println("Place your index finger on the sensor with steady pressure.");
  byte ledBrightness2 = 25; //Options: 0=Off to 255=50mA=0xFF hexadecimal. 100=0x64; 50=0x32 25=0x19
  byte sampleAverage2 = 4; //Options: 1, 2, 4, 8, 16, 32
  byte ledMode2 = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  int sampleRate2 = 400; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  int pulseWidth2 = 411; //Options: 69, 118, 215, 411
  int adcRange2 = 2048; //Options: 2048, 4096, 8192, 16384
  sensor2.setup(ledBrightness2, sampleAverage2, ledMode2, sampleRate2, pulseWidth2, adcRange2); //Configure sensor with default settings
  sensor2.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  sensor2.setPulseAmplitudeGreen(0); //Turn off Green LED


// Initialize sensor Three
  tcaselect(2);
  if (!sensor3.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }
  Serial.println("Place your index finger on the sensor with steady pressure.");
  sensor3.setup(); //Configure sensor with default settings
  sensor3.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  sensor3.setPulseAmplitudeGreen(0); //Turn off Green LED
}
//*******************************************************************************************//

void loop()
{
  long irValue1 = sensor1.getIR();
  
  if (checkForBeat(irValue1) == true)
  {
    //We sensed a beat!
    long delta = millis() - lastBeat;
    lastBeat = millis();

    beatsPerMinute = 60 / (delta / 1000.0);

    if (beatsPerMinute < 255 && beatsPerMinute > 50)
    {
      rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
      rateSpot %= RATE_SIZE; //Wrap variable

      //Take average of readings
      beatAvg = 0;
      for (byte x = 0 ; x < RATE_SIZE ; x++)
        beatAvg += rates[x];
      beatAvg /= RATE_SIZE;
    }
  }
tcaselect(0);
Serial.print(", BPM=");
Serial.print(beatsPerMinute);
Serial.print(", Avg BPM=");
Serial.print(beatAvg);

tcaselect(1);
long irValue2 = sensor2.getIR();
Serial.print(" ");
perCent1 = irValue1 / irOffset1; //offset provides percent
Serial.print("Oxygen=");
Serial.print(perCent1);
Serial.print("%");

tcaselect(2);
float temperatureF3 = sensor3.readTemperatureF(); //Because I am a bad global citizen
Serial.print(" temperatureF=");
Serial.print(temperatureF3, 4);
Serial.println();
delay(300);
}

...and that's why we ask you to use code tags.
If you click on the "modify" control on your post, you can add them in.

My code is attached

No use to some of us on mobile devices.

I adjusted my above code. Hope that is better

At the end of setup, which device is selected?
At the start of loop, which device is read?

Sensor 3 is the last sensor to initialized:

// Initialize sensor Three
  tcaselect(2);
  if (!sensor3.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  {
    Serial.println("MAX30105 was not found. Please check wiring/power. ");
    while (1);
  }
  Serial.println("Place your index finger on the sensor with steady pressure.");
  sensor3.setup(); //Configure sensor with default settings
  sensor3.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  sensor3.setPulseAmplitudeGreen(0); //Turn off Green LED
}

At the start of the loop the code calculates information to determine heart rate from sensor 1:

void loop()
{
  long irValue1 = sensor1.getIR();
  
  if (checkForBeat(irValue1) == true)
  {
    //We sensed a beat!
    long delta = millis() - lastBeat;
    lastBeat = millis();

    beatsPerMinute = 60 / (delta / 1000.0);

    if (beatsPerMinute < 255 && beatsPerMinute > 50)
    {
      rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
      rateSpot %= RATE_SIZE; //Wrap variable

      //Take average of readings
      beatAvg = 0;
      for (byte x = 0 ; x < RATE_SIZE ; x++)
        beatAvg += rates[x];
      beatAvg /= RATE_SIZE;
    }
  }

Lastly, I select the multiplexer ports again to print the readings:

tcaselect(0);
Serial.print(", BPM=");
Serial.print(beatsPerMinute);
Serial.print(", Avg BPM=");
Serial.print(beatAvg);

tcaselect(1);
long irValue2 = sensor2.getIR();
Serial.print(" ");
perCent1 = irValue1 / irOffset1; //offset provides percent
Serial.print("Oxygen=");
Serial.print(perCent1);
Serial.print("%");

tcaselect(2);
float temperatureF3 = sensor3.readTemperatureF(); //Because I am a bad global citizen
Serial.print(" temperatureF=");
Serial.print(temperatureF3, 4);
Serial.println();
delay(300);

My issue is that all of these readings are being read from sensor 3 instead of each sensor. I believe the issue in my code has something to do with the tcaselect() but I have not been able to determine where. My code seems to not be selecting the correct ports on the multiplexer.

Which library and which multiplexer do you use ? Please give links to them.

I suppose the Sparkfun hardware and libraries are used. That might be a problem.
In the file MAX30105.cpp is struct with arrays used called 'sense'. I think only one 'sense' is used for every class. That means that the library can not be used for multiple MAX30105 ? I'm not sure, perhaps someone else can look into it.

HALOBEAST999, user TheMemberFormerlyKnownAsAWOL was trying to tell you that you do something with a sensor at the beginning of the loop() without setting the multiplexer. The multiplexer was still set for sensor3 at the end of the loop(), yet you try to communicate with sensor1 at the beginning of the loop().
Why don't you organize it in a normal way, for example:

void loop()
{
  // -----------------------------------------
  // sensor1
  // -----------------------------------------
  tcaselect(0);
  
  long irValue1 = sensor1.getIR();
  
  if (checkForBeat(irValue1) == true)
  {
    ...
  
  Serial.print(", BPM=");
  Serial.print(beatsPerMinute);
  Serial.print(", Avg BPM=");
  Serial.print(beatAvg);


  // -----------------------------------------
  // sensor2
  // -----------------------------------------
  tcaselect(1);
  ...


  // -----------------------------------------
  // sensor3
  // -----------------------------------------
  tcaselect(2);
  ...
}

Keep each sensor in its own part of the code.
If you can not make it work, then you could make three test-sketches to test each sensor on its own.