I2c data encoding - Synchronise many arduinos

I have two arduinos : one master and one slave.
In the master loop, the master writes a number to the slave then receives a character from it.
The problem is that in the master serial monitor when I try to show what it receives, it shows weird characters very different from what sent.
The slave requests data from my PC then sends it back to the master.
I trued the same programs but with an RPi as a master and it shows me the ASCII codes related to the letters the slave receives from the PC.
Here is my master code :

void loop()
{
  Wire.beginTransmission(0x11);
  Wire.write(2);  
  Wire.endTransmission(); 
  delay(10);
  Wire.requestFrom(0x11, 1); 
  while(Wire.available())  
  { 
    char c = Wire.read(); //I tried both char and int types
    Serial.println(c);    
  }
  delay(500);
}

I receive very strange characters on the serial monitor. Is there a data format that I should specify or s.th related to that ? Thank you.

And what's the slave's code? BTW, that wasn't the master's code but an excerpt from it. Post complete sketches because the error is sometimes in an area where you would never look for it.

Ok :slight_smile: That is the complete master code :

#include <Wire.h>
void setup()
{
  Serial.begin(115200);
  TWBR = 400000L;
  Wire.begin(); 
}
void loop()
{
  Wire.beginTransmission(0x11);
  Wire.write(2);  
  Wire.endTransmission(); 
  delay(10);
  Wire.requestFrom(0x11, 1); 
  while(Wire.available())  
  { 
    char c = Wire.read(); //I tried both char and int types
    Serial.println(c);    
  }
  delay(500);
}

The slave code :

#include <Wire.h>
int readSerial ;
int readWire ;
#define SLAVE_ADDRESS 0x11
void setup(){
  TWBR = 400000L;
  Serial.begin(115200);
  pinMode(led, OUTPUT);
  Wire.begin(SLAVE_ADDRESS);
  Wire.onReceive(receiveData);
  Wire.onRequest(sendData);
 
}
void loop(){
}
void receiveData(int byteCount){
  while(Wire.available()) {
    readWire = Wire.read();
    if (readWire == 2){
      Serial.write(11);
      delay(0.05);
      if (Serial.available()){
        readSerial = Serial.read() ;
      }
    }
  }
}
void sendData(){
  int envoi = readSerial ;
  Wire.write(envoi);
}
  TWBR = 400000L;
  Wire.begin();

I don't know what exactly you want to do with this code but TWBR is overwritten in Wire.begin(). The value doesn't make sense anyway, TWBR is a byte register, your setting would result in a I2C frequency of about 60kHz (0x80), if you place it after the Wire.begin().

      delay(0.05);

That one also probably doesn't do what you expect it to. It uses a few clock cycles and returns almost immediately.

In the slave code, sendData() and receiveData() are called in interrupt context, so never, never call any method of the Serial object inside of it. All variables used in both routines have to be declared "volatile".

Do you expect on the PC to receive a vertical tab (ASCII 11)?

TWBR is overwritten in Wire.begin()

Can you tell me plz how can I set i2c baudrate to 400KHz?
Regarding the delay(0.05); you're absolutely right. I removed it and the slave kept receiving data. So there's no need to let it wait.

Do you expect on the PC to receive a vertical tab (ASCII 11)?

The PC is reading in fact a file containing a vertical ascii tab. I expect to receive in the master side that tab.
Each time the master asks the slave to give him data, the slave in the receiveData() function asks the PC to give him a value from the tab via serial communication. That's why I used the serial communication inside the receiveData() which seems a bad way.
Where can I tell my slave to read from serial when it receives data from wire ?

I found how to set the i2c baudrate in that post: http://forum.arduino.cc/index.php/topic,16793.0.html

I found how to set the i2c baudrate in that post: http://forum.arduino.cc/index.php/topic,16793.0.html

You can do it without changing the Wire library code by setting TWBR after the call to Wire.begin() to 12:

Wire.begin();
TWBR = 12; // ((16000000 / 400000) - 16)/ 2

The PC is reading in fact a file containing a vertical ascii tab. I expect to receive in the master side that tab.
Each time the master asks the slave to give him data, the slave in the receiveData() function asks the PC to give him a value from the tab via serial communication. That's why I used the serial communication inside the receiveData() which seems a bad way.
Where can I tell my slave to read from serial when it receives data from wire ?

You should restructure your communication protocol. You shouldn't have to ask the PC for the value while the requesting party is waiting on the I2C bus, remember the clock signal for the bus is coming from the master and the only way to wait for the slave is to dp clock stretching. This blocks the bus completely and should be avoided for longer periods of time. Making a serial communication over the UART is an extremly long period in this regard.
So do send some command to the slave that it should request the data from the PC. Later on request that data which should be stored on the slave in the meantime. This way you can move the serial communication out of the interrupt handler into the main loop() routine. Usually this is done by using a flag/status variable in the handler, then reacting on it in the loop() and resetting it after the action was taken.

What do you want to achieve with your setup? It's quite unusual to request data from an I2C slave which then in turn has to ask a PC behind for the actual value. What's the purpose of this project?

