How to use 2 I2C and UART simultaneously in ESP32?

2 I2C and 1 UART are not working simultaneously in ESP32

I have a project in which I have to monitor Acceleration of the subject, Location and Pulse + SpO2 of the subject. So, I've written this program to check data from MAX30100 Pulse Oxi sensor and MPU6050 Accelero and Gyroscope sensor using ESP32 -

This program works completely fine. No issues at all.

#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define REPORTING_PERIOD_MS 1000
#define BLYNK_PRINT Serial
#include <Blynk.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>

char auth[] = "*********************";   

// For Pulse sensor
PulseOximeter pox;
float BPM, SpO2;
uint32_t tsLastReport = 0;

// For Accelerometer sensor
const int MPU_addr=0x68;
int16_t accelX, accelY, accelZ, gyroX, gyroY, gyroZ;
float gForceX, gForceY, gForceZ,rotX, rotY, rotZ;

void onBeatDetected()
{
    Serial.println("Beat Detected!");
}

void setup() {
  Serial.begin(115200);

  WiFi.begin("TP-Link", "**********");

  // Wait for wifi to be connected
  uint32_t notConnectedCounter = 0;
  while (WiFi.status() != WL_CONNECTED) {
      delay(100);
      Serial.println("Wifi connecting...");
      notConnectedCounter++;
      if(notConnectedCounter > 50) { // Reset board if not connected after 5s
          Serial.println("Resetting due to Wifi not connecting...");
          ESP.restart();
      }
  }
  Serial.print("Wifi connected, IP address: ");
  Serial.println(WiFi.localIP());
  
  Blynk.begin(auth,"TP-Link_380B", "installation*500");
  Serial.println("Initializing Pulse Oximeter..");
 
    if (!pox.begin())
    {
         Serial.println("FAILED");
         for(;;);
    }
    else
    {
         Serial.println("SUCCESS");
         pox.setOnBeatDetectedCallback(onBeatDetected);
    }
 
    // The default current for the IR LED is 50mA and it could be changed by uncommenting the following line.
        pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
        
  Wire1.begin(32,33,100000); 
  Wire1.beginTransmission(MPU_addr);
  Wire1.write(0x6B);  // PWR_MGMT_1 register
  Wire1.write(0);     // set to zero (wakes up the MPU-6050)
  Wire1.endTransmission(true);
}

void loop()
{
 
  // Reading data from Accelerometer sensor

  Wire1.beginTransmission(MPU_addr);
  Wire1.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire1.endTransmission(false);
  Wire1.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  accelX=Wire1.read()<<8|Wire1.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  accelY=Wire1.read()<<8|Wire1.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  accelZ=Wire1.read()<<8|Wire1.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  
  gyroX=Wire1.read()<<8|Wire1.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  gyroY=Wire1.read()<<8|Wire1.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  gyroZ=Wire1.read()<<8|Wire1.read();

  gForceX = (accelX-2050) / 16384.0;
  gForceY = (accelY-77) / 16384.0; 
  gForceZ = (accelZ-1947) / 16384.0;

  rotX = (gyroX+270) / 131.0;
  rotY = (gyroY-351) / 131.0; 
  rotZ = (gyroZ+136) / 131.0;

  // calculating Amplitute vactor for 3 axis
  float Raw_Amp = pow(pow(gForceX,2)+pow(gForceY,2)+pow(gForceZ,2),0.5);
  int Amp = Raw_Amp * 10;  // Mulitiplied by 10 bcz values are between 0 to 1
  int angleChange = pow(pow(rotX,2)+pow(rotY,2)+pow(rotZ,2),0.5);

  // Reading data from pulseoximeter sensor
  pox.update();
  BPM = pox.getHeartRate();
  SpO2 = pox.getSpO2();

  // Uploading data to Blynk server AND printing data on serial monitor
  if (millis() - tsLastReport > REPORTING_PERIOD_MS)
    {
      Blynk.run();
      
      Blynk.virtualWrite(V3, BPM);
      Blynk.virtualWrite(V4, SpO2);
      

      Serial.println(Amp);
      Serial.println(angleChange);

      Serial.print("Heart rate:");
      Serial.print(BPM);
      Serial.print(" bpm / SpO2:");
      Serial.print(SpO2);
      Serial.println(" %");

      tsLastReport = millis();
    }
}

