Hello Everyone!
I'm currently working on a project where I use the Wire (I2C) library to communicate with the Adafruit BNO055 Absolute Orientation Sensor on one side and the Wire1 library with a Arduino Uno slave device, which is sending a data string to my Arduino Due master device. Both devices are connected via a i2C save level shifter with 3.3kOhm pullups.
Additional, the Arduino Due master is communicating via Ethernet with Matlab Simulink.
The master Arduino is also controlling a BLCD motor which spins very fast and uses a high current. Everything is packed next to each other.
My problem is that my code workes fine when the BLDC motor is not running but when i switch on the motor, after a random time the communication with the slave device break and freeze. I recognize that because the sampling time in Matlab Simulink drops dramatically.
The IC2 Communication on the Master works like:
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
// ---------- Interboard I2C Communication ----------
class I2C_CommunicationClass
{
private:
const int Slave_Address = 42; // I2C Slave Address
static const int BufferSize = 13; // I2C Buffer Size
char recChar;
bool seperatorTrigger; // Seperator Detected - Trigger
int seperatorPos = 0; // Seperator Detected - Position
public:
volatile bool toggleI2C;
// Buffer -> max. I2C Size to avoid overflow if Seperator is not detected
char I2C_Buffer1[BufferSize + 1]; // I2C Data Puffer 1
char I2C_Buffer2[BufferSize + 1]; // I2C Data Puffer 2
public:
void readData()
{
// Empty Char Array Buffers
this->I2C_Buffer1[0] = '0';
this->I2C_Buffer2[0] = '0';
seperatorTrigger = false;
// Stop Active Wire Communication
Wire1.endTransmission();
// Request Data from the I2C Slave
Wire1.requestFrom(Slave_Address, BufferSize);
// Receive Data from I2C Slave
// Slave may Send Less than Requested
if (Wire1.available() == BufferSize) {
// Loop through Buffer Size
for (int i = 0; i < BufferSize; i++) {
// Read each Char from I2C
recChar = Wire1.read(); // receive a byte as character
// Check for Char Seperator -> Set trigger
if (recChar == ';') {
seperatorTrigger = true;
seperatorPos = i + 1;
}
else {
// Write Data to de dependent Buffer
if (!seperatorTrigger) {
// Write I2C Value to Buffer 1
this->I2C_Buffer1[i] = recChar;
}
else {
// Write I2C Value to Buffer 2
this->I2C_Buffer2[i - seperatorPos] = recChar;
}
}
}
// Convert Char Array to Float if Value is not Out of Range
if (atof(this->I2C_Buffer1) <= 360 && atof(this->I2C_Buffer1) > 0.05) {
encoder1.Angle = atof(this->I2C_Buffer1);
}
if (atof(this->I2C_Buffer2) <= 360 && atof(this->I2C_Buffer2) > 0.05) {
encoder2.Angle = atof(this->I2C_Buffer2);
}
}
}
};
For the communication with my IMU the code works like:
// ---------- Adafruit BNO055 IMU ----------
class IMU_BNO055
{
private:
// Sensor Events
sensors_event_t event;
imu::Quaternion quat;
public:
// Adafruit BNO055 9-DOF IMU
Adafruit_BNO055 AdafruitBNO = Adafruit_BNO055(55);
// Orientation variables
float phi, theta, psi;
float Quat_W, Quat_X, Quat_Y, Quat_Z;
// Help variables
bool noBNO055 = false;
volatile bool toggleIMU = false;
// ------------------ Read BNO055 IMU Values -----------------------------
void readBNO055 () {
// ------------------------ Read IMU BNO055 Data -----------------------
// Check if Sensor is Active and IMU toggle is True
if (!noBNO055 && toggleIMU) {
// ---------- Read EULER Angles Adafruit BNO055 IMU Data -------------
this->AdafruitBNO.getEvent(&this->event);
phi = event.orientation.y;
theta = event.orientation.z;
psi = event.orientation.x;
// -------------- Read RAW Adafruit BNO055 IMU Data ------------------
quat = this->AdafruitBNO.getQuat();
Quat_W = quat.w();
Quat_X = quat.x();
Quat_Y = quat.y();
Quat_Z = quat.z();
// Toggle IMU read trigger False until next call
this->toggleIMU = false;
}
}
};
In the main loop I'm just calling the regarding functions from the classes.
The code for the slave device looks like:
void loop()
{
// ----------------- Generate I2C Buffer String -----------------------------
// Convertion from Float to Char-String (For Uno not supported in sprintf)
dtostrf(encoder1.Angle, 5, 2, strEncoder1_Angle);
dtostrf(encoder2.Angle, 5, 2, strEncoder2_Angle);
sprintf(I2C_Buffer, "%s;%s", strEncoder1_Angle, strEncoder2_Angle);
}
// --------------- I2C Communication Event Handler ---------------------------
void requestEvent_I2C() {
// Write I2C Buffer to Connection
Wire.write(I2C_Buffer); // respond with message of 13 bytes
}
I'm not sure what the problem could be. On one hand side i thought about that the i have a buffer overflow if the received string on the master Arduino is wrong or too long. On the other hand side it could be electromagnetic noise from the BLCD motor which influence the I2C communication. I also have some concerns that the wire1 and wire on the Arduino Due are not working proper. I read some topics about bugs in the library.
The strange thing is that if the IMU is physically not connected with the Arduino the master-slave communication does not even work and another thing is that everything works sometimes for 30 seconds or longer and then stops, or sometimes it stops immediately.
Thanks for your input and I appreciate every help. I work on that since 1,5 months and have still no solution.
Best,
Stefan