I2C on Arduino Mega / ESP32

We need to read rotational data from the HMC5883L Sensor. This is the code I used for Calibration of this sensor on the Arduino Mega:

#include <Wire.h>



const int hmc5883Adresse = 0x1E; //0011110b, I2C 7-Bit Addresse des HMC5883L
const int hmc5883ModeRegister      = 0x02;
const int hmcContinuousMode        = 0x00;
const int hmcDataOutputXMSBAdresse = 0x03;


float minX = 0;
float maxX = 0;
float minY = 0;
float maxY = 0;
float XOffset = 0;
float YOffset = 0;
float XScale = 0;
float YScale = 0;

long unsigned int timestart = 0;
long unsigned int dauer = 12; //Dauer in Sekunden

int x,y,z; // 3 Achsen


void setup(){
  dauer *= 1000;
  Serial.begin(9600);
  Wire.setClock(100000);

  Wire.begin();
  Wire.beginTransmission(hmc5883Adresse); // Verbindung öffnen mit dem HMC5883
    Wire.write(hmc5883ModeRegister); // Mode Register
    Wire.write(hmcContinuousMode);   // Kontinuierliche Messung
  Wire.endTransmission();
  
  timestart = millis();
}

void loop(){

  x = 0;
  y = 0;
  z = 0;
  
  if (millis() < (dauer + timestart)) {
    
    Wire.beginTransmission(hmc5883Adresse);
    Wire.write(hmcDataOutputXMSBAdresse); // Register 3, X MSB Register
    Wire.endTransmission();
    Wire.requestFrom(hmc5883Adresse, 6);


    x = Wire.read() << 8 | Wire.read();
    y = Wire.read() << 8 | Wire.read();
    z = Wire.read() << 8 | Wire.read();

    Serial.print(x);
    Serial.print("\t");
    Serial.println(y);
    
    if (x < minX) minX = x;
    if (x > maxX) maxX = x;
    if (y < minY) minY = y;
    if (y > maxY) maxY = y;
  
    delay(5);
}

else {
    float tempXScale = (maxY - minY) / (maxX - minX);
    if (tempXScale > 1) {
     XScale = tempXScale;
    }
    else {
        XScale = 1;
    }
  
    float tempYScale = (maxX - minX) / (maxY - minY);
    if (tempYScale > 1) {
      YScale = tempYScale;
    }
    else {
      YScale = 1;
    }
    
    XOffset = (((maxX - minX) / 2) - maxX) * XScale;
    YOffset = (((maxY - minY) / 2) - maxY) * YScale;
  
    while(1);
  }
}

The code communicates with the Sensor to read the raw values and computes calibration errors in the end.
It runs perfectly on the Arduino Mega, but now I need to port it to the ESP32. It compiles however the values I get from the sensor readings are nonsense (I used the exact same sensor as with the Mega where they're normal), with huge spikes like this:

20:48:16.778 -> 29	65051
20:48:16.778 -> 29	65051
20:48:16.778 -> 29	65051
20:48:16.809 -> 29	65051
20:48:16.809 -> 29	65051
20:48:16.809 -> 29	65051
20:48:16.841 -> 29	65051
20:48:16.841 -> 29	65051
20:48:16.841 -> 65531	65024
20:48:16.874 -> 65531	65024
20:48:16.874 -> 65531	65024
20:48:16.874 -> 65531	65024
20:48:16.905 -> 65531	65024
20:48:16.905 -> 65528	65025
20:48:16.937 -> 65528	65025
20:48:16.937 -> 65528	65025
20:48:16.970 -> 65528	65025
20:48:16.970 -> 65528	65025
20:48:16.970 -> 65528	65025
20:48:17.002 -> 65528	65025
20:48:17.002 -> 65528	65025
20:48:17.033 -> 65528	65025
20:48:17.033 -> 65528	65025
20:48:17.065 -> 65528	65025
20:48:17.065 -> 65524	65022
20:48:17.065 -> 65524	65022
20:48:17.098 -> 65524	65022
20:48:17.098 -> 6	65033
20:48:17.130 -> 6	65033
20:48:17.130 -> 6	65033
20:48:17.130 -> 6	65033
20:48:17.130 -> 6	65033
20:48:17.161 -> 6	65033
20:48:17.161 -> 6	65033

I think there is something different with the I2C Protocol between the chips or maybe something with how the variables work. But I couldn't find anything useful to fix it.
So thank you in advance :slight_smile:

Is the sensor powered by 5V or 3V3 ?

Always show us a good schematic of your proposed circuit. Show us good images of your ‘actual’ wiring. Give links to components.

In the Arduino IDE, use Ctrl T or CMD T to format your code then copy the complete sketch. Use the < CODE / > icon from the ‘posting menu’ to attach the copied sketch.

I guess that you have problems with 16 and 32 bit. Use a more precise data type like int16_t.

3 Likes

Wow that is the solution, thank you :+1:
Could you explain what the difference between Mega and ESP is in this case?

The MPU-6050 has 16-bit signed integers. They are transferred over the I2C bus as two bytes.

With this on the Arduino Mega:

x = Wire.read() << 8 | Wire.read();

Then the highest byte from the sensor is shifted into the highest byte of the 16 bit variable and the sign bit drops nicely into its place.

On the ESP32, the 'int' is 32 bits. Whatever is done in the lowest two bytes, the overall value stays positive and a negative number from the sensor is seen as something like 65051.

By the way, this code is a bit scary :grimacing:

x = Wire.read() << 8 | Wire.read();

The order in which the functions are called and are used for the high and low byte is left-to-right in some C++ versions and it is not specified in other C++ versions.

Ah okay that makes totally sense, thank you! Don't know how I didn't think of that. I will also consider changing the code :smiley: I thought it looked the cleanest like this

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