Now I added GPS, so that I can track the location too. And GPS is working along with accelerometer but Pulse oximeter sensor is not working - Output from that is 0 and the rest of the sensors are producing the expected outputs. Program for that is given below

#include <TinyGPSPlus.h>
#include <HardwareSerial.h>
#include <Arduino.h>
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define REPORTING_PERIOD_MS 1000
#define BLYNK_PRINT Serial
#include <Blynk.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>

char auth[] = "**************";   

// For GPS sensor
float latitude , longitude;
String  latitude_string , longitiude_string;
TinyGPSPlus gps;
WidgetMap myMap(V0);
HardwareSerial SerialGPS(2);

// For Pulse sensor
PulseOximeter pox;
float BPM, SpO2;
uint32_t tsLastReport = 0;

// For Accelerometer sensor
const int MPU_addr=0x68;
int16_t accelX, accelY, accelZ, gyroX, gyroY, gyroZ;
float gForceX, gForceY, gForceZ,rotX, rotY, rotZ;

void onBeatDetected()
{
    Serial.println("Beat Detected!");
}

void setup() {
  Serial.begin(115200);

  WiFi.begin("TP-Link", "***********");

  // Wait for wifi to be connected
  uint32_t notConnectedCounter = 0;
  while (WiFi.status() != WL_CONNECTED) {
      delay(100);
      Serial.println("Wifi connecting...");
      notConnectedCounter++;
      if(notConnectedCounter > 50) { // Reset board if not connected after 5s
          Serial.println("Resetting due to Wifi not connecting...");
          ESP.restart();
      }
  }
  Serial.print("Wifi connected, IP address: ");
  Serial.println(WiFi.localIP());
  
  Blynk.begin(auth,"TP-Link", "**********");

  // Pulse oximeter setup
  Serial.println("Initializing Pulse Oximeter..");
 
    if (!pox.begin())
    {
         Serial.println("FAILED");
         for(;;);
    }
    else
    {
         Serial.println("SUCCESS");
         pox.setOnBeatDetectedCallback(onBeatDetected);
    }
 
    // The default current for the IR LED is 50mA and it could be changed by uncommenting the following line.
        pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
        
  // Accelerometer setup
  Wire1.begin(32,33,100000); 
  Wire1.beginTransmission(MPU_addr);
  Wire1.write(0x6B);  // PWR_MGMT_1 register
  Wire1.write(0);     // set to zero (wakes up the MPU-6050)
  Wire1.endTransmission(true);

 // GPS Setup
 SerialGPS.begin(9600, SERIAL_8N1, 16, 17);
}

