Multiple arduinos and sensor i2c bus

Hi,
I am having an hard time with i2c..

What I am doing

A 3 axis cnc machine which uses stepper motors with a closed loop control.

My setup:

4*328p, one for each of the 3 axis and one as master/serial interface

Arduino master: handles serial with PC, sends commands and receives 'job done' with the rest via i2c
X axis: reads encoder and control relative sepper.
Y axis: via i2c reads one channel of an ads1115 and controls relative stepper
Z axis: via i2c reads the other channel of the ads1115 and controls relative stepper.

It all works fine without the Z axis, but adding that it all goes banana.

I actually have to keep reading the ads1115 from both Z and Y axis, and here is where I think the bus gets clogged..

I am actually after a suggestion on what changes make on my setup.. Or if you have an idea on how to make it work this way...

Thanks

I am actually after a suggestion on what changes make on my setup

Probably some code changes. Since you didn't post any code, despite posting in the Programming section, you're on your own to decide what they are.

PaulS:
Probably some code changes. Since you didn’t post any code, despite posting in the Programming section, you’re on your own to decide what they are.

Thanks,
I don’t know if it is ok or not to post a link to github, if it is not I will cut the code and post it here…

It is public now…

One way to make it work, please correct me if I'm wrong, would be to use an arduino mega, utilizing all four the serial ports (one for each of the 3 axis and one with the pc) and to add a second ADS1115 so I will have independent i2c com for the two sensors to each axis controller...

But i really would have liked to use a single bus for all...

Proceeding by steps, let's immagine the following:

one ADS1115 module (i2c) and two 328p
Is there a way to continuously pull data from the sensor from both the micros via i2c?

You need to change the communication.

Master.ino :
The Master is also a Slave, that is going to fail.
You use a Serial function in the onReceive handler. Do not do that.

This:

for (int i = 0; i < 2; i++)
iRXVal += Wire.read() << (i * 8);

Is making it hard for no reason.
Why not this:

iRXVal = Wire.read();
iRXVal += Wire.read() << 8;

Perhaps you should define whether the LSB or the MSB is send first, and put that in code in both the Master and the Slaves.

iRXVal is used in setup() and in the onReceive handler, it must therefor be “volatile”.

AsseX.ino :
It is not allowed to start a I2C session from the receiveEvent() function.
Do not use a Serial function in the receiveEvent() function.
Writing a TWI register while still in the receiveEvent() function can’t be good.

Using the WatchDog to reset a I2C Slave is a bad idea. What if that reset is done while the Slave is receiving data at that moment. That will disturb the I2C bus.

What is the Wire.begin() doing in the loop(), is that trying to reset the I2C bus ? But that will make it worse if something was being received at that moment.

AsseY.ino :
The same things as AsseX.ino
The call to readSensor() from the receiveEvent() is not okay. That function takes too much time. The receiveEvent() is already longer than it should be.
The variable “setpoint” is two bytes. On a 8-bit microcontroller an interrupt could happen when that variable is only read half. If you use that variable from the loop() function, then you should turn of the interrupts temporarily.
This Slave is a Master for the ADS1115 ? That will fail. Do not try to make a multi-master bus.

AsseZ.ino :
Same as AsseY.ino
Is this Slave using the same ADS1115 as the other Slave. How ? What ? What did I miss ?

Hardware:
How long are the wires ? Do you use a cable ? What kind of cable ?
What is the value of the pullup resistors ?

Conclusion:
These are problems that I noticed at first glance. There are probably more. If you are serious about using the I2C bus, then each and everyone of the issues should be fixed. Using a Serial bus is easier, unless you use SoftwareSerial. With SoftwareSerial a whole new world of problems are introduced.

I don’t know a good reason to reset the I2C bus. All you do, trying to reset things makes it worse. If a Slave behaves as a normal Slave, then the I2C bus runs forever.

Seems like the whole thing could be handled by a single Teensy 3.x. No need for multiple processors or complex comms.

While the I2C specification does allow multi-master operation, the Arduino library doesn't.

The reason for this is that it is actually a bad idea. There should be only one master on each I2C bus.

MorganS:
While the I2C specification does allow multi-master operation, the Arduino library doesn't.

The reason for this is that it is actually a bad idea. There should be only one master on each I2C bus.

Suppose there are 3 independent users, and they are connected together over I2C Bus; then, the Multi-master protocol will allow each user to acquire the bus for data communication with the desired slave device (s). From this view point, the Multi-master operation is a good idea.

gfvalvo:
Seems like the whole thing could be handled by a single Teensy 3.x. No need for multiple processors or complex comms.