I get what you say ! I'll try to change this especially that I don't want to paralyse the bus when I will be working on many arduino slaves.

What's the purpose of this project?

Actually, it's for simulation purpose. I have log files containing simulation data. I need that data in my arduinos.
I would use SD cards to store each data type on an arduino however, since they cannot be synchronized, they don't have the same clock : this can't be done because the diffrent arduinos data are semantically dependent.
So I'm trying to make the PC pilot the simulation using its own clock and each time an arduino needs data it asks for it from the PC.
That's the origin of the idea.
I would give up this solution if found a way to make different arduinos synchronised : start exactly at the same time and have the same clock, or parse files at the same speed with no shift between them.

If every Arduino is connected to the PC anyway, why do connect them via I2C also? Looks to me like an unnecessary burden.

Just to synchronize them a single wire from the master to all slaves is sufficient, but maybe I miss some point.

All arduino slaves are connected to the PC via serial and are connected to an Arduino master via I2C. The master is not connected to PC. It may seem unecessary but I need that to simulate a system.

I would give up this solution if found a way to make different arduinos synchronised : start exactly at the same time and have
the same clock, or parse files at the same speed with no shift between them.

I gave you a solution for this, just use one digital I/O to synchronize the Arduinos. As you haven't described what kind of system you're trying to simulate it's not possible for us to help you with more details or even suggest a different way.

just use one digital I/O to synchronize the Arduinos.

Since I am a beginner I don't even get how can I use a digital I/O to synchronise my arduinos. Would they be able to have shared clock?

As you haven't described what kind of system you're trying to simulate...

I am trying to simulate a sensor network. Many sensors "accelerometers" capt analog data, convert it to digital data then send it to a performant processor to make some calculations and return significant values (speed, etc). They send data via I2c.
The performant processor is the master. I am going to simulate the sensors and the data they send just to test the master algorithms. So I have log files of the measures that sensors return and I need to send them to the master. And this should be done via I2C to make it similar to the real system.
The sensors are supposed to capt and send data in high frequencies let's say every 2.5 ms. I need my arduinos to be able to respond to the master in this frequencies and also send the right data. I mean at a given time t : all arduinos should be able to have the data that corresponds to the instant t in the log file (which can be a table when each row contains the values of a given time)
I can upload on each arduino its own log file and make it parse it in the loop and just send the current value when the master asks for it. But can I really make all arduinos start parsing their files in the same time ? Being 2 ms late can cause problems later on. And can I be sure that they will function in the same speed?
That is my problem. I asked some electronic guys and they told me that there's no way and no hope to make them synchronised.
I would be more than happy if you see a solution there.

Hi again,
I spent some time thinking for a way to synchronise my arduinos. I've got an idea and I'll be glad if you tell whether it is possible or not.
Since all devices on the i2c bus share the same SCL line and only the master controls the clock, would it be possible on each arduini to read regilalrly the SCL line and to increment a variable every falling edge for example and so all devices shold have the same clock.

Since I am a beginner I don't even get how can I use a digital I/O to synchronise my arduinos. Would they be able to have shared clock?

Make all slave Arduinos listen on the input where that signal line is connected. On a rising/falling edge (whatever you prefer) store the current value of millis(). From now on our time reference is millis() - stored_value. Voilà, you have them synchronized.

And can I be sure that they will function in the same speed?

That depends on the type of Arduino used. A Duemillanove uses a crystal as the clock source (differs at a few part per million) while an UNO uses a ceramic oscillator which differs at a few parts per thousand, so it's about a factor thousand less accurate. What are you using?

How are the original sensors (the ones you're trying to simulate) synchronized? How many sensors are typically in that network?

Make all slave Arduinos listen on the input where that signal line is connected. On a rising/falling edge (whatever you prefer) store the current value of millis(). From now on our time reference is millis() - stored_value. Voilà, you have them synchronized.

.
Sorry, but I don't get it. What is the signal line? Do you mean the clock line?
And every arduino will store its own millis on a falling (or rising) edge? How would that make them synchronised?

What are you using?

If I can synchronise different arduinos , I'll be using the same board : arduino uno.

How are the original sensors (the ones you're trying to simulate) synchronized?

The sensors I am trying to simulate are not synchronised, since every sensor has its own data (analog data conerted to digital) so it is able to respond to the master anytime.
In my case arduinos are not sensor and do not have captured data. So I'll make them read log files (containing that data) and this should be done like in the real network.

How many sensors are typically in that network?

The number is not fixed there can be many sensors (up to 30)
But it would be fine if I can simulate from 10 to 20 sensors.

Sorry, but I don't get it. What is the signal line? Do you mean the clock line?

No, any digital IO of the Arduino. As an example, you can use D3 for this but I don't know if this pin is unused in your design yet.

If I can synchronise different arduinos , I'll be using the same board : arduino uno.

That's fine but keep in mind that the UNO is not the most accurate of all types in terms of timing.

The number is not fixed there can be many sensors (up to 30)
But it would be fine if I can simulate from 10 to 20 sensors.

In that number I would choose cheaper variants than a complete UNO for every sensor but that's up to you to decide.