Does I2C conflicts with Timer1,Timer2 interrupts?

I’m using IR sensors to measure RPM and with the RPM measurements I’m changing the angle of two Servo motor. Currently I have successfully done it with the following method,

I have used Timer1 interrupts for measuring RPM with IR sensor and Timer2 for controlling the servo (ServoTimer2), to remove any conflict between two interrupts. And this approch is working so far.

Problem:
Now I needed to measure angle and I used mpu6050 gyroscope sensor and read from I2C. But after few seconds of program start, the serial monitor was stopping.

  1. What may the issue for this?
  2. Does I2C use a Timer interrupt? If so what is it?
  3. How can I solve this issue?

Code with mpu6050:

#include <LCD.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <TimerOne.h>
//#include <Servo.h>
#include "ServoTimer2.h"

ServoTimer2 servo_front;
ServoTimer2 servo_rear;
const int servo_pin_f = 9;
const int servo_pin_r = 7;
//RPM
//-------------------------------------------------------------------
// RPM values to track
const int IRSensorPin_A = 3;  // the number of the IR sensor input pin
int inputState_A;                          // the current state from the input pin
int lastInputState_A = LOW;        // the previous InputState from the input pin
long lastDebounceTime_A = 0;   // the last time the output pin was toggled
long debounceDelay_A = 5;        // the debounce time; increase if the output flickers
long time_A;
long endTime_A;
long startTime_A;
int RPM_A = 0;
float lnTime_A = 0;

// RPM values to track
const int IRSensorPin_B = 4;  // the number of the IR sensor input pin
int inputState_B;                          // the current state from the input pin
int lastInputState_B = LOW;        // the previous InputState from the input pin
long lastDebounceTime_B = 0;   // the last time the output pin was toggled
long debounceDelay_B = 5;        // the debounce time; increase if the output flickers
long time_B;
long endTime_B;
long startTime_B;
int RPM_B = 0;
float lnTime_B = 0;
// ---------------------------------------------------------------

//LCD
//---------------------------------------------------------------
//LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7); // 0x27 is the I2C bus address for an unmodified backpack
// ---------------------------------------------------------------

//<SPEEDS AND GEAR>-------------------------------------------------------
const int crankRpmLim = 0; //Minimum Speed of Crank to change gear
int currentGear   = 1;
int matchingGear  = 1;
int currentFrontAngle   = 0; //TODO
int currentRearAngle  = 0; //TODO

int gearAnglesFront[11] = {
  0, 0, 20, 40, 60, 80, 
  100, 120, 140, 150, 160  
};
int gearAnglesRear[11]  = {
  0, 0, 20, 40, 60, 80, 
  100, 120, 140, 150, 160 
};
int gearSpeedLims[11]     = {
  0, 100, 400, 600, 900, 1200,
  2000, 2350, 2400, 2450, 2500
};
//</SPEEDS AND GEAR>------------------------------------------------------

//<GYRO>------------------------------------------------------------------
const int MPU_addr=0x68; int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
int minVal=265; int maxVal=402;
double x; double y; double z;
//</GYRO>------------------------------------------------------------------


void setup() {
  pinMode(IRSensorPin_A, INPUT);
  pinMode(IRSensorPin_B, INPUT);
  servo_front.attach(servo_pin_f);
  servo_rear.attach(servo_pin_r); 

  Serial.begin(9600);

  //<GYRO>
  Wire.begin(); 
  Wire.beginTransmission(MPU_addr); 
  Wire.write(0x6B); 
  Wire.write(0); 
  Wire.endTransmission(true); 

  delay(2000);

  endTime_A = 0;
  endTime_B = 0;
  Timer1.initialize(1000000);  // Set the timer to 60 rpm, 1,000,000 microseconds (1 second)
  Timer1.attachInterrupt(timerIsr);  // Attach the service routine here

  //----------------LCD-------------------
  // lcd.begin (16,4); // for 16 x 4 LCD module
  // lcd.setBacklightPin(3,POSITIVE);
  // lcd.setBacklight(HIGH);
  //
}


//<GYRO>---------------------------------------------------------
void updateGyro(){ 
  Wire.beginTransmission(MPU_addr); 
  Wire.write(0x3B); 
  Wire.endTransmission(false); 
  Wire.requestFrom(MPU_addr,14,true); 
  AcX=Wire.read()<<8|Wire.read(); 
  AcY=Wire.read()<<8|Wire.read(); 
  AcZ=Wire.read()<<8|Wire.read(); 
  //int xAng = map(AcX,minVal,maxVal,-90,90); 
  int yAng = map(AcY,minVal,maxVal,-90,90); 
  int zAng = map(AcZ,minVal,maxVal,-90,90);

  x= RAD_TO_DEG * (atan2(-yAng, -zAng)+PI);

  Serial.print("AngleX= "); Serial.println(x); 
}
//</GYRO>---------------------------------------------------------

//<GearFunctions>---------------------------------------------------------
int pwm_map(int angle)
{
  int pulse_wide, analog_value;
  pulse_wide = map(angle, 0, 180, 1500, 2500);
  return pulse_wide;
}

void setServoF(int ang){
	servo_front.write(pwm_map(ang)); 
}
void setServoR(int ang){
	servo_rear.write(pwm_map(ang));
}

