Multiple Arduino Mega I2C network

Hi,

I have a network of multiple Arduino Mega as slaves and only one Arduino Mega as master, all connected over an I2C bus. Sometimes, because of the noise (I suspect), the bus is freezing, waiting probably for another master. Anyway, I want to use some I2C bidirectional I2C isolators to make sure the signals are clean and to avoid to freeze all network when one slave is going down (power off).

For this I choose ISO1540. But it can be any similar chip...

To test it I buy an I2C Isolator Click board and use it to connect a slave to actual bus and it worked well. When I power off this slave, the network continue to works. :wink:

So, I decided to implement the isolator solution for each Arduino on my "network". I want a compact solution... And such board as above is too big to use it on a protoshield for each Arduino on the I2C bus... The plan is to to use ISO1540 chip directly on the protoshield.
The problem is how to design this as best as possible. I need pull-up resistors? let's see:

  1. Slave type A connection, pure connection Arduino->ISO1540->I2C Bus. It should be OK?

  2. Slave type B connection. There are some pull-up resistors only on the Arduino side to clean up signal. I believe is a better solution vs Slave type A. Is this correct?

  3. Slave type C. There are also pull-up resistors on the bus side. For an Arduino->Arduino connection it is OK. But it is OK to use it for this situation where I use an I2C bus? On this bus there are over 10 Arduinos (and counting), if there are pull-up resistors for each slave connected to bus what are the side effects? Is there a point to have [Arduino Slave X->Pull-up resistors (SDA1 and SCL1)->ISO1540]->Pull-up resistors (SDA2 and SCL2)->I2C BUS>Pull-up resistors (SDA2 and SCL2)->[ISO1540->Pull-up resistors (SDA1 and SCL1)->Arduino Slave Y] ???
    Or, because there is an ISO1540 chip for each Slave there is no point to use pull-up resistors on the SDA2 and SCL2 for all participants on the bus? In fact there is a point for using power-up resistors on any SDA2 and SCL2 if there are always 2 ISO1540 chips between any 2 Arduinos?

  4. There is a master on the bus and someone must power up the I2C bus (all slaves have isolated power). It is OK to power it up from the master's VCC and GND?

So, how to design this thing?

Thank you!

PS The number of slaves are changing over time.
PPS I have no electronic skills.

  1. Whenever I read "I2C" and "Network" to connect several Arduinos I wonder - if the thread owner has chosen the right network technology.

Why have you chosen I2C and not a network like CAN, RS485, Ethernet? You are trying to solve problems within a bus system which might simple not exist if you had chosen a proper network technology.

  1. What makes it necessary to connect the Arduinos? Why even do you need several Arduinos? Which distances are between the Arduinos and how long is your "Bus" in total from the "Master" to the the last Arduino?

noiasca:
0) Whenever I read "I2C" and "Network" to connect several Arduinos I wonder - if the thread owner has chosen the right network technology.

I do not know if this was the best idea or not.

noiasca:
Why have you chosen I2C and not a network like CAN, RS485, Ethernet? You are trying to solve problems within a bus system which might simple not exist if you had chosen a proper network technology.

I2C seems to be OK for the purpose. Each slave (Arduino) have attached other shied and manage it. So, each slave is doing something complex. Master checks status for each slave and give something to do.
I like I2C because Slave receives only the messages addressed to it. Also the speed is quite good.
At RS485 there I found a problem "hearing" all the traffic and filtering what is addressed for a specific slave.
Do you have any recommendations?

noiasca:
00) What makes it necessary to connect the Arduinos? Why even do you need several Arduinos? Which distances are between the Arduinos and how long is your "Bus" in total from the "Master" to the the last Arduino?

As I said before, every Arduino has a Shield to deal with. And the number of Slaves can increase over time, depending on needs. So, this structure is the best. One master, multiple slaves.
The distance is very low. 20-30 cm max. All Arduinos are connected into a hub, so, the distance between each Adruino is the same.

I have the same thoughts as noiasca.

When you have 10 Arduinos at 20 cm around a single star point, then the total length is still 2 meters.

Does any Arduino board do something with power ? Could there be a ground current that can disturb the I2C signal ?
The I2C bus has three wires: SDA, SCL and GND. Without a good ground, there can be no good I2C bus.

Do you have pullup resistors ?
Nice pictures about the pullup resistors: Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino.

Starting with Arduino IDE 1.8.13, the Wire library has timeouts for the low level SDA and SCL signals. The bus is not waiting for another master, it is somehow stuck. When you use the timeouts, you should be able to revive the I2C bus.

Can you show all of your sketches ? When you have delays, or Serial functions, or String functions or other fancy things in the onReceive and onRequest handlers, then it is a software problem. Since almost everyone does that, you should let us have a look at your onReceive and onRequest handlers.

If you use flat ribbon cable, don’t put SDA and SCL next to each other. Don’t use a flat ribbon cable for I2C to begin with.

Do you know someone who is using the “I2C Isolator Click” and is happy with it ? I have serious doubts with that module. There seems to be 1k pullup resistors on the secondary bus to show off how strong the ISO1540 is. The designer seems to have forgotten that the 1k pullup is not within the I2C standard and a Slave connected to it must be able to sink it to a low level.
Don’t solve a problem with another problem. I think the “I2C Isolator Click” is bad. Can someone else confirm this ?