Yes, I'm sure there are infinite better possibilities for the hardware. I also thought about using a plc... But the code I managed to badly stitch together took me a very long time... I am just a beginner trying to learn, I can now make something half functional with arduino, already had to learn a bit of python to make the gui... In my late 30s I find it hard to move from one language to another... Basically, I think I'm better off sticking with what I already have my feet wet... Probably this project is over my capabilities. Thanks to this forum, even if I'm not active at all, I learned a lot. Thank you, all of you.

Koepel:
Conclusion:
These are problems that I noticed at first glance. There are probably more. If you are serious about using the I2C bus, then each and everyone of the issues should be fixed. Using a Serial bus is easier, unless you use SoftwareSerial. With SoftwareSerial a whole new world of problems are introduced.

I did go through all your explanations, took me a while. I understood most of it. Some of your annotations have a logic explanation, but that might also be wrong. For instance, what I was trying to accomplish with the i2c reset, was trying not to miss any encoder interrupts deactivating the i2c bus, and once the movement is complete, reactivate it (wrongly) in the loop.

But, as you suggested, I decided to move to uart for the communications. Even if so, I will actually try to port your suggestions there. I will be very happy if you would have a look at it once is done..
Thanks

GolamMostafa:
Suppose there are 3 independent users, and they are connected together over I2C Bus; then, the Multi-master protocol will allow each user to acquire the bus for data communication with the desired slave device (s). From this view point, the Multi-master operation is a good idea.

No.

  1. I2C is very limited in length by reason of the maximum capacitance specification. So all the masters have to be close to each other. Like inside the same box, in a typical appliance like a TV. Why do you need 3 processors in the one box? Buy a Mega instead of 3 UNO's.

  2. The slaves on the I2C bus are very simple. Just thermometers or accelerometers. If 3 masters need to know the temperature then they will get 3 different answers. There would be no way for each one to get the same answer. In the worst case, the heater and air conditioner might come on at the same time.

  3. The I2C bus is very simple. It doesn't support networks that might be useful for larger applications like industrial control. So why do you need 3 processors for a simple task?

  4. Arduino programs tend to be very simple too. If you could put a master into slave mode, it would make the interface to the Wire object much more complex, making it more difficult for the people who just want to connect a thermometer.

MorganS:

  1. I2C is very limited in length by reason of the maximum capacitance specification. So all the masters have to be close to each other. Like inside the same box, in a typical appliance like a TV. Why do you need 3 processors in the one box? Buy a Mega instead of 3 UNO's.

  2. The slaves on the I2C bus are very simple. Just thermometers or accelerometers. If 3 masters need to know the temperature then they will get 3 different answers. There would be no way for each one to get the same answer. In the worst case, the heater and air conditioner might come on at the same time.

  3. The I2C bus is very simple. It doesn't support networks that might be useful for larger applications like industrial control. So why do you need 3 processors for a simple task?

  4. Arduino programs tend to be very simple too. If you could put a master into slave mode, it would make the interface to the Wire object much more complex, making it more difficult for the people who just want to connect a thermometer.

Not sure it will make sense... but I try to answer why I've made that choice

  1. There are 3 processor in one box because I was afraid that one arduino would not have been fast enough (mostly for my programming skills) to do closed loop feedback on 3 steppers.
    one is reading an optical encoder while driving one stepper, the other two are reading each an angle sensor while controlling their motors. Also, I thought for me was easier to divide the project in smaller tasks. might be more work at the end, but made of smaller blocks...

  2. The slave I am using is an ADC with 4 channels (only 2 needed) to read the angle sensor. Each arduino in theory would have read it's channel from the slave.

  3. Smaller bloks, easier to digest for a beginner.

  4. Arduino can be simple. How simple I think is relative. But if there would be more functionalities doesn't mean all have to use them..

tomy983:
Some of your annotations have a logic explanation, but that might also be wrong. For instance, what I was trying to accomplish with the i2c reset, was trying not to miss any encoder interrupts deactivating the i2c bus, and once the movement is complete, reactivate it (wrongly) in the loop.

You may assume that my remarks are right, and that there are even more problems.
It is allowed to stop the interrupt from the I2C controller for a very short time, but trying to reset something while Slave itself might be receiving data at that moment is not okay.

A Arduino as a Slave is something for advanced Arduino users, because so many things can go wrong.

I hope that you are not seriously thinking about SoftwareSerial, are you ?

Another set of eyes on the problem...
You're making things much more complicated than they need to be. I think your working assumption of "One ATMega328P is not enough to manage the job" is wrong. By having 2 I2C masters reading from the same ADC, you're asking for trouble. If you need sub-microsecond precision for managing the sensor and motors, then you should choose a different microcontroller. If not, then the 328p can handle the work with time to spare. The other assumption that seems odd to me is the notion of "reseting the I2C bus". There shouldn't ever need to be a reset - that doesn't even make sense. The bus is either active or not. The I2C bus 'controller' is mostly just a shift register. If both clock and data are floating high, it's inactive. If either one is pulled low by a master or slave, it's active.

Anyway, unless you're doing all sorts of complicated math or purposely slowing down the control loop with delay()'s, a single MCU can manage the job.

Koepel:
It is allowed to stop the interrupt from the I2C controller for a very short time, but trying to reset something while Slave itself might be receiving data at that moment is not okay.

A Arduino as a Slave is something for advanced Arduino users, because so many things can go wrong.

I hope that you are not seriously thinking about SoftwareSerial, are you ?

It was't supposed to be receiving, since I would have not sent any messages to it before it would have answered it finished the movement. Anyway, I got that is a bad Idea.

I am moving to a mega, with it's 4 serials. the move looked pretty easy, too easy maybe? instead of wire. just put serial. ... not really but..

Try to put most things in the Arduino Mega 2560. Everything in one Arduino board is the best solution.

When something changes, and you change the communication between the Arduino boards, then you have to upload a sketch to all Arduino boards. With one Arduino board you have one sketch and one upload.

The Serial bus has strong HIGH and LOW levels, that is better than the I2C bus with its weak pullup high level.
If possible try to avoid the Serial.parseInt() and Serial.readString() and those functions.
You could define the Serial data with a start byte (for example 'stx') and trailer byte (for example 'etx') and you could add a checksum (for example 'crc'), but at least define it with something at the end, for example a LineFeed.

I hope you are not tempted to use SoftwareWire in one of the Slaves.

bitbank:
Another set of eyes on the problem...
You're making things much more complicated than they need to be. I think your working assumption of "One ATMega328P is not enough to manage the job" is wrong. By having 2 I2C masters reading from the same ADC, you're asking for trouble. If you need sub-microsecond precision for managing the sensor and motors, then you should choose a different microcontroller. If not, then the 328p can handle the work with time to spare.

Anyway, unless you're doing all sorts of complicated math or purposely slowing down the control loop with delay()'s, a single MCU can manage the job.

As I said, probably one processor is enough. But, when I began, I had a really hard time to get things fast enough. For example, I had to change the i2c library (twi.h) and increase the clock speed considerably otherwise my servo would oscillate back and forward...

I did try to look for examples of closed loop stepper motor control on arduino, but could not find any.
on this machine each axis move one at a time. But 2 of them they still have work to do holding the position, like a servo.

Actually, I could nearly certainly loose one micro. The X axis one, since once it's movement is done it will just stay there waiting for instructions...

I am moving to use another ADC, but still, using a single micro would mean still have a lot of traffic on the i2c bus polling continuously from the two sensor.

I don't know really.. I am really afraid that going for a single board would be a lot of trouble, more than the communications issue. Keep in mind, I have zero forward thinking, I am totally unable to plan for the code. I am only able to write a piece at a time without planning.. I am afraid it would be a massive work for me to fix all the issues that will arise without the comprehensive knowledge required. I let you imagine how long it took me to understand my i2c bus was too slow, then that I could increase it's speed, and then how to do it...

I actually put everything on github because the project is open source. All the mechanics either are or will be there. If someone would like to give it a shot at squeezing things on a mega, I would love to try it out.

MorganS:
No.

  1. I2C is very limited in length by reason of the maximum capacitance specification. So all the masters have to be close to each other. Like inside the same box, in a typical appliance like a TV. Why do you need 3 processors in the one box? Buy a Mega instead of 3 UNO’s. […]

Cool!

Does anyone know how to send the DRT serial signal from one arduino to another?

I am asking because I would like to implement a way to reset all the 328p controlling the axis, I know it should not be needed and it most certainly isn't, but now I really would like to know how it is done...

tomy983:
Does anyone know how to send the DRT serial signal from one arduino to another?

I am asking because I would like to implement a way to reset all the 328p controlling the axis, I know it should not be needed and it most certainly isn't, but now I really would like to know how it is done...

You mean DTR (Data Terminal Ready)? Now you are mixing the serial with the i2c bus, why? Just use any io pin that is free.

LightuC:
You mean DTR (Data Terminal Ready)? Now you are mixing the serial with the i2c bus, why? Just use any io pin that is free.

Yes, Data Terminal Ready. I am moving to the following configuration:

Arduino mega, with small touch lcd which I have connected to PC via serial 0
(this is the one that I would like to send the DTR to the other arduino)

Each of the 3 axis is connected to the 3 left hardware serial on the mega.

I2c is still used on 2 of the 3 axis to get data from their respective ADC