int getMatchingGear(float currentVelocity) {
  if (currentVelocity < gearSpeedLims[1])       {return 1;}
  else if (currentVelocity < gearSpeedLims[2])  {return 2;}
  else if (currentVelocity < gearSpeedLims[3])  {return 3;}
  else if (currentVelocity < gearSpeedLims[4])  {return 4;}
  else if (currentVelocity < gearSpeedLims[5])  {return 5;}
  else                                          {return 6;}
}

void changeGear(int gearNum)
{
    Serial.print("Current Gear = ");
    Serial.print(currentGear);
    Serial.print("\tMatching Gear = ");
    Serial.print(matchingGear);
    Serial.print("\tChange To = ");
    Serial.println(gearNum);
    
    setServoF(gearAnglesFront[gearNum]);
    setServoR(gearAnglesRear[gearNum]);
    currentFrontAngle 	= gearAnglesFront[gearNum];
    currentRearAngle 	= gearAnglesRear[gearNum]; 
    currentGear = gearNum;
}

void updateGear(int speed){
  //float velocity = rpmToVelocity(RPM_B);
  // if(RPM_A < crankRpmLim){
  //   return;
  // }
  matchingGear = getMatchingGear(speed);
  if(currentGear != matchingGear){
      changeGear(matchingGear);
  }
}
//</GearFunctions>---------------------------------------------------------



//<RpmFunctions>---------------------------------------------------------------
void Update_rpm_A() {
  time_A = millis();
  int currentSwitchState_A = digitalRead(IRSensorPin_A);

  if (currentSwitchState_A != lastInputState_A) {
    lastDebounceTime_A = millis();
  }

  if ((millis() - lastDebounceTime_A) > debounceDelay_A) {
    if (currentSwitchState_A != inputState_A) {
      inputState_A = currentSwitchState_A;
      if (inputState_A == LOW) {
        calculateRPM_A(); // Real RPM from sensor
      }
    }
  }
  lastInputState_A = currentSwitchState_A;
}

void calculateRPM_A() {
  startTime_A = lastDebounceTime_A;
  lnTime_A = startTime_A - endTime_A;
  RPM_A = 60000 / (startTime_A - endTime_A);
  endTime_A = startTime_A;
}

void Update_rpm_B() {
  time_B = millis();
  int currentSwitchState_B = digitalRead(IRSensorPin_B);

  if (currentSwitchState_B != lastInputState_B) {
    lastDebounceTime_B = millis();
  }

  if ((millis() - lastDebounceTime_B) > debounceDelay_B) {
    if (currentSwitchState_B != inputState_B) {
      inputState_B = currentSwitchState_B;
      if (inputState_B == LOW) {
        calculateRPM_B(); // Real RPM from sensor
      }
    }
  }
  lastInputState_B = currentSwitchState_B;
}

void calculateRPM_B() {
  startTime_B = lastDebounceTime_B;
  lnTime_B = startTime_B - endTime_B;
  RPM_B = 60000 / (startTime_B - endTime_B);
  endTime_B = startTime_B;
}

// Custom ISR Timer Routine
// Timer set to rpm, see above
void timerIsr()
{
  // Print RPM every second
  // RPM based on timer
  Serial.println("---------------");
  time_A = millis() / 1000;
  time_B = millis() / 1000;
  Serial.print(time_A);
  Serial.print(" RPM_A: ");
  Serial.println(RPM_A);
  Serial.print(time_B);
  Serial.print(" RPM_B: ");
  Serial.println(RPM_B);
  updateGyro();
  updateGear(RPM_A);

  delay(250);
  RPM_A = 0;
  delay(250);
  RPM_B = 0;
}
//</RpmFunctions>----------------------------------------------


void loop(){
  Update_rpm_A();
  Update_rpm_B();
}
// ---------------------------------------------------------------

Note: This is my first post on this forum and I’m a beginner to Arduino. Please forgive and advice about any mistake.

Can you please try changing this line: Wire.endTransmission(false); to this: Wire.endTransmission(false); Wire.endTransmission();

Because there is no other I2C Master in the Bus who might acquire the Bus, it it better to bring STOP condition on the Bus.

Edit: In view of Post#2.

GolamMostafa:
Can you please try changing this line: Wire.endTransmission(false); to this: Wire.endTransmission(false);.

Is there something very subtle that I'm missing between Wire.endTransmission(false); and Wire.endTransmission(false);?

rainbow_rings:
Is there something very subtle that I'm missing between Wire.endTransmission(false); and Wire.endTransmission(false);?

Thank you for the remark; I have edited my Post#1. (Copy and paste makes life miserable very often!)

You can always look at the source code to see how things work, you have all the Arduino runtime code.

Don't do Serial prints in an ISR.

Worse still, in that ISR:

  • trying to call another function (NEVER do this: set a flag and let loop() take care of it)
  • two times delay(250) (which afaik relies on timer interrupts, yet in an ISR interrupts are disabled).
    That all is a recipe for disaster.

ISRs are peculiar things. Try to do as little as possible inside the ISR, and exit the function fast - really fast. What you can do are things like: record a value, increase a counter or set a flag. All the heavy lifting is to be done in the regular flow of your program, i.e. in loop(). There you read that flag and act upon it, or at set intervals check the counter, or whatever you want to do with the data.

Remember to declare all global variables written to by the ISR volatile.