I2C communication between Arduino

Hello

To reduce work load in one Arduino, I am using two Arduino as Master and Slave communication, the slave has to display message in LED Matrix, and listen commands from Master. How to make the slave display and listen from Master.

Option1: Peridoc checking use timer interrupts

Option 2: Using Wire.h library, Wire.onRecieve(receiveEvent), recieveEvent is a function, will the function triggers when the master communicates.

Also I am using, DS1307 on the same line.

-- Thanks in Advance

The Master is the I2C Master. The DS1307 is a I2C Slave. The other Arduino is a I2C Slave. You can add many more sensors and Arduino boards as Slave.

If the Master sends something, use Wire.beginTransmission - Wire.write - Wire.endTransmission. The Slave uses its onReceive handler. https://www.arduino.cc/en/Tutorial/MasterWriter

If the Master reads something, use Wire.requestFrom - Wire.read (or Wire.readBytes). The Slave uses its onRequest handler. https://www.arduino.cc/en/Tutorial/MasterReader

Most of the code in the Slave should be done in the loop(). Since the onReceive handler is an interrupt handler, it may only contain very short and fast code. The common way is to copy the received data into a buffer and set a flag. In the loop() check for the flag. Use the keyword 'volatile' for the buffer and for the flag.

P.S.: Don't just copy the examples in the links. They are not very good.

Peter I had gone through the tutorial, in this case the DS1307 is read by the slave to display the clock which is connected on the same line with 0x68 register address.

In proper sequence of I2C communication, the SCL lines low, followed be transformation of data, and later it is made logic high, in order to avoid Confusion or collision do the master need to check for SCL low, before attempting command the slave what to do next.

-- Thanks in Advance

myuino:
Peter I had gone through the tutorial, in this case the DS1307 is read by the slave to display the clock which is connected on the same line with 0x68 register address.

In proper sequence of I2C communication, the SCL lines low, followed be transformation of data, and later it is made logic high, in order to avoid Confusion or collision do the master need to check for SCL low, before attempting command the slave what to do next.


Thanks in Advance

The I2C protocol uses the SCL line as the clock, it is driven by the Master device. The SDA (data) line driven by the sender.

so, for the ‘master’ to send a byte to the slave the master creates a Start condition.

The start condition is signified by the master pulling the clock (SCL) LOW, waiting a moment ( 1/2 bit time) then pulling the data (SDA) LOW. The next 7 transitions of the Clock (SCL) line are used to transfer the 7bit address of the slave one the data line (SDA) the 8th bit transfered is (READ or Write) if the 8th bit is HIGH it signifies a READ command, if it is LOW it signifies a Write operation. The Master releases the data (SDA) and monitors the data line for and acknowledge from the slave. This acknowledge is transmitted by the slave device holding the data line Low during the 9th bit of the clock.
After the Acknowledge bit the master either start sending the next byte (write mode) or listens to the data line (SDA) (read Mode) while it clocks the SCL line for each bit. to mark the end of transmission the master generates a stop condition by holding the clock line (SCL) LOW and releasing the data line (SDA) to a HIGH condition.

All of this bit twiddling is handled by the AVR hardware, the Wire library is the wrapper for the Two Wire Interface hardware.

to use the Wire library you only need to do a couple of things.

Here is simple code to read the current time in a DS1307 RTCC

#include <Wire.h>
#define rtccAddr 0x68   // DS1307 RTCC i2c Address

void setup(){
Serial.begin(9600);  // for serial monitor
Wire.begin();  // initialize TWI hardware

/* set the internal RTCC register pointer to 0 */

Wire.beginTransmission(rtccAddr);  // start communication with Slave device (0x68)
Wire.write((uint8_t)0);                 // add a byte to the Wire library transmit buffer
                                                // write one byte of Zero, This sets the internal address pointer
                                                // of the RTCC chip to 0
Wire.endTransmission(false);       // actually send the buffer content to the slave, maintain ownership of the
                                                // I2C bus

/* Read the current time /date from the RTCC */

Wire.requestFrom(rtccAddr,8,true); // read 8 byte from the RTCC, Starting with register 0
                                                 // the  store it in the Internal Wire Receive buffer.
                                                // release the I2C bus when completed,
                                               // the I2C bus can have multiple 'masters' and multiple 'Slaves'
                                               // at the same time.  One at a time.
uint8_t x[8];
for(uint8_t i=0;i<8;i++){
  x[i]=Wire.read();                   // transfer from the internal Wire library buffer to my array x[]
  }

Serial.print(x[2],HEX);            // hours
Serial.print(':');
Serial.print(x[1],HEX);            // minutes
Serial.print(':');
Serial.print(x[0],HEX);            // seconds
Serial.print(' ');
Serial.print(x[5],HEX);            // month
Serial.print('/');
Serial.print(x[4],HEX);            // day
Serial.print('/');
Serial.print(x[6],HEX);            // year
}

void loop(){}

Chuck.

http://www.gammon.com.au/i2c

