Internal EEPROM read conflicts with IMU sensor communication

Hello everyone,

I have 6 IMUs that I'm reading data from, so I use a multiplexer to switch between them. Today i calibrated the sensors and saved the values in the EEPROM of the Arduino Mega that I'm using. The code i used for saving the values comes from this post. Then, I created the calibrations functions that read from the EEPROM. After uploading the code, the arduino mega cannot identify the sensors. I tried connecting my other arduino mega, with the original code (without the calibration functions), and it worked as expected. Then I uploaded the new sketch (with the calibrations functions) and it stopped working again. I tried re-uploading the first sketch but the problem remained.

After @er_name_not_found's suggestion I'm posting the code in code tags. Thanks for the tip and the welcome!

The TCA communication code without the calibration functions

#include <Adafruit_FXOS8700.h>
#include <Adafruit_FXAS21002C.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

#define TCAADDR 0x70
#define FRAMESIZE (45) //(1 + 4 + 4*3 + 4*3 + 4 + 4*3)
//                accmag timestamp uint long + 3 floats acc + 3 floats mag + gyro timestamp uint long
#define NUMSENSORS 6

/* Assign a unique ID to this sensor at the same time */
Adafruit_FXOS8700 accelmag0 = Adafruit_FXOS8700(0x8700A, 0x8700B);
Adafruit_FXAS21002C gyro0 = Adafruit_FXAS21002C(0x0021002C);
byte dataframe[FRAMESIZE] ={0x00};
unsigned long timestamp;

void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
//  Wire.write(1 << i);
  Wire.endTransmission();

}

void displaySensorDetails(void) {
  sensor_t accel, mag, gy;
  accelmag0.getSensor(&accel, &mag);
  gyro0.getSensor(&gy);
  Serial.println("------------------------------------");
  Serial.println("ACCELEROMETER");
  Serial.println("------------------------------------");
  Serial.print("Sensor:       ");
  Serial.println(accel.name);
  Serial.print("Driver Ver:   ");
  Serial.println(accel.version);
  Serial.print("Unique ID:    0x");
  Serial.println(accel.sensor_id, HEX);
  Serial.print("Min Delay:    ");
  Serial.print(accel.min_delay);
  Serial.println(" s");
  Serial.print("Max Value:    ");
  Serial.print(accel.max_value, 4);
  Serial.println(" m/s^2");
  Serial.print("Min Value:    ");
  Serial.print(accel.min_value, 4);
  Serial.println(" m/s^2");
  Serial.print("Resolution:   ");
  Serial.print(accel.resolution, 8);
  Serial.println(" m/s^2");
  Serial.println("------------------------------------");
  Serial.println("");
  Serial.println("------------------------------------");
  Serial.println("MAGNETOMETER");
  Serial.println("------------------------------------");
  Serial.print("Sensor:       ");
  Serial.println(mag.name);
  Serial.print("Driver Ver:   ");
  Serial.println(mag.version);
  Serial.print("Unique ID:    0x");
  Serial.println(mag.sensor_id, HEX);
  Serial.print("Min Delay:    ");
  Serial.print(accel.min_delay);
  Serial.println(" s");
  Serial.print("Max Value:    ");
  Serial.print(mag.max_value);
  Serial.println(" uT");
  Serial.print("Min Value:    ");
  Serial.print(mag.min_value);
  Serial.println(" uT");
  Serial.print("Resolution:   ");
  Serial.print(mag.resolution);
  Serial.println(" uT");
  Serial.println("------------------------------------");
  Serial.println("");
  Serial.println("------------------------------------");
  Serial.println("GYROSCOPE");
  Serial.println("------------------------------------");
  Serial.print("Sensor:       ");
  Serial.println(gy.name);
  Serial.print("Driver Ver:   ");
  Serial.println(gy.version);
  Serial.print("Unique ID:    0x");
  Serial.println(gy.sensor_id, HEX);
  Serial.print("Max Value:    ");
  Serial.print(gy.max_value);
  Serial.println(" rad/s");
  Serial.print("Min Value:    ");
  Serial.print(gy.min_value);
  Serial.println(" rad/s");
  Serial.print("Resolution:   ");
  Serial.print(gy.resolution);
  Serial.println(" rad/s");
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}

void setup(void) {
  Serial.begin(115200);
  
  /* Wait for the Serial Monitor */
  while (!Serial) {
    delay(1000);
  }
  Wire.begin();
  for (uint8_t i=0; i<NUMSENSORS; i++) {
    delay(100);
    Serial.println("NXPsensor Test Accel+Gyro Test");
    Serial.println("");
    tcaselect(i);
    
    
    /* Initialise the sensor */
    if (!gyro0.begin()) {
      /* There was a problem detecting the FXAS21002C ... check your connections
       */
      Serial.println("Ooops, no FXAS21002C detected ... Check your wiring!");
      while (1)
        ;
    }
    
    /* Initialise the sensor */
    if (!accelmag0.begin(ACCEL_RANGE_4G)) {
      /* There was a problem detecting the FXOS8700 ... check your connections */
      Serial.println("Ooops, no FXOS8700 detected ... Check your wiring!");
      while (1)
        ;
    }
    
    
    /* Display some basic information on this sensor */
    displaySensorDetails();
  }
  

  timestamp = micros();
}
// https://arduino.stackexchange.com/questions/60863/print-byte-array-in-serial-monitor-screen-of-arduino-ide
//void printHex(uint8_t num) {
//  char hexCar[2];
//
//  sprintf(hexCar, "%02X", num);
//  Serial.print(hexCar);
//}
void loop(void) {
  

//  // Set sr to 100 Hz.
  if ( micros() - timestamp <10000 - 10) {
    // test micros()-timestamp>10000 ? delay( (micros()- timestamp-1000)/1000 : ; // delay for something less than time remaining only if there is a lot of time left
    return;
  }
  timestamp = micros();
  for (uint8_t i=0; i<NUMSENSORS; i++)  {
    tcaselect(i); //Change sensor
    sensors_event_t aevent, mevent, gevent; //Nikos
    /* Get a new sensor event */
    accelmag0.getEvent(&aevent, &mevent);
    gyro0.getEvent(&gevent);
    
    /* dataframe:
     * |UINT8_T| ULONG | FLOAT | FLOAT | FLOAT | FLOAT | FLOAT | FLOAT | ULONG | FLOAT | FLOAT | FLOAT |
     * |   -   |- - - -|- - - -|- - - -|- - - -|- - - -|- - - -|- - - -|- - - -|- - - -|- - - -|- - - -|
     * |sensor | accts | acc.x | acc.y | acc.z | mag.x | mag.y | mag.z | gyrts | gyr.x | gyr.y | gyr.z |
     * |   #   |  μs   | m/s^2 | m/s^2 | m/s^2 |  uT   |  uT   |  uT   |  μs   | rad/s | rad/s | rad/s |
     *
     */
    
    dataframe[0] = i;
    memcpy(&dataframe[1], &aevent.timestamp, 4);
    memcpy(&dataframe[5], &aevent.acceleration, 12);
    memcpy(&dataframe[17], &mevent.magnetic, 12);
    memcpy(&dataframe[29], &gevent.timestamp, 4);
    memcpy(&dataframe[33], &gevent.gyro, 12);
    Serial.println("");
    Serial.write(dataframe, FRAMESIZE);
  }
  
//  delay(10);
}

The calibration functions

template <class T> int EEPROM_readAnything(int ee, T& value)
{
    byte* p = (byte*)(void*)&value;
    int i;
    for (i = 0; i < sizeof(value); i++)
        *p++ = EEPROM.read(ee++);
    return i;
}

void getCalibration(int noIMU, double calibration[]){
  unsigned int baseAddrTest = noIMU*12*4;
    for (int i=0; i <= 11; i++){
      double val;
      int addr = (i*4)+baseAddrTest;
      EEPROM_readAnything( addr, val);
      calibration[i];
    }
  return;
}

bool calibrate_mag(sensors_event_t &mag_event, int noIMU){
    double calibration[12];
    getCalibration(noIMU, calibration);
    float mx = mag_event.magnetic.x - calibration[0];
    float my = mag_event.magnetic.y - calibration[1];
    float mz = mag_event.magnetic.z - calibration[2];

    mag_event.magnetic.x = mx * calibration[3] + my * calibration[6] + mz * calibration[7];
    mag_event.magnetic.y = mx * calibration[6] + my * calibration[4] + mz * calibration[8];
    mag_event.magnetic.z = mx * calibration[7] + my * calibration[8] + + mz * calibration[5];
}

bool calibrate_gyro(sensors_event_t &gyro_event, int noIMU){
  double calibration[12];
  getCalibration(noIMU, calibration);
  gyro_event.gyro.x -= calibration[9];
  gyro_event.gyro.y -= calibration[10];
  gyro_event.gyro.z -= calibration[11];
  return true;
}

The EEPROM read/write sketch

#include <EEPROM.h>


template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    int i;
    for (i = 0; i < sizeof(value); i++)
        EEPROM.write(ee++, *p++);
    return i;
}

template <class T> int EEPROM_readAnything(int ee, T& value)
{
    byte* p = (byte*)(void*)&value;
    int i;
    for (i = 0; i < sizeof(value); i++)
        *p++ = EEPROM.read(ee++);
    return i;
}

unsigned int noIMU = 5;
double calibration[12] = {13.73, -33.57, -44.06, 0.0975, 0.964, 1.067, 0.033, -0.026, 0.024, -0.0082, -0.0164, -0.0003};
byte noElem = 12;
unsigned int baseAddr = noIMU*12*4;
unsigned int baseAddrTest;
unsigned int n = 0;

void setup() {
  Serial.begin(9600);

////  // write data to eeprom 
//  for (int i=0; i <= noElem-1; i++){
//    n = EEPROM_writeAnything( (i*4)+baseAddr, calibration[i]);
//  }

  // read data back
  for (int NI=0; NI<=5; NI++){
    Serial.print("Number of IMU:");
    Serial.println(NI);
    baseAddrTest = NI*12*4;
    for (int i=0; i <= noElem-1; i++){
      double val;
      int addr = (i*4)+baseAddrTest;
      n = EEPROM_readAnything( addr, val);
      Serial.println(val,4);
    }
  }
  
}

void loop() {
}

Any ideas?

1 Like

Can you please post your code in code tags </> so everyone can read it?

Also, welcome to the forum :smiley:

1 Like

Not sorting your problem.

Any reason why you don't use EEPROM.put() and EEPROM.get(); the post that you linked is from an era that those functions did not exists :wink: They can store and read any type of variable.

1 Like

This function is a very complex way to do nothing.
The compiler will probably remove it.

return; as the last statement of a void function is rather pointless.

1 Like

Thanks for the reply @sterretje

Will definitely use these two functions from now on, thanks for pointing that out. The problem still remains though. As I mentioned in the original post, even when using the first sketch, that doesn't read anything from the EEPROM, I get "Ooops, no FXAS21002C detected ... Check your wiring!", which means that arduino cannot find the sensors.

Hello @Whandall thanks for replying,

As I pointed out in my original question, the problem remains even when using the first sketch that doesn't include the getCalibration function. Other than that, thanks for the tip, I'm going to make some changes to the code.

I should point out that I checked the I2C communication with the multiplexer using the code below and, as it turns out, the IMUs are visible to the arduino board.

The code for checking the multiplexer communication:

#include "Wire.h"
extern "C" { 
#include "utility/twi.h"  // from Wire library, so we can do bus scanning
}
 
#define TCAADDR 0x70
 
void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}
 
 
// standard Arduino setup()
void setup()
{
    while (!Serial);
    delay(1000);
 
    Wire.begin();
    
    Serial.begin(115200);
    Serial.println("\nTCAScanner ready!");
    
    for (uint8_t t=0; t<8; t++) {
      tcaselect(t);
      Serial.print("TCA Port #"); Serial.println(t);
 
      for (uint8_t addr = 0; addr<=127; addr++) {
        if (addr == TCAADDR) continue;
      
        uint8_t data;
        if (! twi_writeTo(addr, &data, 0, 1, 1)) {
           Serial.print("Found I2C 0x");  Serial.println(addr,HEX);
        }
      }
    }
    Serial.println("\ndone");
}
 
void loop() 
{
}

After running the above code I get:

*TCAScanner ready!
TCA Port #0
Found I2C 0x1F
Found I2C 0x21
TCA Port #1
Found I2C 0x1F
Found I2C 0x21
TCA Port #2
Found I2C 0x1F
Found I2C 0x21
TCA Port #3
Found I2C 0x1F
Found I2C 0x21
TCA Port #4
Found I2C 0x1F
Found I2C 0x21
TCA Port #5
Found I2C 0x1F
Found I2C 0x21
TCA Port #6
TCA Port #7
*

The result above basically says that at ports 0, 1, 2, 3, 4 and 5 there are two different devices at 0x1F (accelerometer and magnetometer) and 0x21 (gyro).

So, my assumption is that the problem lies somewhere in the Adafruit's libraries

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