void loop()
{

  // Reading data from Accelerometer sensor

  Wire1.beginTransmission(MPU_addr);
  Wire1.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire1.endTransmission(false);
  Wire1.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  accelX=Wire1.read()<<8|Wire1.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  accelY=Wire1.read()<<8|Wire1.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  accelZ=Wire1.read()<<8|Wire1.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)

  gyroX=Wire1.read()<<8|Wire1.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  gyroY=Wire1.read()<<8|Wire1.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  gyroZ=Wire1.read()<<8|Wire1.read();

  gForceX = (accelX-2050) / 16384.0;
  gForceY = (accelY-77) / 16384.0; 
  gForceZ = (accelZ-1947) / 16384.0;

  rotX = (gyroX+270) / 131.0;
  rotY = (gyroY-351) / 131.0; 
  rotZ = (gyroZ+136) / 131.0;

  // calculating Amplitute vactor for 3 axis
  float Raw_Amp = pow(pow(gForceX,2)+pow(gForceY,2)+pow(gForceZ,2),0.5);
  int Amp = Raw_Amp * 10;  // Mulitiplied by 10 bcz values are between 0 to 1

  int angleChange = pow(pow(rotX,2)+pow(rotY,2)+pow(rotZ,2),0.5);

  // Reading data from pulseoximeter sensor

  pox.update();
  BPM = pox.getHeartRate();
  SpO2 = pox.getSpO2();

  // Reading the data from GPS

  if(SerialGPS.available() > 0) {
    if (gps.encode(SerialGPS.read()))
    {
      if (gps.location.isValid())
      {
        latitude = gps.location.lat();
        latitude_string = String(latitude , 6);
        longitude = gps.location.lng();
        longitiude_string = String(longitude , 6);
      }
    }
  }

  // Uploading data to Blynk server AND printing data on serial monitor
  if (millis() - tsLastReport > REPORTING_PERIOD_MS)
    {
      Blynk.run();
      
      Blynk.virtualWrite(V3, BPM);
      Blynk.virtualWrite(V4, SpO2);
      

      Serial.println(Amp);
      Serial.println(angleChange);

      Serial.print("Heart rate:");
      Serial.print(BPM);
      Serial.print(" bpm / SpO2:");
      Serial.print(SpO2);
      Serial.println(" %");

      Blynk.virtualWrite(V0, 1, latitude, longitude, "Location");
      Serial.print("Latitude = ");
      Serial.println(latitude_string);
      Serial.print("Longitude = ");
      Serial.println(longitiude_string);

      tsLastReport = millis();
    }
}

Will you please help me with this. What's wrong with the program.

Which MAX30100 module do you use ? (please give a link to where you bought it).
Which MAX30100 library do you use ? (please give a link to it).
Why do you use two I2C buses ?
What happens if the MPU-6050 is on the normal (first) I2C bus ?

The gyro values are not okay. If you request 14 bytes, then the temperature data is there somewhere in between. You must read that.
See: https://playground.arduino.cc/Main/MPU-6050/#short

First, thanks for your reply

I bought MAX30100 sensor from offline market.
Link for MAX30100 Library - https://github.com/oxullo/Arduino-MAX30100.git

I'm using 2 I2C busses because the pulse oxi sensors library uses wire.begin() i.e. default I2C pins and I couldn't use same pins to read data from the accelerometer

Coming to gyro, then should I take temperature reading as well? and don't use it in the program.

You might be interested in reading the ESP32 API on the differences between portA and portB.

PortB pins, those pins >32 are inputs only.

See: API Reference - ESP32 - — ESP-IDF Programming Guide latest documentation (espressif.com)

If you can not read the MPU-6050 from the normal I2C bus, then something is wrong.
The Oximeter is at I2C address 0x57 and the MPU-6050 is at 0x68. So there is no conflict when they are on the same I2C bus.

Can you make a photo of both modules and tell how they are wired ?

I took a look at that MAX30100 library. I see no problems there, it should work fine.

When requesting 14 bytes with Wire.requestFrom() then the 14 bytes will be read and are held in a buffer inside the Wire library. You can read them with Wire.read(). But you may not skip a value in the middle.

You should read the temperature data before the gyro data. For example with a variable. It does not matter if that variable is used or not:

int16_t temperature = Wire1.read()<<8 | Wire1.read();

Reading the temperature and not using it at all:

Wire1.read();
Wire1.read();

So, can I connect both accelerometer and pulse oxi sensor to default I2C pins i.e. 21, 22 and to get data from accelerometer instead of using Wire1.read() can I use Wire.read() ? And problem is solved?

Right now both these sensors are connected to different pins.

As long as each I2C sensor has its own address. Run the I2C scanner program with your current wiring scheme to make sure all your I2C devices are with unique address.

With the current wiring scheme i.e. pulse oxi and accelerometer connected at different pins, the i2c scanner output is like this

Scanning...
I2C device found at address 0x57
done

0x57 - Address of Pulse oxi sensor

Maybe I should connect both sensors to default pins and check, right?

Right.

