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.