I2C - Noise Causing Issues?

Hi All,
Long time reader, first time poster so please forgive me if things aren't posted correctly. I'll try my best and to provide as much detail as possible. Thanks for all of your other posts, they have really helped me out.

Essentially, the project I'm working on involves an Adruino Mega controlling stepper motors. The code I have written works as it should so I am confident that I don't have a programming issue. Currently this is a prototype running 4 stepper motors with the actual project eventually controlling around 40 motors. When I have 2 motors connected, things usually work great, however when I add in the second two motors the keypad/I2C expander starts sending back random digits to my input field on the screen. Not helpful as you can imagine as I'm trying to input what step the motors should go to.

Hardware breakdown:
Controller: Arduino Mega
Motor Drivers: ISD02
Motors: Nema 17
Power Supply: LRS-350-24 - 24V 350W - Mean Well
Display: 20x4 LCD with I2C Backpack - Sunfounder
Keypad: 16 Button Keypad - DFRobot
I2C Expander: PCF8574 - Robojax

Basic Wiring:

  1. Vcc of Motor Drivers are connected to Vcc of Arduino Mega
  2. Step/Direction inputs of Motor Drivers are connected to outputs on the Arduino Mega
  3. Actual Motor Power that runs through the Motor Drivers is from the 24V power supply
  4. 330 Ohm resistor is wired in series with the SDA (D20) and SCL (D21) lines
  5. 1.7 kOhm pull up resistor connected from Arduino 5V to SDA (D20) and SCL (D21) lines
  6. Vcc, GND, SDA (D20) and SCL (D21) are sent to the controller where they are split between the Display and the I2C expander
  7. Keypad is connected to the I2C Expander
  8. Arduino is powered by a 9V DC adapter

The display works perfectly, but as mentioned before, where the keys show on the screen from the keypad, random keys will show up without pressing anything. Could this be caused by noise from the motors? Is there a way to solve it?

Things I have tried:

  1. Increasing/decreasing pull-up resistor size
  2. All connectors to motors/controller have been replaced
  3. Added capacitor (100pF) across the Arduino power supply to eliminate/help reduce any power ripples
  4. Tried adjusting Wire.setClock speeds to see if that makes a difference
  5. Completely disassembled project and reassembled to eliminate wiring issues