If you are actually waiting for a reply to this question. Yes. Do it.

yeah, i did, this is the output

Scanning...
I2C device found at address 0x57
I2C device found at address 0x68
done
Scanning...
I2C device found at address 0x57
I2C device found at address 0x68
done

Now, in the program, if I'm not wrong, I should do this - to get data from accelerometer instead of using Wire1.read() I should use Wire.read() ? , right?

@Koepel @Idahowalker THANKS FOR YOUR HELP TILL NOW!!!!

I HAVE DONE THE ABOVE TASK AND IT WORKS COMPLETELY FINE BUT NOW I'VE ADDED GSM MODULE AND IT WORKS FINE BUT THE PROBLEM IS AGAIN PULSE OXI SENSOR IS NOT WORKING.

NOW I'VE CONNECTED 2 I2C DEVICES - PULSE OXI AND ACCELEROMETER AND 2 UART DEVICES - GSM AND GPS. SO THE PROBLEM IS AGAIN PULSE OXI SENSOR IS NOT WORKING.
WILL YOU PLEASE HELP ME WITH THIS. THIS IS THE FINAL STEP FOR THE PROJECT

HERE IS THE PROGRAM -

#include <TinyGPS++.h>
#include "MAX30100_PulseOximeter.h"
#include <Blynk.h>
#include <HardwareSerial.h>
#include <WiFi.h>
#include <Wire.h>             
#include <BlynkSimpleEsp32.h>
#define REPORTING_PERIOD_MS 1000
#define BLYNK_PRINT Serial

#define rxPin 4
#define txPin 2
HardwareSerial sim800(1);

const int MPU_addr=0x68;
int16_t accelX, accelY, accelZ, gyroX, gyroY, gyroZ;
float gForceX, gForceY, gForceZ,rotX, rotY, rotZ,Tmp;

uint32_t tsLastReport = 0;
PulseOximeter pox;
float BPM, SpO2;

float latitude , longitude;
String  latitude_string , longitiude_string;
char auth[] = "VUjbOe139IPotsyC2Sjx-MQbB54al9s0"; 

WidgetMap myMap(V0); 
WiFiClient client;
TinyGPSPlus gps;
HardwareSerial SerialGPS(2);

void onBeatDetected()
{
    Serial.println("Beat Detected!");
}

void setup()
{
  Serial.begin(115200);
 
  Blynk.begin(auth, "TP-Link_380B", "installation*500");
  
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  
  SerialGPS.begin(9600, SERIAL_8N1, 16, 17);

  sim800.begin(9600, SERIAL_8N1, rxPin, txPin);
  Serial.println("SIM800L serial initialize");
  sim800.print("AT+CMGF=1\r"); //SMS text mode
  delay(1000);
  
  pinMode(19, OUTPUT);
  Serial.print("Initializing Pulse Oximeter..");
 
    if (!pox.begin())
    {
         Serial.println("FAILED");
         for(;;);
    }
    else
    {
         Serial.println("SUCCESS");
         pox.setOnBeatDetectedCallback(onBeatDetected);
    }
 
    // The default current for the IR LED is 50mA and it could be changed by uncommenting the following line.
        pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
    Blynk.virtualWrite(V0, "clr"); 
 
}
void loop()
{
  Wire.beginTransmission(MPU_addr);
 Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
 Wire.endTransmission(false);
 Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
 accelX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
 accelY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
 accelZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
 Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
 gyroX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
 gyroY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
 gyroZ=Wire.read()<<8|Wire.read();

 gForceX = (accelX-2050) / 16384.0;
  gForceY = (accelY-77) / 16384.0; 
  gForceZ = (accelZ-1947) / 16384.0;

  rotX = (gyroX+270) / 131.0;
  rotY = (gyroY-351) / 131.0; 
  rotZ = (gyroZ+136) / 131.0;

  // calculating Amplitute vactor for 3 axis
 float Raw_Amp = pow(pow(gForceX,2)+pow(gForceY,2)+pow(gForceZ,2),0.5);
 int Amp = Raw_Amp * 10;  // Mulitiplied by 10 bcz values are between 0 to 1
 //Serial.println(Amp);

 angleChange = pow(pow(rotX,2)+pow(rotY,2)+pow(rotZ,2),0.5);
  
  if (SerialGPS.available() > 0)
  {
    if (gps.encode(SerialGPS.read()))
    {
      if (gps.location.isValid())
      {
        latitude = gps.location.lat();
        latitude_string = String(latitude , 6);
        longitude = gps.location.lng();
        longitiude_string = String(longitude , 6);
      }
    }  
    }

    pox.update();
    
    BPM = pox.getHeartRate();
    SpO2 = pox.getSpO2();

    if (!sim800.available()){            //Displays on the serial monitor if there's a communication from the module
    //Serial.write(sim800l.read()); 
    Serial.println("SIM800L INITIALISATION FAILED!!!");
    for(;;);
  }
    
    if (millis() - tsLastReport > REPORTING_PERIOD_MS)
    {
      Blynk.run();
      Blynk.virtualWrite(V0, 1, latitude, longitude, "Location");
      Blynk.virtualWrite(V3, BPM);
      Blynk.virtualWrite(V4, SpO2);

      Serial.println(Amp);
      Serial.println(angleChange);

      Serial.print("Heart rate:");
    Serial.print(BPM);
    Serial.print(" bpm / SpO2:");
    Serial.print(SpO2);
    Serial.println(" %");

    Serial.print("Latitude = ");
        Serial.println(latitude_string);
        Serial.print("Longitude = ");
        Serial.println(longitiude_string);

    tsLastReport = millis();
    }
  
}

