Hi, I want to communicate between two Arduino's DUE with I2C, so both have to be master. I read a lot that this was difficult, but I also read that it was easy to install, for example with de following code:
#include <Wire.h>
void setup() {
Serial.begin(9600);
Wire.begin(1);
Wire.onReceive(receiveI2C);
}
void loop() {
delay(100);
Wire.beginTransmission(2);
Wire.write("hello world from 1 to 2");
Wire.endTransmission();
}
void receiveI2C(int howMany) {
while (Wire.available() > 0) {
char c = Wire.read();
Serial.print(c);
}
Serial.println();
}
This is the code for both Arduino's, I just switch the addresses. If I run this, I want it to print out "Hello" from Arduino 1 to Arduino 2 via I2C and vice versa, but it does not print it on the serial monitor. Also if I plug in the logic analyzer it does not trigger on a rising or falling edge and if I run a I2C scanner script it triggers one time and then it says "unknown error". Does someone know if it is doable and if so how I can fix this?
If you say that you want communicate between Master and Slave using I2C Bus , then the communication is possible. Both DUEs cannot work as Masters on the I2C Bus at the same time.
DUE-1 is Master when DUE-2 is Slave. When DUE-2 is Master then DUE-1 is Slave.
An I2C device becomes master as soon as it begins a transmission. If multiple devices try to transmit at the same time only one of them is finally accepted (arbitration), the others must retry later. At any other time all I2C devices behave as slaves, waiting for some input.
I think it is needed, I will tell a little bit more what I want to achieve. I want to build a system connected in a 3 by 3 matrix form (later expand this to 5 by 5 or even bigger), each node is then an Arduino and every Arduino has to send and receive data. So for example I want to send data from Arduino 1 to the last one in the matrix, Arduino 9. It has to do this in the shortest path available and if a connection between Arduino's is not available the system has to rearrange and it has to take another route to Arduino 9. I already made a simulation in Python and wanted to test my findings with Arduino's, because they are versatile and quite "easy" to program. I thought that I2C was a good option, because I think that every node has to send and receive data. The picture maybe gives a better idea of what I am talking about.
Sorry to spoil the fun, but that will never work. The I2C bus is not that kind of bus.
Even with two Due boards, it will not work reliable, not even when one is the Master and the other the Slave.
The Teensy 4.0 board and the Teensy 4.1 board have many Serial ports (with RX and TX). That should work for your project.
If you use a I2C bus or Serial bus, don't forget that the GND wire is part of the bus. The GND wire is actually the most important wire.
An other solution is to run everything on a single board and use tasks with queues between the tasks instead of wires.
It is possible to have 9 displays, so each task can control some output.
There are libraries for some kind of multitasking on a Arduino Uno. The Arduino scheduler works on the Arduino Zero, the MKR Zero and other boards. The Mbed/rtos (Raspberry Pi Pico) and FreeRTOS (ESP32) are preemtive multitasking systems.
The Wokwi simulator can not run multiple boards yet, but it can simulate the Mbed/rtos (Raspberry Pi Pico) and FreeRTOS (ESP32) multitasking systems.
The RadioHead library has a routing/mesh possibility for transceivers.
Thank you for your answer, but why it will never work? If every Arduino is configured as a master in theory it should work right? And why it doesn't work reliable with two Arduinos?
Don't get me started ! O, wait, you just did. Well, I will try very hard to restrain myself.
The software for the Arduino Due is no longer maintained by the Arduino Team, they focus on newer boards. That does not mean that the Due software is good and finished. The Due has troubles. No one should buy a Arduino Due board.
The Arduino Due has 1k or 1k5 onboard pullup resistors for the first I2C bus. If you connect two boards, then there is already too much pullup. The I2C standard allows a maximum sink current of 3mA (the current to pull a signal low). You should know everything about pullup resistors for the I2C bus if you are going to connect many devices.
If you do everything wrong, then the maximum length is about 20 cm for the I2C bus. If you do everything right, then it is 2 meters or more. You may assume that at this moment you do everything wrong. The 20 cm is the total length. That means with 10 boards, there can only be 10 wires of 2 cm each.
The onReceive handler (your receiveI2C function) runs in a interrupt. You should not process data in that function and only use Serial functions during testing, unless you try to use the SerialUSB port, that might crash the Arduino board.
The I2C bus is slow. The Wire.requestFrom() and Wire.endTransmission() wait until the I2C session has completely finished. That means that every board could be waiting 95% of the time. Just waiting, doing nothing. With Serial communication, no one waits.
I have never seen a reliable Multi-Master I2C bus with Arduino boards. I often say that it is a fairy tale. It does not exist yet. If you are smarter than everyone else, then you can spend many hours to make it, and I can see problems in just a few minutes. Only less experienced people try a Multi-Master bus, the advanced programmers stay away from it. That is for a good reason. The reliability of a project should not be compromised by something that has no guarantees that it will work well.
In your sketch, you do not show even the most basic check for a collision. You should check the return value of Wire.requestFrom() and Wire.endTransmission(). If there was a problem, you have to do a retry. That retry mechanism will fail in software with more than two Arduino boards (for example because they are all 95% of the time waiting). With only two boards, you should fully trust that the Arduino Wire library handles the collision correctly in all situations. I'm not sure about that.
I often say: "The I2C bus is not that kind of bus". I assume that you don't know that SDA should not be next to SCL and that SDA and SCL have no meaning without GND. Perhaps you are going to make a number of mistakes with just the wires.
The picture with the 9 boards shows four I2C buses for the board in the middle. The Arduino Due has only two I2C buses. Are you going to connect them all to the same I2C bus ? So everyone can talk to everyone ? That is way more complex than the goal of your project.
@DrDiettrich If I say something wrong, I expect you to correct me, but you don't have to tell me how the Wire library works I will write a few things here, but that is only a part of the problems that I see.
If the Due board has nothing else to do, then the waiting is no problem. But then a Arduino Uno is just as fast.
The Due has two I2C buses, if both are used, then the waiting can be a problem.
When I visualize what is going on and compare that with Serial communication, the difference is very big. A sketch that uses Serial communication reads a byte from one stream, sends a byte to another stream, and so on. The interrupts take care of the rest and no one is waiting.
I just keep bluntly saying that a Multi-Master I2C bus with Arduino boards is a fairy tale, until someone proves me otherwise. If has seen all the efforts, with extra wires, and complex code for the retries. The more complex it becomes, the more things I see that can go wrong.
If someone should make a reliable Multi-Master I2C library, it could be me. But I stay away from it as far as I can.
I don't see a problem even with two buses. The master does not have to wait except for proper transmission, the slave handles the data transfer in asynchronous callbacks.
With two buses and waiting, the Master can send data to one, then send data to the other and so on. In between data could be incoming. My feeling tells me that if the Master can not get rid of the data soon enough, it becomes clogged.
Suppose data is incoming that has to be passed on to Slave 1, but the Master has still some data for Slave 2 that is send first. That means some buffering is required. Add a layer on top of that with retries, and the buffering is out of control. Extra code is needed to keep things in control. That complexity will not make it better. I see dark clouds and hail storms and Due boards in heavy seas.