myuino, there is only one way to do this, and that is to do it right :P The Master controls the bus. If the Slave Arduino needs the time, the Master should request the time from the DS1307 and send it to the Slave Arduino. You can't use the I2C bus for multiple things, and using SCL as chip select is not possible.

Peter, cant the slave Arduino request time from DS1307 as mentioned

 Wire.beginTransmission(0x68);
 Wire.write(byte(0x00));
 Wire.endTransmission();
 Wire.requestFrom(clockAddress, 7);

If the Slave is doing that, and the Master tries to communicate with the Slave at the same moment, then there is a collision. The Wire library can not deal with that. It is not possible to check SCL or something like that.

Peter, once the event driven program is pulled for slave, or Master tries to request data from Slave, a flag == False statement will be set, the slave Arduino will only listen, later once the request has been satisfied by slave to Master, again the flag==True will be set, so that the Slave can read data from the clock register. Is it possible.

This is possible I am planning to pull any of the digital pin low other than SCL or SCA , in Maser, the slave will first check for the Low state and request data from DS1307

Advice please

-- Thanks in Advance

The I2C is a bus. The SDA and SCL are both used to transfer information. It is not possible to keep one low. It is also not possible to set a flag in the Master or Slave.

You could add an extra wire. A third wire next to SDA and SCL, and use it to indicate that the Master or the Slave is busy on the I2C bus. But you have to develop a protocol and you have to be an advanced software engineer. My advice is to not even try that. Keep the Master the Master at all times.

What can be wrong when the Master reads the time and passes that on to the Slave Arduino ?

I just want to point out that being a Master is a temporal thing. As I show in my code on http://www.gammon.com.au/i2c both ends can takes turns being masters.

The "real" Master could allow the Slave to use the I2C bus for a while. The Master would stay low, and the Slave would be temporary the Master of the I2C bus. However, in this situation, with the DS1307 RTC, I don't see any advantage for that and I see too many disadvantages. That is why I wrote to keep the Master the Master at all times. It will prevent so much trouble.

P.S.: Nick, I think your section "Communicating with other devices" will cause a collision now and then.

See the datasheet, 22.4:

The TWI protocol allows bus systems with several masters. Special concerns have been taken in order to ensure that transmissions will proceed as normal, even if two or more masters initiate a transmission at the same time.

So it specifically allows multiple masters.

Then it goes on:

Two problems arise in multi-master systems:

The wired-ANDing of the bus lines is used to solve both these problems.

There is a warning a page or two later about steps you take to make this work properly.

I know that is in the datasheet, but the Wire library does not allow it.

Peter, As suggested by Nick, if I configure the master with wire.begin(001), and slave with wire.begin(002) and DS1307 of course 0x68, is it not possible their is a coordination in i2C bus. This was well documented in Nick webpage, I had been benefited a lot.

Also I am planning alternately to try third wire other than SCL and SCA to enable the protocol more efficiently.

Mr.Peter,

The Master Arduino is already busy as client server and sending message through GSM sim, it is quite impossible to read time every second and sent to slave for display in LED Matrix. May be I have pull timer interrupt for this.

- Thanks in advance

I have something like that. I don't have the project source file here at the moment, but I do it like this: The 'Master' is a Arduino Mega 2560. It gets the time every three hours from an internet time server with NTP. A Slave is a VirtualWire receiver that stores the received data with a timestamp. For that timestamp it has to know the time. The Master updates the time to the Slave now and then (I forgot how often).

Perhaps you can do the same. Use the 16MHz crystal accuracy to let the Slave keep track of time. And have the Master update the time to the Slave. I think your project uses the time in a different way than in my project. I'm not sure this solution would work for you.

In the Library Manager is 'SoftwareWire', a software I2C library. With that the Slave can have it's own I2C bus for the DS1307. The library is working, but it has not been used a lot yet.

Peter,

Using Software Library, I can reconfigure the pins SDA, SCL as I need, do I need external pull -up resistor, or it will be default microcontroller has it say value of 4.7k resistor .

-- Thanks

The internal pullup resistors are 50k or 70k (I forgot what it is). They can be enabled when the SoftwareWire object is created. I might be best if two pullup resistors of 4k7 or 10k are used, unless they are already on the RTC module.

I don't have a DS1307, so I can't test the SoftwareWire library with the DS1307.

Peter and all, as the I2C communication,

the idea is to use master and slave Arduinos, the master will send incremental data say x++,

and the Slave has to

  1. receive the data from master, print in serial port
  2. read data from DS1307 and display in LED matrix every second

The idea of having of having multiple master is implemented by having master with address example wire.begin(004) and slave with different address work perfectly as described by Mr. Nick, thanks for his valuable input.

Finally I implemented his idea and got benefited. only two wires are sufficient SCL and SCA.

when communication happening between two devices, the other devices are waiting for the bus to be freed, in which case as multiple masters. thanks for such great idea.

photo for kind reference : Master- Arduino uni, Slave Arduino Nano clone, Clock - DS1307, Display LED Matrix


Thanks

Are both Arduino boards also connected via GND ? I think they are. How can someone wait for the bus to be freed ? Is there some magic I don't know about ?