void sendSMS()
{
  Serial.println("Sending SMS...");               //Show this message on serial monitor
  //sim800l.print("AT+CMGF=1\r");                   //Set the module to SMS mode
  delay(100);
  sim800.print("AT+CMGS=\"+919182932597\"\r");  //Your phone number don't forget to include your country code, example +212123456789"
  delay(500);
  if (!sim800.print("SIM800l is working")){Serial.println("SIM800L INITIALISATION FAILED!!!");
    for(;;);}
  //This is the text to send to the phone number, don't make it too long or you have to modify the SoftwareSerial buffer
  delay(500);
  sim800.print((char)26);// (required according to the datasheet)
  delay(500);
  sim800.println();
  Serial.println("Text Sent.");
  delay(500);
}

Can you tell which pulse Oximeter module you have ? and how is it connected ?
Are there other pins connected to the Oximeter module ?

In the library of the Oximeter is code to return zero when the tracking is lost. I don't understand the condition when that happens. Maybe the Oximeter update() function has to be called more often.

@Koepel PULSE OXI SENSOR - MAX30100, SENSOR'S PINS ARE CONNECTED TO DEFAULT I2C PINS - 21,22 AND SAME I2C PINS ARE BEING USED FOR ACCELEROMETER.

There are a number of MAX30100 modules. Which module is it ? Is it powered with 5V or 3.3V ?

@Koepel 3.3V AND THIS IS THE MODULE I'M USING - https://github.com/oxullo/Arduino-MAX30100.git

Which module is it ? This one or this one ?

@Koepel The first one i.e. Pulse Oximeter SpO2 and Heart-Rate Sensor Module - I2C - MAX30100 [5337] : Sunrom Electronics

That MAX30100 module is not a good design. On the module are pullup resistors of 4k7 to 1.8V.

I think that the MAX30100 library want to be able to track the heartbeat and has a timeout. I suppose that the GPS functions take some time to read the serial data.

This is the explanation for TinyGPS++ : http://arduiniana.org/libraries/tinygpsplus/
Your code does this:

if (SerialGPS.available() > 0)
  {
    if (gps.encode(SerialGPS.read()))
    {
      if (gps.location.isValid())

It is possible to use the 'encode()' all the time and the 'isValid()' when the heartbeat is not need to know. Is there a moment that the heartbeat is not measured.