Use this forum to chat about hardware specific topics for the ESP8266 (peripherals, memory, clocks, JTAG, programming)

User avatar
By alex_g
#68129 I have been trying to get this magnetometer to work - to no avail.
These are the common, cheap HMC5883L magnetometers available on well known reprobate auction sites, I'll post a link if necessary, but I suspect you know the ones - 5 pins: Vcc, Gnd, SCL, SDA and unused DRDY.

I got one module and tried it with NodeMCU/Lua - no luck, it just reported device not found. I then tried with the common Arduino scripts given, no luck here, either, it appeared not to be connecting. I tried with various ESP8266 devices, no difference. Then I assumed the magnetometer was blown so I ordered a couple more, but now that these have arrived, same problem, they just don't seem to register.

I am a newbie to I2C, so I ran the following scan, while having two devices on the bus (the second one was a u8g OLED.:
Code: Select all#include <Wire.h>

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

  // Leonardo: wait for serial port to connect
  while (!Serial)
    {
    }

  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
  byte count = 0;
 
  Wire.begin();
  for (byte i = 1; i < 120; i++)
  {
    Wire.beginTransmission (i);
    if (Wire.endTransmission () == 0)
      {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);
      Serial.println (")");
      count++;
      delay (1);  // maybe unneeded?
      } // end of good response
  } // end of for loop
  Serial.println ("Done.");
  Serial.print ("Found ");
  Serial.print (count, DEC);
  Serial.println (" device(s).");
}  // end of setup

void loop() {}


It found the two devices, reporting thus:
Code: Select allI2C scanner. Scanning ...
Found address: 13 (0xD)
Found address: 60 (0x3C)
Done.
Found 2 device(s).

I know that 0x3C is the u8g display, so the HMC5883L is 0xD. I tested three different magnetometers, they all reported the same address (0xD)

Looking through the HMC5833L.h code, I was surprised to see that the hardcoded address for the magnetometer is 0x1E. I tried changing that to 0x0D but still no joy.

In both cases I get the a constant, unchanging value back, although it is different if I change the hardcoded address. The code is a pretty standard example, FWIW here it is...

Code: Select all
// Reference the I2C Library
#include <Wire.h>

// Reference the HMC5883L Compass Library
#include <HMC5883L.h>

// Store our compass as an object.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;
 



// Out setup routine, here we will configure the microcontroller and compass.
void setup()
{
  Wire.begin(); // Start the I2C interface.

  // Initialize the serial port.
  Serial.begin(9600);

  Serial.println("Starting the I2C interface.");

  Serial.println("Constructing new HMC5883L");
  compass = HMC5883L(); // Construct a new HMC5883 compass.
  //The implementation of the class is provided in the library
 
  // Now we have an istance of the class!
  //Let's initializate it...

  // Now we have an istance of the class!
  //Let's initializate it...
 
  Serial.println("Setting scale to +/- 1.3 Ga");
  error = compass.SetScale(1.3); // Set the scale of the compass to 1.3Ga
  if(error != 0){ // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
    error =0;
  }

  Serial.println("Setting measurement mode to continous.");
  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) {// If there is an error, print it out.
    Serial.println(compass.GetErrorText(error)); //Todo: Error handling for this method in .h and .cpp
    error=0;
  }


  //=======================================

  // AG - extra connection check
  Serial.print("Checking connection... ");
  error = compass.EnsureConnected();
  if(error == 0) {
    Serial.println("Not Connected");}
  else {
    Serial.println(" Connected");}
  error =0;
 
}


// Our main program loop.
void loop()
{
  // Retrieve the raw values from the magnetometer (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrieve the scaled values from the magnetometer (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();

  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  // Atan2() automatically check the correct formula taking care of the quadrant you are in
  float heading = atan2(scaled.YAxis, scaled.XAxis);

  // Once you have your heading, you must then add your 'Declination Angle',
  // which is the 'Error' of the magnetic field in your location. Mine is 0.0404
  // Find yours here: http://www.magnetic-declination.com/
 
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  float declinationAngle = 0.0404;
  heading += declinationAngle;

  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;

  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;

  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI;

  // Output the data via the serial port.
  Output(raw, scaled, heading, headingDegrees);

  // By default the HMC5883L reads the data 15 time per second (15Hz)
  // However since we have a long serial out (104ms at 9600) we will let
  // it run at its natural speed.
   delay(2000);
}

