I2C. Error when I try to send the roll angle between two Arduinos

Hi Friends!
I have a problem and please I need your help. I want to send the roll angle from one Arduino to another Arduino through I2C. But when I try it, the COM port stops working, my Arduino IDE crashes, all become crazy. However, the codes work perfect separately, but when I try to transmit the Roll angle from an Arduino Nano 33 IoT to a MEGA 2560, strange things happen. In other words, the code of angle roll from Arduino nano 33 IoT works perfectly. And the code to transmit a float from an Arduino nano 33 IoT to Mega works perfect, as well. But, when I mix it and I try to send the roll values, not work it. i share the codes with you…maybe you could help me.
Thank you very much!

MASTER - ARDUINO MEGA 2560

I try to receive the roll angle from an Arduino nano 33 IoT into Mega 2560.

#include "Wire.h"
const byte I2C_SLAVE_ADDR = 0x60;
float response = 0;

void setup()
{
   Serial.begin(115200);
   Wire.begin();
}

void loop()
{
   
   requestToSlave();
   delay(2000);
}


void requestToSlave()
{
   response = 0;
   Wire.requestFrom(I2C_SLAVE_ADDR, sizeof(response));

   uint8_t index = 0;
   byte* pointer = (byte*)&response;
   while (Wire.available())
   {
      *(pointer + index) = (byte)Wire.read();
      index++;
   }

   Serial.println(response);
}

SLAVE - ARDUINO NANO 33 IoT

I try to send from Arduino nano 33 IoT to Mega 2560 the roll angle.

#include "Wire.h"
#include <Arduino_LSM6DS3.h>
#include <MadgwickAHRS.h>

// initialize a Madgwick filter:
Madgwick filter;
// sensor's sample rate is fixed at 104 Hz:
const float sensorRate = 104.00;

const byte I2C_SLAVE_ADDR = 0x60;
// values for orientation:


void setup()
{
  Serial.begin(115200);
  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU");
    // stop here if you can't access the IMU:
    while (true);
  }
  // start the filter to run at the sample rate:
  filter.begin(sensorRate);

  Wire.begin(I2C_SLAVE_ADDR);
  Wire.onRequest(requestEvent);
}

void requestEvent()
{
  float roll;
  // values for acceleration & rotation:
  float xAcc, yAcc, zAcc;
  float xGyro, yGyro, zGyro;

  // check if the IMU is ready to read:
  if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
    // read accelerometer & gyrometer:
    IMU.readAcceleration(xAcc, yAcc, zAcc);
    IMU.readGyroscope(xGyro, yGyro, zGyro);

    // update the filter, which computes orientation:
    filter.updateIMU(xGyro, yGyro, zGyro, xAcc, yAcc, zAcc);

    // print the heading, pitch and roll
    roll = filter.getRoll();
    Wire.write((byte*)&roll, sizeof(roll));
  }

}


void loop() {


}

The IMU on the Nano IoT is connected using the i2c bus so you can not read it while in the middle of an i2c event inside requestEvent().

You will have to either

  1. always read it in loop() and when the request comes in, just return the global value
  2. make it such that you send a request to read the value, the receiver sets a flag and then reads in loop() and then you send a different request to fetch it
1 Like

Thank you very much blh64,
I did the first point (I think…). But, I don’t understand:

  1. make it such that you send a request to read the value, the receiver sets a flag and then reads in loop() and then you send a different request to fetch it
#include "Wire.h"
#include <Arduino_LSM6DS3.h>
#include <MadgwickAHRS.h>

// initialize a Madgwick filter:
Madgwick filter;
// sensor's sample rate is fixed at 104 Hz:
const float sensorRate = 104.00;

const byte I2C_SLAVE_ADDR = 0x20;

float roll;

void setup()
{
  Serial.begin(115200);
  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU");
    // stop here if you can't access the IMU:
    while (true);
  }
  // start the filter to run at the sample rate:
  filter.begin(sensorRate);

  Wire.begin(I2C_SLAVE_ADDR);
  Wire.onRequest(requestEvent);
}

void requestEvent()
{
  Wire.write((byte*)&roll, sizeof(roll));
}

void loop() {

  // values for acceleration & rotation:
  float xAcc, yAcc, zAcc;
  float xGyro, yGyro, zGyro;

  // check if the IMU is ready to read:
  if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
    // read accelerometer & gyrometer:
    IMU.readAcceleration(xAcc, yAcc, zAcc);
    IMU.readGyroscope(xGyro, yGyro, zGyro);

    // update the filter, which computes orientation:
    filter.updateIMU(xGyro, yGyro, zGyro, xAcc, yAcc, zAcc);

    // print the heading, pitch and roll
    roll = filter.getRoll();
  }
}

It is like other i2c devices where you write a value to a register that initiates something and then you read back the status until is says “ready” and then read the value. All this extra work is only needed if you only want the slave to read upon demand.

The much easier route is to make the slave hold the current value in a global variable and refresh it every time through loop() or every x milliseconds and then when the master requests the value, just reply with the current value held in the global variable.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.