1

I needed a magnetometer with a high Output Data Rate (ODR). This is because I wanted to measure AC magnetic fields of around 20-80 Hz. So I decided to go with the MMC3416xPJ prototyping board which has an ODR of 800 Hz (https://au.mouser.com/new/memsic/memsic-mmc3416xpj-sensors/). I have never written an I2C interface for a sensor myself so I probably messed up. The datasheet for my sensor can be found here. I can get the product ID from the sensor correctly so that means the wiring is correct and some of the code is correct. But when I print out the measurements, they give me overflow values instead of the Earth's magnetic field. BTW I am developing this on Arduino board. Any help would be appreciated. My code can be seen below -

Magnetometer.h

#ifndef MAGNETOMETER_H
#define MAGNETOMETER_H

#include "General.h"
#include <Wire.h>

#define MAGNETOMETER_I2C_ADDRESS 0x30
#define X_OUT_LOW 0x00
#define X_OUT_HIGH 0x01
#define Y_OUT_LOW 0x02
#define Y_OUT_HIGH 0x03
#define Z_OUT_LOW 0x04
#define Z_OUT_HIGH 0x05
#define STATUS 0x06
#define INTERNAL_CONTROL_0 0x07
#define INTERNAL_CONTROL_1 0x08
#define RO 0x1b
#define R1 0x1c
#define R2 0x1d
#define R3 0x1e
#define R4 0x1f
#define PRODUCT_ID 0x20

class Magnetometer
{
  public:
    Magnetometer();
    void Setup();
    void Test();
  private:
    void TestConnnection();
    void ReadRawData();
};


#endif

Magnetometer.cpp

#include "Magnetometer.h"

Magnetometer::Magnetometer()
{

}

void Magnetometer::Setup()
{
    Wire.begin(SDA, SCL);
    TestConnnection();

    Wire.beginTransmission(MAGNETOMETER_I2C_ADDRESS);
    Wire.write(INTERNAL_CONTROL_1);
    Wire.write(0x00);
    Wire.endTransmission();

    Serial.println("Magnetometer Setup");
}

void Magnetometer::Test()
{
    ReadRawData();
    Serial.println("Magnetometer Test");
    delay(1000);
}

void Magnetometer::ReadRawData()
{
    int16_t RawMx, RawMy, RawMz;
    byte status = -1;

    // 1-3
    Wire.beginTransmission(MAGNETOMETER_I2C_ADDRESS);
    Wire.write(INTERNAL_CONTROL_0);
    Wire.write(0x01);
    Wire.endTransmission();

    // 4-7
    Wire.beginTransmission(MAGNETOMETER_I2C_ADDRESS);
    Wire.write(STATUS);
    Wire.requestFrom(MAGNETOMETER_I2C_ADDRESS, 1);
    status = Wire.read();
    Serial.print("status = "); Serial.println(status);
    while ((status%2) != 1)
    {
        status = Wire.read();
        Serial.println("Data not ready");
    }
    Serial.println("Data ready");
    Wire.endTransmission();

    // 8-17
    Wire.beginTransmission(MAGNETOMETER_I2C_ADDRESS);
    Wire.write(X_OUT_LOW);
    Wire.endTransmission();
    Wire.requestFrom(MAGNETOMETER_I2C_ADDRESS, 6);
    RawMx = Wire.read();
    RawMx |= Wire.read()<<8;
    RawMy = Wire.read();
    RawMy |= Wire.read()<<8;
    RawMz = Wire.read();
    RawMz |= Wire.read()<<8;

    Serial.print("RawMx: "); Serial.print(RawMx);
    Serial.print(" RawMy: "); Serial.print(RawMy);
    Serial.print(" RawMz: "); Serial.println(RawMz);

    float scaleFactor = 2048;
    float convertToMircoTelsa = 100;
    float Mx, My, Mz;

    Mx = (float) RawMx / scaleFactor * convertToMircoTelsa;
    My = (float) RawMy / scaleFactor * convertToMircoTelsa;
    Mz = (float) RawMz / scaleFactor * convertToMircoTelsa;

    Serial.print("Mx: "); Serial.print(Mx);
    Serial.print(" My: "); Serial.print(My);
    Serial.print(" Mz: "); Serial.println(Mz);

    // Serial.print("Wire.ava = "); Serial.println(Wire.available());
}

void Magnetometer::TestConnnection()
{
    byte id = -1;
    while (id != 6)
    {
        Wire.beginTransmission(MAGNETOMETER_I2C_ADDRESS);
        Wire.write(PRODUCT_ID);
        Wire.requestFrom(MAGNETOMETER_I2C_ADDRESS, 1);
        id = Wire.read();
        Wire.endTransmission();

        if (id != -1)
        {
            Serial.println("Cannot connect to Magnetometer");
        }
    }
    Serial.println("Magnetometer TestConnnection Success");
}

If you guys suggest me any other magnetometers that have a high ODR (at least above 300 Hz), it would be really appreciated.

  • Add print-out when you run the sketch. What are the raw values? – Mikael Patel Jun 7 '19 at 7:15
  • That is not fast, that is slow, because the I2C bus is slow and the Wire.endTransmission and Wire.requestFrom are blocking functions, they wait until everything has finished. You might use Wire.setClock to set the bus to 400kHz, but a magnetometer with SPI interface avoids all these problems. Which arduino board do you use ? I see a few mistakes with the Wire functions, you have to read in the Arduino Wire reference how to use them. – Jot Jun 7 '19 at 11:08
  • @MikaelPatel I get overflow values – Nadim Ahmed Jun 7 '19 at 17:37
  • @Jot I am using a Wemos D1 mini which based on the Esp8266. Can you give me pointers on the mistakes I made? Thanks in advance. – Nadim Ahmed Jun 7 '19 at 17:37
  • @Jot Do you know where I can find a magnetometer which has an odr of above 300 Hz and uses SPI for data transfer? – Nadim Ahmed Jun 7 '19 at 17:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.