// Output the data down the serial port.
void Output(MagnetometerRaw raw, MagnetometerScaled scaled, float heading, float headingDegrees)
{
  Serial.print("Raw:\t");
  Serial.print(raw.XAxis);
  Serial.print("   ");   
  Serial.print(raw.YAxis);
  Serial.print("   ");   
  Serial.print(raw.ZAxis);
  Serial.print("   \tScaled:\t");

  Serial.print(scaled.XAxis);
  Serial.print("   ");   
  Serial.print(scaled.YAxis);
  Serial.print("   ");   
  Serial.print(scaled.ZAxis);

  Serial.print("   \tHeading:\t");
  Serial.print(heading);
  Serial.print(" Radians   \t");
  Serial.print(headingDegrees);
  Serial.println(" Degrees   \t");
}


Using 0x1E
Code: Select allStarting the I2C interface.
Constructing new HMC5883L
Setting scale to +/- 1.3 Ga
Setting measurement mode to continous.
Checking connection... Not Connected
Raw:   256   0   0      Scaled:   235.52   60041.96   0.00      Heading:   1.61 Radians      92.09 Degrees      
Raw:   44677   0   65087      Scaled:   235.52   235.52   0.00      Heading:   0.83 Radians      47.31 Degrees      
Raw:   44677   0   65087      Scaled:   235.52   235.52   0.00      Heading:   0.83 Radians      47.31 Degrees      
Raw:   44677   0   65087      Scaled:   235.52   235.52   0.00      Heading:   0.83 Radians      47.31 Degrees      


Using 0xD:
Code: Select allStarting the I2C interface.
Constructing new HMC5883L
Setting scale to +/- 1.3 Ga
Setting measurement mode to continous.
Checking connection... Not Connected
Raw:   0   0   0      Scaled:   0.00   0.00   0.00      Heading:   0.04 Radians      2.31 Degrees      
Raw:   0   0   0      Scaled:   0.00   0.00   0.00      Heading:   0.04 Radians      2.31 Degrees      
Raw:   0   0   0      Scaled:   0.00   0.00   0.00      Heading:   0.04 Radians      2.31 Degrees      


Any ideas?
Last edited by alex_g on Tue Jul 11, 2017 9:49 am, edited 1 time in total.
User avatar
By alex_g
#68154 Hey, some good news at last!

After a long time head banging and a day of terminal depression :P I found out the following:
The chips on the modules below, even though marked 5883 are NOT HMC5833Ls! I kid you not...

Image

They are, instead, something else called a QMC5833L (right), and are not compatible, one of the differences being the I2C address, as I mentioned above, but the code is different too.

I found this on github, which has started me off just fine, and seems to work as expected, I suppose it may need some more development, especially for inclusion in the Lua/NodeMCU codebase.

Anyway, all is good again, I hope I can focus on my project now, instead of troubleshooting all this nonsense. I am sure others will come across this too, and accordingly I have changed the original title!

Happy hacking!
User avatar
By alex_g
#68174 Just to add, after some reading up (mainly on Reddit, sorry don't have the links) it appears that the HMC chip is the original Honeywell, but these are due to be discontinued and have been licensed by some Chinese outfit, that produces them as QMCs! I may have some minor details wrong, but this is how I have understood it, so far.

Basically the chips work in exactly the same way, as you'd expect, but the I2C address and some registers are different - though not in a major way. From what I've seen I think it would be easy to have a common codebase for both, with some judiciously chosen #defines, and maybe a probe to identify the chip (or just select manually).

Anyway, this change may be somewhat new, even though all the modules I got from fleaby (different suppliers) are all QMC, the relevant Internet articles only seem to appear around May 2017 or so. However, if the Honeywell version is really about to be phased out, then the QMC will definitely be the prevalent module in the future, I'd guess (unless more join the party).

Worth bearing in mind.

(I have also posted some pics and links on the Lua specific section)
User avatar
By SailSense
#70618 A compass is a key part of my project and I have been through the same pain of trying the boards and finding that none of them work with the HMC5883L library. Thank you so much for sharing this experience. A have found a glimmer of hope.
Thank you
David