Problem with Arduino Mega and I2C programming

I am facing an issue with the Serial monitor stopping all print statements and the execution of program also in the Mega. I am using the Serial monitor to give inputs to the mega to decide on a case statement to execute which sets PWM values for given pins connected to a motor driver. If I attempt to add code to use an I2C based IMU (MPU6050) into the program, the execution of the program is halted and the motors continue to move in the state it was moving in before the program stopped executing. This only happens if the power supply to the motor driver (through an SMPS) is turned on. The code used for this issue is given below and the issue occurs if all the commented parts are uncommented.

#include <Wire.h>
#include <MPU6050_light.h>

MPU6050 mpu(Wire);

int RPWM_Output1 = 3;
int LPWM_Output1 = 2;

int RPWM_Output2 = 5;
int LPWM_Output2 = 6;

int RPWM_Output3 = 7;
int LPWM_Output3 = 8;

int RPWM_Output4 = 9;
int LPWM_Output4 = 10;

int RPWM_Output5 = 11;
int LPWM_Output5 = 12;

char input;

void setup()
{
  Serial.begin(115200);
  Serial.println("HelloThere");

  byte status = mpu.begin();
  while(status!=0){ }
  
  Serial.println(F("Calculating offsets, do not move MPU6050 1"));
  delay(2000);
  mpu.calcOffsets(true,true);

  pinMode(RPWM_Output1, OUTPUT);
  pinMode(LPWM_Output1, OUTPUT);
  pinMode(RPWM_Output2, OUTPUT);
  pinMode(LPWM_Output2, OUTPUT);
  pinMode(RPWM_Output3, OUTPUT);
  pinMode(LPWM_Output3, OUTPUT);
  pinMode(RPWM_Output4, OUTPUT);
  pinMode(LPWM_Output4, OUTPUT);
  pinMode(RPWM_Output5, OUTPUT);
  pinMode(LPWM_Output5, OUTPUT);

  setMotor(511, LPWM_Output1, RPWM_Output1);
  setMotor(511, LPWM_Output2, RPWM_Output2);
  setMotor(511, LPWM_Output3, RPWM_Output3);
  setMotor(511, LPWM_Output4, RPWM_Output4);
  setMotor(511, LPWM_Output5, RPWM_Output5);
}

void loop()
{
    // mpu.update();
    // Serial.println(mpu.getAngleX());
   
    if(Serial.available()){
        input = Serial.read();
    }
    
  switch(input)
    {
      case 'w':    
      setMotor(511, LPWM_Output1, RPWM_Output1);
      setMotor(600, LPWM_Output2, RPWM_Output2);
      setMotor(422, LPWM_Output3, RPWM_Output3);
      break;

      case 's':
      setMotor(511, LPWM_Output1, RPWM_Output1);
      setMotor(422, LPWM_Output2, RPWM_Output2);
      setMotor(600, LPWM_Output3, RPWM_Output3);
      break;

      case 'a':
      setMotor(333, LPWM_Output1, RPWM_Output1);
      setMotor(600, LPWM_Output2, RPWM_Output2);
      setMotor(600, LPWM_Output3, RPWM_Output3);
      break;

      case 'd':
      setMotor(689, LPWM_Output1, RPWM_Output1);
      setMotor(422, LPWM_Output2, RPWM_Output2);
      setMotor(422, LPWM_Output3, RPWM_Output3);
      break;

      case '[':
      setMotor(600, LPWM_Output1, RPWM_Output1);
      setMotor(600, LPWM_Output2, RPWM_Output2);
      setMotor(600, LPWM_Output3, RPWM_Output3);
      break;

      case ']':
      setMotor(422, LPWM_Output1, RPWM_Output1);
      setMotor(422, LPWM_Output2, RPWM_Output2);
      setMotor(422, LPWM_Output3, RPWM_Output3);
      break;

      case 'q':
      setMotor(322, LPWM_Output1, RPWM_Output1);
      setMotor(542, LPWM_Output2, RPWM_Output2);
      setMotor(542, LPWM_Output3, RPWM_Output3);
      break;

      case 'e':
      setMotor(700, LPWM_Output1, RPWM_Output1);
      setMotor(480, LPWM_Output2, RPWM_Output2);
      setMotor(480, LPWM_Output3, RPWM_Output3);
      break;

      case 'i':
      Serial.println("In case i");
      setMotor(800, LPWM_Output4, RPWM_Output4);
      break;
 
      case 'k':
      Serial.println("In case k");
      setMotor(222, LPWM_Output4, RPWM_Output4);
      break;

      case 'l':
      Serial.println("In case l");
      setMotor(650, LPWM_Output5, RPWM_Output5);
      break;

      case 'j':
      Serial.println("In case j");
      setMotor(372, LPWM_Output5, RPWM_Output5);
      break;

      case 'o':
      Serial.println(" **STOP** ");
      setMotor(511, LPWM_Output1, RPWM_Output1);
      setMotor(511, LPWM_Output2, RPWM_Output2);
      setMotor(511, LPWM_Output3, RPWM_Output3);
      setMotor(511, LPWM_Output4, RPWM_Output4);
      setMotor(511, LPWM_Output5, RPWM_Output5);
    }
    delay(100);
}

void setMotor(int Motorval, int LPWM_Output, int RPWM_Output)
{
  if (Motorval <= 512)
  {
    int reversePWM = -(Motorval - 511) / 2;
    analogWrite(LPWM_Output, 0);
    analogWrite(RPWM_Output, reversePWM);
  }
  else
  {
    int forwardPWM = (Motorval - 512) / 2;
    analogWrite(RPWM_Output, 0);
    analogWrite(LPWM_Output, forwardPWM);
  }
}

To which pins are you connecting SDA and SCL?

Doesn't that IMU work at 3.3V? Then you need a level shifter to connect to the 5V Mega.

The SCL and SDA pins are explicitly shown on the Arduino Mega so connected to those.

The module with the MPU6050 has a built in level shifter and we have tested it individually it works.

Can you show a photo of your project ?
So we can see the level shifter, the wires, the ground wires, the pullup resistors, the cables, the motors, and so on.

The MPU6050_light library is this one: https://github.com/rfetick/MPU6050_light
It is a simple and straightforward library.

If I translate your problem, then your problem is: If using the I2C bus and the motors at the same time, then the sketch halts.
Your motors probably create so much noise, that they completely disturb the I2C bus.

The Wire library can halt a sketch. There is a timeout function: https://www.arduino.cc/reference/en/language/functions/communication/wire/setwiretimeout/
It might help, but if you need that function, then something is very wrong with your I2C bus.

Can you help me on how to debug issues in the I2C bus or the I2C libraries like a Serial.print statement for the I2C library? Also if you know about this how do we build a debug version of the I2C library?
PS: I cannot add a picture of the device as it is proprietary information of an organization, but the MPU 6050 module name is GY-521 and it says in the datasheet that it has an in built level shifter to 3.3 V. Also we have added pull up resistors to SCL and SDA of 3.3kohms.

So it's obviously an electrical interference problem.
How long are the wires between the MPU6050 and the arduino?

I don't see any digital pin assignment for the 1st argument of the analogWrite(arg1, arg2); function quoted above!

There might be about 10 serious problems in your project, and you have fix each and every problem.

The Wire library for the Arduino Mega works. The timeout function that I mentioned can help a little. That is not the problem. A debug version of the Wire library with a Serial.print will not help to fix your project. The I2C bus is not a bus where you can put data in one end and it comes out at the other end. The I2C bus is not a fault tolerant bus, it is supposed to work 100%.

The I2C bus is a weak bus, because the high level is created by the pullup resistors.
It can easily pick up noise from motors.
Motors can create peaks (interference, electro-magnetical noise through air, peaks of current and voltage in wires) throughout the whole project.

Grounding is a craftsmanship on its own.
If the GND wire for the I2C bus gets also some current from the motors, then that current will disturb the I2C bus. The I2C bus has three wires: SDA, SCL and GND, and the GND wire is the most important.

If you use a flat ribbon cable with the SDA wire next to a SCL wire, then the I2C bus stops working. The official standard for the I2C bus gives you 10 cm length for the I2C bus if you do it wrong.

The GY-521 does not have level shifters for SDA and SCL. The Arduino Mega has 10k pullup resistors to 5V. Your MPU-6050 might already be broken. Your MPU-6050 sensor is also a counterfeit chip, it might work or not.
When connecting the GY-521 directly to a Arduino Mega without level shifter, then you lost your noise margin on the I2C bus.
Sometimes there are pullup resistors on the GY-521 board of 2k2. If you have more pullup resistors, then there might be too much pullup.

To be able to help, I would like to know everything with schematics and photos. It is even possible that your project can not work this way. Some say that I see problems everywhere when talking about the I2C bus, but I have not even started yet :scream:

Is GND line considered as a part of "I2C Bus"?

  1. Some people think that SDA and SCL on their own are a "bus", even without GND. But without GND, the signal voltages have no meaning.
  2. The I2C bus is supposed to be used in the same PCB. Things started to get awkward when wires were used with modules. Most beginners think that any GND wire is a perfect ground and a single GND wire can be used for both motors and the I2C bus. I like to express that the GND for the I2C bus should be treated in the same careful way as SDA and SCL.

It is just shorter and easier to say that the GND is part of the I2C bus :smiley:

I am with you to say that I2C Bus a 3-wire bus; where, GND line is the return path for the currents of the SDA/SCL line. However, the vocabulary is: I2C is a two-wire bus (GND line is understood).

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.