I2C Communication on Arduino R4 Wifi

I'm making two prop phones for an exhibition.

Each one uses an arduino r4 wifi to drive a DFplayer mini to play back audio and a h-bridge to drive the bell in the phone.

They need to communicate with each other to ring at the same time and to detect when one has been answered or if the phone is off the hook.
Initially I was going to use wifi to connect them and to use the RTC on each device to sync the ringing.

The wifi tests I did were too unreliable - they wouldn't always connect and so I've decided to go with a wired solution.

My intention is to use I2C to send the hook (phone picked up) state between the two devices and for the master device to trigger ringing on the slave.

I' don't have any experience with I2C but have just tried some simple examples to no avail.
After checking it seems there's an issue with the SCA and SDL pins on the digital header of the r4 wifi in that they don't have pullup resistors.

I'm going to play around with them a bit but does anyone have experience of using these.
I have the SDA & SCL pins on both devices connected and they are grounded together. Perhaps I'm missing something simple!

Master Code ->

#include <Wire.h>

#define TO_MASTER_SIZE 3
#define TO_SLAVE_SIZE  4

#define START_NODE   1 // The starting I2C address of slave nodes
#define END_NODE     2 // last node to probe +1

#define NODE_READ_DELAY 1000 // Some delay between I2C node reads

byte messageToMaster[TO_MASTER_SIZE];
byte messageToSlave[TO_SLAVE_SIZE];

void setup() {
  Serial.begin(9600);  
  Serial.println("MASTER");
  
  Wire.begin();  // Activate I2C link
  Serial.println("I2C enabled");
}

void loop() {
  for (int address = START_NODE; address < END_NODE; address++) {
    sendToSlave(address);
    readFromSlave();
  }
  delay(NODE_READ_DELAY);
  Serial.println("Master Loop");

}

void sendToSlave(int address) {
  // message is 0123
  for(int i = 0; i < TO_SLAVE_SIZE; i++) {
    messageToSlave[i] = (byte)i;  
  }

  Wire.beginTransmission(address);
  Wire.write(messageToSlave, TO_SLAVE_SIZE);
  Wire.endTransmission();
}

void readFromSlave() {
  // if data size is available from nodes
  if(Wire.available() == TO_MASTER_SIZE) {
    for (int i = 0; i < TO_MASTER_SIZE; i++) {
      messageToMaster[i] = Wire.read();  // get data
    }
    int fromAddress = messageToMaster[0];
    int value = ((int)messageToMaster[1] << 8 ) | (int)messageToMaster[2];
    Serial.print("Slave ");
    Serial.print(fromAddress);
    Serial.print(" says ");
    Serial.print(value);
  }
}

slave code ->

#include <Wire.h>

// Change this unique address for each I2C slave node
#define NODE_ADDRESS 1

// matches values on master side.
#define TO_MASTER_SIZE 3
#define TO_SLAVE_SIZE 4
#define NODE_READ_DELAY 1000

byte messageToMaster[TO_MASTER_SIZE];
byte nodeReceive[TO_SLAVE_SIZE];

void setup() {
  Serial.begin(9600);  
  Serial.print("SLAVE #");
  Serial.println(NODE_ADDRESS);

  Wire.begin(NODE_ADDRESS);  // Activate I2C network
}

void loop() { 
  delay(NODE_READ_DELAY);

  if(Wire.available() == TO_SLAVE_SIZE) {
    readFromMaster();
    sendToMaster();
  }

  Serial.println("Slave Loop");
}

void readFromMaster() {
  for(int i = 0; i < TO_SLAVE_SIZE; i ++){
    nodeReceive[i] = Wire.read();
  }
  Serial.print("Master says ");
  for(int i = 0; i < TO_SLAVE_SIZE; i ++){
    Serial.print(nodeReceive[i]);  
  }
  Serial.println();
}

void sendToMaster() {
  int x = 100;
  messageToMaster[0] = NODE_ADDRESS;
  messageToMaster[1] = (x>>8) & 0xff;  // the top byte of x
  messageToMaster[2] = (x   ) & 0xff;  // the bottom byte of x
  Wire.write(messageToMaster,TO_MASTER_SIZE);  

  Serial.print("Sensor value: ");
  Serial.println(x);
}

A quick update on this. I've added a 1kOhm resistor to VCC on both the SDA and SCL lines but still no joy.

I've also tried this using the A4 and A5 pins but also no joy.
thanks

tom

Gah!

Have tried this example using the A4 & A5 pins and still nothing.

master->

#include <Wire.h>

void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
  Serial.begin(9600); 
  Serial.println("master begin");  
}

byte x = 0;

void loop()
{
  Serial.println("master loop");  
  Wire.beginTransmission(4); // transmit to device #4
  Wire.write("x is ");        // sends five bytes
  Wire.write(x);              // sends one byte  
  Wire.endTransmission();    // stop transmitting

  x++;
  delay(500);
  
}

Slave ->


#include <Wire.h>

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
  Serial.println("slave begin");  
}

void loop()
{
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(1 < Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  int x = Wire.read();    // receive byte as an integer
  Serial.println(x);         // print the integer
  Serial.println("slave event");  
}

Will there be wires between the phones ?
How many phones do you want to connect ?

The I2C bus is not what you think it is.
You can not put data in at one end and expect that data comes out at the other end.
It is not Serial/UART bus. You can not just check Wire.available() to check if something has arrived. It is not possible to only use Wire.read() to read something. It is not possible to only use Wire.write() to write something.
The SDA and SCL are digital signals, and the I2C bus can not deal with crosstalk between those two signals. It is best to keep them away from each other.

I hope that I scared you enough :ghost:

Can you use a Serial/UART communication ?

I've fixed your code tags; please pay a little attention and check after you have made your post :wink:

I have no experience with the R4 so can't help.

You are aware that I2C is not intended for use over long distances (something over 25 cm)? You might now have them next to each other but on the expo a few meters apart. People do manage to get it working over long distances (with or without I2C extenders).

Hey.
thanks - I actually tried to edit the code tags three times but couldn't get it to work. not sure why.
Thanks for the help.

Ah - I didn't realise the distance limitation with I2C - that is a problem - they'll be approx 3m away. So will need to find another solution then.

How will you ring the bells ?
Do you want to use the coil with the switch. That will cause sparks and so much electric noise, that your Arduino board might stop work.
Is there a way to drive the coil directly from the H-bridge ?

I guess I'll just use serial comms then.
I thought (for some reason - not sure why) that using I2C was better for this for some reason - also hadn't used is to decided to play around. But I can just use software serial I guess.
I've a distance of 3m to run so not sure if this is a problem here too.

I'll just be sending a flag from the slave to the master to say if the device has been picked up
and from the master I'll be sending a trigger flag and a similar flag if it has been picked up.

hope that makes sense?

Thanks for the help.

yes - this bit is all good.
I use a square wave from the arduino and a boost convertor (seen on the top board) to drive the h-bridge and generate a roughly 70Vac square wave.

Is one or two digital signals (plus a GND wire) enough ? Just a digital pin going high.
You can protect the inputs of the Arduino with a resistor in the signal line. For example 1kΩ.

it works fine

Have you managed to excnage data between two UNOR4WiFi using Software UART Port (SUART)? The SUART netwrok works well even within 30 m using TTL logic.

I haven't tried but I guess I'll try that tomorrow. Thanks