1. Inside ATmega328P MCU, there is hardware "I2C Interface" (Fig-6.1) to exchange data bit-by-bit with another MCU/Sensor. I2C stands for "Inter-Integrated Circuit". I2C is called bus; because, we can connect more than one MCU/sensor in parallel (Fig-6.2).
Figure-6.1: Formation of I2C bus and its connection between two Arduino
Figure-6.2: Three I2C Bus compatible sensors/devices are connected in parallel
2. The I2C Interface has two lines: SDA (Serial Data Line) and SCL (Serial Clock Line) which form the I2C Bus. The SDA line is bi-directional and caries serial data between UNO (the Master) and NANO (the Slave). The SCL line is uni-directional and carries serial clock from UNO to NANO to push-in and push-out data. The I2C bus system is also known as TWI (Two Wire Interface) bus.
3. (I2C bus formation for Master) SDA and SCL lines of Master will be connected with DPin-A4 and A5 respectively when we include the following lines in Master sketch:
#include<Wire.h> //Library file put in Global space
Wire.begin(); //K1 switch of Fig-6.1 will be closed; put this line in etup() function
4. (I2C bus formation for Slave) SDA and SCL lines of NANO Slave will be connected with DPin-A4 and A5 respectively when we include the following lines in Slave sketch:
#include<Wire.h>
Wire.begin(0x13);//put 7-bit slave address as argument
5. In I2C Bus system, there is one Master which generates SCL signal. The other MCU/sensor devices are Slaves with their own 7-bit addresses. The address range is 0x00 – 0x7F (0000000 – 1111111 = 128) of which 0x00 – 0x07 (0000000 – 000111 = 8) are reserved. The slaves are expected to be within 30 cm to ensure reliable operation.
6. The SDA and SCL lines are terminated at 5V by 2.2k – 10k pull-up resistors.
7. I2C bus is a byte (8-bit) oriented system; where, data is sent and received byte-by-byte. The Slave always sends ACK (acknowledgement = 0) signal to Master after receiving a data byte. As a result, the Master sends the next byte to Slave.
8. The possible data transfer rates (speed) of the I2C bus are:
(1) 100 kbits/s (default Standard Mode)
(2) 400 kbits/s (Fast Mode)
(3) 1 Mbits/s (Fast Mode Plus = Fm+)
(4) 3.4 Mbits/s (High Speed Mode)
9. The following instruction is used to change the data transfer rate of I2C bus.
Wire.setClock(clockFrequency); //clockFrequency is in Hz. 400 kHz 400x1000 = 400000
10. (Checking the presence of Slave) The Master/UNO of Fig-6.1 checks the presence of the Slave/NANO by executing the following codes: (This is known as Roll Calling.)
Wire.beginTransmission(7-bitSlaveAddress); //START command; roll call; ACK = 0 comes
byte busStatus = Wire.endTransmission(); //STOP command to get ACK in busStatus
if(busStatus == 0x00) //busStatus = 0x00 means Slave is found on the I2C bus
{
Serial.print(“Slave is found on the I2C Bus!”);
}
else
{
Serial.print(“Slave is not found…!”);
while(1); //wait here for ever
}
Note: We have said that I2C bus is a byte oriented system. In Roll Calling, the Slave address is only 7-bit data (0010011). The Master makes it 8-bit by putting “zero (0)” or “one (1)” at the right-most position of the address. Zero is appended in “Write Mode”; where, Master sends/writes something to Slave. One is appended in “Read mode”; where, Master wants to read something from Slave.
11. (Data Write Mode) The Master executes the following codes to write/send a data byte (say: 0x32) into the Slave/NANO:
Wire.beginTransmission(0x13); //7-bitSlaveAddress; START command; roll call, ACK = 0 comes
Wire.write(0x32); //0x32 goes to NANO and automatically saved in FIFO BUFFEer, ACK=0 comes
byte busStatus = Wire.endTransmission(); //STOP command, and I2C bus is free
Note: Two ACK signals are sent by Slave one after another after receiving “address bits +R-W/” and 0x32. If UNO receives these two ACK signals correctly, it puts 0x00 in the busStatus variable.
12. (Collection of data byte 0x32 by Slave) When the above data byte (0x32) of Step-11 reaches to Slave and enters into BUFFer, the Slave is automatically interrupted. The Slave goes to receiveEvent() Interrupt Sub Routine (ISR), reads data from BUFFER, and sets a flag to true state. The flag is tested in loop() function (Step-13) to show data onto Serial Monitor. Note that print() and write() methods are not allowed in ISR; perform them in loop() functio. The codes are:
volatile bool flag = false; //put in Global Space; why volatile keyword is here?
byte y; //declare in Global space
Wire.onReceive(receiveEvent); //put this code in setup() function; declaration of ISR
void receiveEvent(int howMany) //put this Interrupt Sub Routine (ISR) in User Space
{ //howMany holds a number that is equal to data bytes received
y = Wire.read(); //bring data from BUFFer and keep in y; do print() in loop()
flag = true; //a data byte has been stored in BUFFer
}
13. (Slave shows data in Serial Monitor) The Slave/NANO performs the following codes in the loop() function to read the data byte (0x32) of Step-11 from the I2C BUFFer and show it on Serial Monitor. It is not allowed to give print() or write() ommand in ISR routine; always, do it in the loop() function.
void loop()
{
if(flag == true) //to be sure that there is a data byte in BUFFer
{
Serial.println(y, HEX); //show the data byte on Serial Monitor
flag = false; //reset the flag
}
}
14. (Send 2-byte data) Class Work: (a) Write just the necessary codes for Master/UNO of Fig-6.1 to send int y = 0x1234 to Slave/NANO.
Wire.beginTransmission(0x13); //Slave address
Wire.write(highByte(y)); //MSByte of data goes first
Wire.write(lowByte(y));
byte busStatus = Wire.Wire.endTransmission();
(b) Write just the necessary codes for Slave/NANO to receive the data bytes of Step-14(a) and show it on Serial Monitor.
(c) Write codes for Master to send “OK” to Slave. Slave will receive it and show on SM2.
15. (Master requests Slave to give data (Read Mode)) Master/UNO of Fig-6.1 executes the following code to get 1-byte data (say: 0x45) from Slave.
byte m = Wire.requestFrom(7-bitSlaveAddress, n); //addr is made 8-bit with 1 at the right
Where:
n = number of bytes requested by Master
m = number of bytes actually received
... see next post.