Koepel:
Does any Arduino board do something with power ? Could there be a ground current that can disturb the I2C signal ?

Every slave is doing some stuff. Some of them are using GSM modules that are using a lot of power some times. Because of this I believe that there is some noise on the bus sometimes.

Koepel:
Do you have pullup resistors ?

I do not have pullup resistors.

Koepel:
Starting with Arduino IDE 1.8.13, the Wire library has timeouts for the low level SDA and SCL signals. The bus is not waiting for another master, it is somehow stuck. When you use the timeouts, you should be able to revive the I2C bus.

This is good news, but I already use a version of wire library that is using timeouts.
Timeouts are good to escape from a freezing moment, but are not resolving the problem.
Take in mind that when a slave is powered off the whole I2C bus is freezing and a timeout will make master to pass over, but all slaves will look as powered off.
So, not only the noise, but this situation when a slave is powered off makes me want to implement an I2C bidirectional isolator solution.

Koepel:
Do you know someone who is using the "I2C Isolator Click" and is happy with it ? I have serious doubts with that module. There seems to be 1k pullup resistors on the secondary bus to show off how strong the ISO1540 is. The designer seems to have forgotten that the 1k pullup is not within the I2C standard and a Slave connected to it must be able to sink it to a low level.
Don't solve a problem with another problem. I think the "I2C Isolator Click" is bad.

As I say, I used this solution on a small network: A master and a slave on an I2C bus without pullup resistors and I added another slave on this bus with this I2C Isolator Click between I2C bus and this other slave.
Everything was OK. When I powered off this last slave, the master and the first slave continue to work. Without this I2C Isolator, when a slave connected to bus is turned off, the bus is over.

junior-root:
To test it I buy an I2C Isolator Click board and use it to connect a slave to actual bus and it worked well. When I power off this slave, the network continue to works. :wink:

Trying to see the overall picture, I see too many problems. Sorry :frowning:
You scare me every time you mention "network" and "I2C" in the same sentence. The first reply by user noiasca was spot on.
The I2C bus is not a network. A Slave may not be powered down. I really don't like that "I2C Isolator Click" module.

A single "I2C Isolator Click" module might work. It has pullup resistors on the module, so it does the pullup for you. However, the module is not according to the I2C standard. So only one of the isolator modules makes things bad already, and four of them is not good at all.

Going a great length to make it work this way is when you stick too long with the chosen solution.
Are you afraid to show the onReceive and onRequest handlers ? So you have hardware and software troubles :confused:
The I2C bus has weak signals and is not a fail-safe bus anyway.

You need to think about an other communication bus. The Arduino Mega 2560 has three spare serial ports. You can use RS-485 or perhaps a hard-wired TTL level serial communication, or use a multiplexer. There are many good solutions for that.

Koepel:
TAre you afraid to show the onReceive and onRequest handlers ? So you have hardware and software troubles :confused:
The I2C bus has weak signals and is not a fail-safe bus anyway.

I’m not afraid to show parts of the code. I just feel like we’re moving away from the topic of discussion. If the chosen method is not good, I do not find counter-solutions either.

Despite the fact that I beleive that this will not help, this is the requestFrom():

// Ping a slave and grab the status
void syncSlaveHub (int hub) {
  int l = Wire.requestFrom(slaves[hub].ID, 3);
  if (l == 0) {
    slaves[hub].i2cStatus = false;
  } else {
    slaves[hub].i2cStatus = true;
    slaves[hub].net_status = Wire.read();
    slaves[hub].slave_status = Wire.read();
    slaves[hub].variable_status = Wire.read();
  }
}

This is the onReceive() and onRequest():

  Wire.onReceive(receiveEvent); // register event
  Wire.onRequest(requestEvent); // register event

// Master is requesting slave's status
void requestEvent() {
  Wire.write((int8_t) net_status);
  Wire.write(slave_status);
  Wire.write(variable_status);
  gui_ping = ++gui_ping % 4;
}


void receiveEvent(int howMany) {
  Serial.println(howMany);
  uint8_t crc = 0;
  gui_msg = ++gui_msg % 4;
  while (Wire.available() && i < BUFFER_LENGTH) {
    x = Wire.read();
    wireBuff[i] = x;
    if (i >= 4) crc += x;
    i++;
  }
}

junior-root:
I like I2C because Slave receives only the messages addressed to it. Also the speed is quite good.
At RS485 there I found a problem “hearing” all the traffic and filtering what is addressed for a specific slave.
Do you have any recommendations?

I like I2C because Slave receives only the messages addressed to it. Also the speed is quite good.
At RS485 there I found a problem "hearing" all the traffic and filtering what is addressed for a specific slave.
Do you have any recommendations?

That's easy: start each master request with the "Slave Address", and on slave side, check if the first byte fits to the own "address", if not - ignore.

And I assume there are already some "frameworks", patterns, best practices existing which make that more convenient... 15 secs google brings up the pages from forum member gammon:

https://www.gammon.com.au/forum/?id=11428