Thinking of trying next:

  1. Unplugging keypad to see if the issue is being caused by the I2C Expander or Keypad (I doubt it is the keypad but I'm grasping at straws at this point)
  2. Replacing the I2C Expander by Robojax with this was from SX1509 I2C Breakout from Sparkfun.

Has anyone seen this before or heard of it happening? Is the PCF8574 expander more susceptible to noise than the I2C backpack on the display?

Any feedback or suggestions would be greatly appreciated.

Thanks,

  • Jamie

This is always difficult to diagnose , but things such as layout and detail of the wiring can make a big difference . You could really do with a scope to look for noise etc.
A proper drawing would help, length of cables , how connected , etc. For the keyboard , do the connections have pull up /down resistor so the input is not open circuit when a key is not pressed ? .
There may also be things you can do in software , such as looking for a key press , then checking in say 50mS to see if it’s still pressed before you decide it’s valid. ( debounce ) -a noise spike would then be ignored.

I’d post your software up too

Sounds like a power issue or EMI. Please post pictures and wiring diagram.

Here is the current code running on the Arduino.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

#include <Keypad.h>
#include <Keypad_I2C.h>
int i2caddress = 0x20;

int TILT1_1_DIR_PIN = 22;
int TILT1_1_STEP_PIN = 23;

int TILT1_2_DIR_PIN = 24;
int TILT1_2_STEP_PIN = 25;

int TILT1_3_DIR_PIN = 26;
int TILT1_3_STEP_PIN = 27;

int TILT1_4_DIR_PIN = 28;
int TILT1_4_STEP_PIN = 29;

int TILT_LIMIT_1 = 50;

int Calibrate = 0;
int TILT_1_STEPS;

int value_tilt = 55;
int value_height = 0;
int num;
int GOTO_TILT = Calibrate;
int target_pos;
int i = 16;
int j = 9;
char menu;
char setting_1[20];
char setting_2[20];

const byte ROWS = 4; // Four rows

const byte COLS = 4; // Four columns

// Define the Keymap

char keys[ROWS][COLS] =

{


  {'1', '2', '3', 'A'},


  {'4', '5', '6', 'B'},


  {'7', '8', '9', 'C'},


  {'*', '0', '#', 'D'}

};

// Keypad pins connected to the I2C-Expander pins P0-P6
byte rowPins[ROWS] = {0, 1, 2, 3}; // connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 5, 6, 7};    // connect to the column pinouts of the keypad


// Create the Keypad

Keypad_I2C Keypad_I2C( makeKeymap(keys), rowPins, colPins, ROWS, COLS, i2caddress);

void setup() {
Serial.begin(9600);
  pinMode(TILT1_1_DIR_PIN, OUTPUT);
  pinMode(TILT1_1_STEP_PIN,  OUTPUT);

  pinMode(TILT1_2_DIR_PIN,  OUTPUT);
  pinMode(TILT1_2_STEP_PIN,  OUTPUT);

  pinMode(TILT1_3_DIR_PIN,  OUTPUT);
  pinMode(TILT1_3_STEP_PIN,  OUTPUT);

  pinMode(TILT1_4_DIR_PIN,  OUTPUT);
  pinMode(TILT1_4_STEP_PIN,  OUTPUT);

  pinMode(TILT_LIMIT_1, INPUT);

  Keypad_I2C.begin();
  lcd.begin (20, 4);
  lcd.init();
  lcd.backlight();

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Enter Calibration");
  lcd.setCursor(0,3);
  lcd.print("Press # to continue");
  lcd.setCursor(0,1);
  lcd.print("Number:  ");

 int num = 0;
  char key = Keypad_I2C.getKey();
  while (key != '#')
  {
    switch (key)
    {
      case NO_KEY:
        break;

      case '0': case '1': case '2': case '3': case '4':
      case '5': case '6': case '7': case '8': case '9':
        lcd.setCursor (j, 1);
        lcd.print(key);
        j++;
        num = num * 10 + (key - '0');
        break;

      case '*':
        num = 0;
        j = 9;
        lcd.clear();
        break;

    }
    key = Keypad_I2C.getKey();
  }
  j = 9;
  Calibrate = num;
  
  lcd.clear();
  lcd.setCursor(0,1);
  lcd.print("   Calibrating...   ");

  while (digitalRead(TILT_LIMIT_1)) {  // Do this until the switch is activated
    digitalWrite(TILT1_1_DIR_PIN, LOW); // (HIGH = anti-clockwise / LOW = clockwise)
    digitalWrite(TILT1_2_DIR_PIN, HIGH);
    digitalWrite(TILT1_3_DIR_PIN, LOW);
    digitalWrite(TILT1_4_DIR_PIN, HIGH);

    digitalWrite(TILT1_1_STEP_PIN, HIGH);
    digitalWrite(TILT1_2_STEP_PIN, HIGH);
    digitalWrite(TILT1_3_STEP_PIN, HIGH);
    digitalWrite(TILT1_4_STEP_PIN, HIGH);
    delayMicroseconds(600);                       // Delay to slow down speed of Stepper

    digitalWrite(TILT1_1_STEP_PIN, LOW);
    digitalWrite(TILT1_2_STEP_PIN, LOW);
    digitalWrite(TILT1_3_STEP_PIN, LOW);
    digitalWrite(TILT1_4_STEP_PIN, LOW);
    delayMicroseconds(600);
  }

  while (!digitalRead(TILT_LIMIT_1)) { // Do this until the switch is not activated
    digitalWrite(TILT1_1_DIR_PIN, HIGH);
    digitalWrite(TILT1_2_DIR_PIN, LOW);
    digitalWrite(TILT1_3_DIR_PIN, HIGH);
    digitalWrite(TILT1_4_DIR_PIN, LOW);

    digitalWrite(TILT1_1_STEP_PIN, HIGH);
    digitalWrite(TILT1_2_STEP_PIN, HIGH);
    digitalWrite(TILT1_3_STEP_PIN, HIGH);
    digitalWrite(TILT1_4_STEP_PIN, HIGH);
    delayMicroseconds(1000);                       // More delay to slow even more while moving away from switch

    digitalWrite(TILT1_1_STEP_PIN, LOW);
    digitalWrite(TILT1_2_STEP_PIN, LOW);
    digitalWrite(TILT1_3_STEP_PIN, LOW);
    digitalWrite(TILT1_4_STEP_PIN, LOW);
    delayMicroseconds(1000);
  }

  TILT_1_STEPS = Calibrate;// Reset position variable to position
  value_tilt = Calibrate;
  if (TILT_1_STEPS == Calibrate) {
    lcd.clear();
    lcd.setCursor (0, 1);
    lcd.print ("    Calibration   ");
    lcd.setCursor (0, 2);
    lcd.print("      Complete   ");
    delay(2000);
    lcd.clear();
  }

  lcd.setCursor ( 0, 0 ); // go to the top left corner
  lcd.print("To set Tilt,"); // write this string on the top row
  lcd.setCursor ( 0, 1 ); // go to the 2nd row
  lcd.print("press 'A'"); // pad string with spaces for centering

}

void loop() {
  Serial.print("Void loop entered \n");
  tooFar();
  pickOne();
}


void tooFar() {
  Serial.print("tooFar loop entered \n");
  if (value_tilt <= Calibrate) {
  while ( TILT_1_STEPS >= 0 && TILT_1_STEPS <= Calibrate && TILT_1_STEPS < value_tilt)
  {
    digitalWrite(TILT1_1_DIR_PIN, HIGH);
    digitalWrite(TILT1_2_DIR_PIN, HIGH);
    digitalWrite(TILT1_3_DIR_PIN, HIGH);
    digitalWrite(TILT1_4_DIR_PIN, HIGH);

    if (TILT_1_STEPS < value_tilt)

    {


      digitalWrite(TILT1_1_STEP_PIN, HIGH);
      digitalWrite(TILT1_2_STEP_PIN, HIGH);
      digitalWrite(TILT1_3_STEP_PIN, HIGH);
      digitalWrite(TILT1_4_STEP_PIN, HIGH);

      delayMicroseconds(1000);

      digitalWrite(TILT1_1_STEP_PIN, LOW);
      digitalWrite(TILT1_2_STEP_PIN, LOW);
      digitalWrite(TILT1_3_STEP_PIN, LOW);
      digitalWrite(TILT1_4_STEP_PIN, LOW);

      delayMicroseconds(1000);
      TILT_1_STEPS++;

    }
    else;
  }


  while (TILT_1_STEPS >= 0 && TILT_1_STEPS <= Calibrate && TILT_1_STEPS > value_tilt)
  {
    digitalWrite(TILT1_1_DIR_PIN, LOW);
    digitalWrite(TILT1_2_DIR_PIN, LOW);
    digitalWrite(TILT1_3_DIR_PIN, LOW);
    digitalWrite(TILT1_4_DIR_PIN, LOW);

    if (TILT_1_STEPS > value_tilt)

    {
      digitalWrite(TILT1_1_DIR_PIN, LOW);
      digitalWrite(TILT1_2_DIR_PIN, LOW);
      digitalWrite(TILT1_3_DIR_PIN, LOW);
      digitalWrite(TILT1_4_DIR_PIN, LOW);

      digitalWrite(TILT1_1_STEP_PIN, HIGH);
      digitalWrite(TILT1_2_STEP_PIN, HIGH);
      digitalWrite(TILT1_3_STEP_PIN, HIGH);
      digitalWrite(TILT1_4_STEP_PIN, HIGH);

      delayMicroseconds(1000);

      digitalWrite(TILT1_1_STEP_PIN, LOW);
      digitalWrite(TILT1_2_STEP_PIN, LOW);
      digitalWrite(TILT1_3_STEP_PIN, LOW);
      digitalWrite(TILT1_4_STEP_PIN, LOW);
      delayMicroseconds(1000);
      TILT_1_STEPS--;
    }
    else;

  }
}}

int GetNumber ()
{
  Serial.print("GetNumber loop entered \n");
  int num = 0;
  char key = Keypad_I2C.getKey();
  while (key != '#')
  {
    switch (key)
    {
      case NO_KEY:
        break;

      case '0': case '1': case '2': case '3': case '4':
      case '5': case '6': case '7': case '8': case '9':
        lcd.setCursor (i, 0);
        lcd.print(key);
        i++;
        num = num * 10 + (key - '0');
        break;

      case '*':
        num = 0;
        i = 16;
        lcd.clear();
        break;

    }
    key = Keypad_I2C.getKey();
  }
  i = 16;
  value_tilt = num;
  return num;
}

void pickOne() {
  Serial.print("pickOne entered \n");
  char whatdo = Keypad_I2C.getKey();

  while (whatdo != '*')
  {
    switch (whatdo)
    {
      case NO_KEY:
        break;

      case 'A':
        lcd.clear();
        lcd.setCursor (0, 2);
        lcd.print("Press # to confirm");
        lcd.setCursor (0, 0);
        lcd.print ("Set tilt to:");
        GetNumber();
        tooFar();
        lcd.clear();
        lcd.setCursor (0, 0);
        sprintf(setting_1, "Tilt set to: %i", value_tilt);
        lcd.print(setting_1);
        lcd.setCursor (0, 1);
        lcd.print("To set:");
        lcd.setCursor(0, 2);
        lcd.print("Tilt press 'A'");
        break;

      case 'C':
        value_tilt = 0;
        value_height = 0;
        break;


      case 'D':
        lcd.clear();
        lcd.setCursor (0, 0);
        sprintf(setting_1, "Tilt set to: %i", value_tilt);
        lcd.print(setting_1);
        lcd.setCursor (0, 1);
        break;


      case '*':
        value_tilt = 0;
        value_height = 0;
        break;
    }
    whatdo = Keypad_I2C.getKey();
  }

}

I will try and get an up to date wiring diagram done.

Hammy - Right now the keypad is connected directly to the I2C expander. How would I go about adding in the pull up/pull down resistors and do I need to change the code for this? How would I add a check into my code for the proposed 50mS?

Thanks All!

  • Jamie

Google "i2c pull up"
You must have pullup resistors on the I2C lines or you will get random data. 4.7K is sufficient for most Arduino I2C applications.

Also, a wiring diagram (not a pretty (useless) Fritzing picture, please) would go a long way toward understanding what you have. I am puzzled by your power-supply.

I've included a quick power drawing. Please let me know if something better is needed.

SteveMann:
You must have pullup resistors on the I2C lines or you will get random data. 47K is sufficient for most Arduino I2C applications.

Steve - please see my original post where I say that I am using pull up resistors.

jbeemer:
5. 1.7 kOhm pull up resistor connected from Arduino 5V to SDA (D20) and SCL (D21) lines

Thanks,

  • Jamie

I created a better diagram. Hopefully this one is more helpful than my first one. I tried to keep it as neat as possible.

  • Jamie

jbeemer:
I created a better diagram. Hopefully this one is more helpful than my first one. I tried to keep it as neat as possible.

  • Jamie

This is actually a pretty good drawing. The 1.7K pullups may be too strong. I2C works by the devices pulling the SDA and SCL lines to ground and 1.7K pullups may not let them pull the lines to ground when they need to, giving random data. Try 4.7K resistors. I don't think the series 300Ω resistors do anything.

Thanks for the feedback Steve. I haven't seen a lot of drawings on here so I wasn't 100% sure what people were looking for. Glad it was decent.

I will pull the 300 Ohm resistors. As I was trying to troubleshoot, I found a post where someone said it could help, but obviously hasn't.

I tried 4.7kohm resistors before and still had the same issue, however, I will swap the 1.7kohm resistors to 4.7kohm and try them again and report back.

Thanks again,

  • Jamie

Steve - I got rid of the 300 ohm resistors and changed the pull-up resistors to 4.7kohm. The issue is still there. Thoughts?

Thanks,

  • Jamie

1k7 is the minimum combined value of the common (old) I2C standard.

A Mega already has (physical) 10k pull up resistors, the other modules might have 10k or 4k7.
You must calculate that combined resistance, so you can stay above 1k7 below 3mA pull up current.
It should be clear that adding 1k7 to the maybe already ~3k present is adding up too low.

This is not a big deal if all of your devices are of the newer FastMode+ standard (30mA).

If you got problems with I2C, then it's could be wiring. Too long, too messy, crosstalk, etc.
Post a 'real' picture of the setup.
Leo..

Hi Leo,
Thanks for looking at this. I'm not 100% clear on what resistance I should be adding then. Could you please assist me in solving this? Am I considering the built in 10k and the pull-up resistor to be in parallel?
Sorry very new to the whole "pull up resistor" concept.

I will try and get a 'real' photo up soon.

Thanks,

  • Jamie

Real world photos. I apologize that the lighting isn't any better. Let me know if I need to retake them.

Photo 1 - How the project sits with duct covers on
Photo 2 - Duct covers removed
Photo 3 - Picture of drivers and connectors on project enclosure

NOTE: In photos 1 and 2 - The two sets of "loose" twisted pair are what the power (Vcc and Gnd on one pair) and the I2C signal (SDA and SCL on other pair) are on. I had previously taken them out of the ducts thinking that the power wires were causing the interferance.

Thanks,

  • Jamie

jbeemer:
...and the I2C signal (SDA and SCL on other pair...

Don't pair SDA with SCL.
The signals will be 'fighting' each other, and that will reduce possible transmission length.
Can pair SDA with GND and SCL with 5volt.

Pull up strength (resistor values) needed depends on wire capacitance (length/type).
So what is the total length of I2C twisted pair.
More than 5meter of Cat-5 twisted pair @default speed (100kHz) will give problems.

This all might have nothing to do with I2C though, but with supply or wire cross-talk.
At what stage did you start seeing the problems.
I suppose you did build in stages, and tested between stages.
If not, you must peel it back, and start over.
Leo..

Sounds good. I will swap two of the wires and see if that helps the case.

The idea was to go about 50 feet in the end, but I know that I will likely need a pair of buffers to do that. If I could get 6 feet stable for the moment that would be ideal. Right now when I plug the controller directly into the enclosure (about 4 inches) I have problems.

I had everything working with 2 motors no problem. When I added in the other 2 I started to see feedback which would tell me there is a good possibility that it is a power issue which is why I pulled the I2C lines out of the wire duct to see if that helped or not, which it didn't really.

I will try and swap two of the wires as mentioned and report back.

Thanks,

  • Jamie

Okay so I swapped two of the wires and now I have nothing on my LCD screen. Well, I have the rows of blocks but that is it. I did a beep test and everything is wired correctly.

To be fair, I think the issue occurred before I switched the wires. I had hook up a 30 foot or so CAt5 cable to see if it would do it (which it did not - not surprising) but the only thing that came up were the blocks. I haven't been able to get anything up since. Did I fry something by doing that?

If my testing has showed me anything, I believe that the Arduino won't run the program until it has found all of the I2C devices. Could the I2C backpack on the LCD screen be blown? I did load the "blink" sketch onto the Arduino and it runs fine so I believe my Arduino is safe.

Thoughts anyone?

Thanks,

  • Jamie

jbeemer:
The idea was to go about 50 feet in the end, but I know that I will likely need a pair of buffers to do that. If I could get 6 feet stable for the moment that would be ideal. Right now when I plug the controller directly into the enclosure (about 4 inches) I have problems.

50feet between what and what?
If you are trying to communicate with I2C over 50ft, then forget it. I2C was designed as a communication system between components ON a PCB, not even 30cm.
Is this diagram still current?


Where is the gnd between the Mega and the stepper controller?
Thanks.. Tom... :slight_smile:

Hi,
Have you got I2C wires sharing the same path as the power and stepper control and current?

Keep your stepper power and controller wires away from any input and I2C wires that are associated with the Mega.
ALL the signal and stepper power current is of SQUAREWAVE form, this produces a great amount of electromagnetic interference, especially anything with a significant amount of current such as wiring used for the steppers and drivers.


You have four drivers, that can be a lot of EMC.

Tom.... :slight_smile:

Hi Tom,
50 feet between the arduino and the LCD screen/keypad, but right now I will settle for 6ft if I can get it. This is a prototype and the communication method on the actual project will be different.

That diagram is still current except the 300 ohm resistors have been removed and the pull up resistors are now 4.7k.

There is no ground that travels between the Mega and the motor driver. It uses Vcc and the a digital out pin either high or low.

TomGeorge:
Have you got I2C wires sharing the same path as the power and stepper control and current?

Mentioned in my previous post with the photos:

jbeemer:
NOTE: In photos 1 and 2 - The two sets of "loose" twisted pair are what the power (Vcc and Gnd on one pair) and the I2C signal (SDA and SCL on other pair) are on. I had previously taken them out of the ducts thinking that the power wires were causing the interference.

4 drivers is a lot, but the end project will have over 40 motors and though I2C will not be used as the main communication method to control the project, it will be used in areas of the project.

Thanks,

  • Jamie

Hi,

50 feet between the arduino and the LCD screen/keypad, but right now I will settle for 6ft if I can get it. This is a prototype and the communication method on the actual project will be different.

Sorry not what I2C was designed for.
As I2C is not a balanced system, twisted wire is introducing significant capacitance between the wires, this will cause cross talk.
SCL is the clock signal and it will be cross feeding to SDA the data signal, possibly introducing clock glitches on the data line.

There is no ground that travels between the Mega and the motor driver. It uses Vcc and the a digital out pin either high or low.

Hmm, I'd still fit a gnd connection, for electrical noise reduction.
Using 100pF caps is way too small, 0.1uF would be better.

What is the overall application/distances?
40 steppers????

Tom.... :slight_smile: