Hello,
I am trying to send data via I2C in both ways between two microcontrollers.
One being an ESP32 (slave) and the other being an Arduino Micro (Master).
For the ESP32 i used this ESP32-I2C Library: GitHub - gutierrezps/ESP32_I2C_Slave: I2C slave library for ESP32
I was successful in building a connection between the two microcontrollers and sending data in both directions.
The Problem is, that the Arduino Micro crashes after a maximum of around 2 minutes...
I already discovered that it has to do something with the "slaveReq.request();" command in the "ReadData()" function. The request fails and then the Arduino normally crashes.
I tried to reset the bus when this happens, so i added
TWCR = 0; //resets I2C-Connection
Wire.begin(); //restart I2C-Connection
This seems to work a few times, but the Arduino still crashes after seconds to minutes.
What I also tried so far:
- trying both libraries on the Arduino Micro. For reading only the ESP Library works.
- shuffling around the sequence of reading and writing
- messing around with the delays. 10s between reading and writing seems to work best...
- connecting the 3.3V Pin on the ESP with the 3V Pin on the Arduino (instead of the 5V Pins). Works, but not better
I am starting to run out of ideas... I am wondering if the following might work, but I have no Idea on how to try that:
- do i need pull up resistors or a voltage converter?
- I have read about interrupts in I2C. Could that help me?
Maybe you can help me...
Here is my code:
Master(Arduino Micro):
#include <Arduino.h>
#include <Wire.h>
#include <WirePacker.h>
#include <WireSlaveRequest.h>
// define the device name of this device
#define device 0x04
// define the max amount of bytes which are awaited from the i2c connection
#define MAX_SLAVE_RESPONSE_LENGTH 32
int x = 0;
char i2c_buffer[7] = "x is: ";
char dataIn_gl[6] = {'0', '0', '0', '0', '0'};
void setup() {
Serial.begin(115200);
Wire.begin(0x04); // join i2c bus (address optional for master)
}
void loop() {
//ESP to Lucy
ReadData();
delay(10);
//Lucy to ESP
WirePacker packer;
char cstr[1];
itoa(x,cstr,10);
//Serial.println(cstr);
i2c_buffer[6] = cstr[0];
//Serial.println(i2c_buffer);
// then add data the same way as you would with Wire
packer.write(i2c_buffer);
// after adding all data you want to send, close the packet
packer.end();
Wire.beginTransmission(0x04); // transmit to device #8
//Serial.println(packer.available());
while (packer.available()) {
Wire.write(packer.read());
}
Wire.endTransmission(); // stop transmitting
Serial.print("Transmission of '");
Serial.print(i2c_buffer);
Serial.println("' successful");
x++;
if(x>9){
x=0;
}
delay(10);
}
void ReadData()
{
// initialies the array for the state input of the i2c connection
char dataIn[5] = {'0', '0', '0', '0', '0'};
// ask for data at address specified by defvice
WireSlaveRequest slaveReq(Wire, device, MAX_SLAVE_RESPONSE_LENGTH);
//Serial.println("req class erstellt");
slaveReq.setRetryDelay(5);
//if the request was succsessful read the data byte for byte and flush the rest
bool success = slaveReq.request();
Serial.println(success);
if (success)
{
Serial.println("request successful");
dataIn[0] = slaveReq.read();
dataIn[1] = slaveReq.read();
dataIn[2] = slaveReq.read();
dataIn[3] = slaveReq.read();
dataIn[4] = slaveReq.read();
for (int i = 0; i<=4; i++){
dataIn_gl[i] = dataIn[i];
}
Serial.print("dataIn_gl: ");
Serial.println(dataIn_gl);
Serial.println();
while (0 > slaveReq.available()) { // loop through all but the last byte
char c = slaveReq.read(); // receive byte as a character
}
}
else if (!success){
Serial.println("request failed!!!!");
Serial.println(slaveReq.lastStatusToString());
TWCR = 0; //resets I2C-Connection
Wire.begin(); //restart I2C-Connection
}
}
Slave(ESP32):
#include <Arduino.h>
#include <Wire.h>
#include <WireSlave.h>
#define SDA_PIN 21
#define SCL_PIN 22
#define I2C_SLAVE_ADDR 0x04
char result[7];
char i2c_buffer[5] = {'1', '2', '3', '4', '5'};
void receiveEvent(int howMany);
void setup()
{
Serial.begin(115200);
bool success = WireSlave.begin(SDA_PIN, SCL_PIN, I2C_SLAVE_ADDR);
if (!success) {
Serial.println("I2C slave init failed");
while(1) delay(100);
}
else {
Serial.println("I2C slave init successful");
}
WireSlave.onReceive(receiveEvent);
WireSlave.onRequest(requestEvent);
}
void loop()
{
// the slave response time is directly related to how often
// this update() method is called, so avoid using long delays
// inside loop(), and be careful with time-consuming tasks
WireSlave.update();
Serial.print("result = ");
Serial.println(result);
// let I2C and other ESP32 peripherals interrupts work
delay(10);
}
// function that executes whenever a complete and valid packet
// is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
int i = 0;
while (1 < WireSlave.available()) // loop through all but the last byte
{
char c = WireSlave.read(); // receive byte as a character
Serial.print(c); // print the character
result[i] = c;
i++;
}
char x = WireSlave.read(); // receive byte as an integer
Serial.println(x); // print the integer
result[i] = x;
}
void requestEvent()
{
//Write values of buffer via i2c
WireSlave.write(i2c_buffer);
//newval = false;
}