Open Sayeed97 opened 8 months ago
Issue: Wire.h library has no trace of which device it is talking to other than its I2C address.
Arduino Memory Reference: https://wiki-content.arduino.cc/en/Tutorial/Foundations/Memory
New library features:
In the I2C (Inter-Integrated Circuit) protocol, it is indeed possible to have multiple master devices on the same bus. However, this arrangement requires careful coordination and adherence to specific rules to prevent conflicts and ensure proper communication.
Here are some key points regarding multiple I2C master devices:
Bus Arbitration: When multiple masters share the same I2C bus, they must follow a protocol for bus arbitration. This means that if two or more masters attempt to communicate simultaneously, they need a mechanism to determine which one gets control of the bus. The I2C protocol uses a combination of start/stop conditions and clock stretching to handle this.
Start and Stop Conditions:
Addressing:
Clock Synchronization:
Priority and Design Considerations:
Multi-Master Scenarios:
Both the ESP8266 (NodeMCU) and the Arduino UNO need to run the Wire.h code for successful I2C communication. Let me explain why:
Master-Slave Relationship:
Communication Flow:
Wire.beginTransmission()
function to specify the slave's address and writes data using Wire.write()
.Wire.endTransmission()
.Wire.requestFrom()
to request data from the master.Both Devices Must Participate:
Addressing:
In the I2C (Inter-Integrated Circuit) protocol, it is indeed possible for multiple devices to communicate on the same I2C bus. However, there are some important considerations to keep in mind:
Shared Bus Architecture:
Unique Addresses:
There are three main ways to deal with this:
Hardware Solutions:
Example Scenario:
The two pins which you need for the I2C communication are the following:
SDA (Serial Data): Connection between master and slave to send and receive data. SCL (Serial Clock): Shares the clock signal between the master and the slave, where the master always controls the clock signal. I2C overview
The Serial Data line and the Serial Clock line are pulled up with resistors. Therefore when there is no transmission of data on the bus, the SDA and SCL are in the HIGH state. Why a resistor is needed, see subsection “Physical layer”. Typical voltages are +5V and +3.3V and devices can communicate at 100 kHz or 400 kHz. All I2C devices are connected to the bus either with open collector or open drain pins to pull the line LOW. The communication between master and slave occurs by toggling the lines by pulling LOW and releasing HIGH. Also bits are clocked on falling clock edges.
There may be four potential modes of operation for a given bus device, although most devices only use a single role and its two modes:
master transmit – master node is sending data to a slave, master receive – master node is receiving data from a slave, slave transmit – slave node is sending data to the master, slave receive – slave node is receiving data from the master.
Reference: https://diyi0t.com/i2c-tutorial-for-arduino-and-esp8266/
Arduino Being Slave Code
///Arduino Sketch for Arduino Uno (Slave I2C Device)
#include <Wire.h>
void setup() {
Wire.begin(8); /* join i2c bus with address 8 */
Wire.onReceive(receiveEvent); /* register receive event */
Serial.begin(9600); /* start serial for debug */
}
void loop() {
delay(100);
}
// function that executes whenever data is received from master
void receiveEvent(int howMany) {
while (0 <Wire.available()) {
char c = Wire.read(); /* receive byte as a character */
Serial.print(c); /* print the character */
}
Serial.println(); /* to newline */
}
ESP8266 Being Master Code
//Arduino Sketch for NodeMCU (Master I2C Device)
#include <Wire.h>
#define SDA 4
#define SCL 5
void setup() {
Serial.begin(9600); /* begin serial for debug */
Wire.begin(SDA, SCL); /* join i2c bus with SDA=D1 (GPIO 5) and SCL=D2 (GPIO 4) of NodeMCU */
}
void loop() {
Wire.beginTransmission(8); /* begin with device address 8 */
Wire.write("Hello Arduino"); /* sends hello string */
Wire.endTransmission(); /* stop transmitting */
delay(1000);
}
Original Working Code Reference: https://github.com/microdigisoft/ESP8266-I2C-communication-Using-Arduino/blob/main/i2c_master___salve.ino
Customized the above code to make the Master first send "Hello\n", to which the Slave performs a String match to reply it with its DEVICE_NAME.
UNO Slave Code:
///Arduino Sketch for Arduino Uno (Slave I2C Device)
#include <Wire.h>
#include <string.h>
#define DEVICE_NAME "UNO"
void setup() {
Wire.begin(8); /* join i2c bus with address 8 */
Wire.onReceive(receiveEvent); /* register receive event */
Serial.begin(9600); /* start serial for debug */
}
void loop() {
delay(100);
}
// function that executes whenever data is received from master
void receiveEvent(int howMany) {
String recvInfo;
while (0 <Wire.available()) {
char c = Wire.read(); /* receive byte as a character */
if(c == '\n')
break;
recvInfo += c;
//Serial.print(c); /* print the character */
}
Serial.print(recvInfo);
if(recvInfo == "Hello")
Wire.onRequest(requestEvent);
Serial.println(); /* to newline */
}
// function that executes whenever data is requested from master
void requestEvent() {
Wire.write(DEVICE_NAME); /*send string on request */
}
ESP8266 Master Code:
//Arduino Sketch for NodeMCU (Master I2C Device)
#include <Wire.h>
#define SDA 4
#define SCL 5
void setup() {
Serial.begin(9600); /* begin serial for debug */
Wire.begin(SDA, SCL); /* join i2c bus with SDA=D1 (GPIO 5) and SCL=D2 (GPIO 4) of NodeMCU */
}
void loop() {
Wire.beginTransmission(8); /* begin with device address 8 */
Wire.write("Hello\n"); /* sends hello string */
Wire.endTransmission(); /* stop transmitting */
Wire.requestFrom(8, 3);
Serial.print("Device Name: ");
while(Wire.available()){
char c = Wire.read();
Serial.print(c);
}
Serial.println();
delay(1000);
}
TODO: Switch UNO as the Master and ESP8266 as the Slave; Build and Test.
Write code that can successfully perform I2C communication between Arduino UNO and ESP8266.