HMC5983 issue (at NEO-M8N GPS + HMC5983 XXL module)

Hello everybody,

recently bought NEO-M8N GPS + HMC5983 Magnetometer module (XXL). Attached to Raspberry PI via UART (GPS) and I2C (Magnetometer). GPS works just fine, but magnetometer seems to deliver incorrect data.

According to HMC5983 datasheet, each axis has same sensivity and symmetric output in range of 0xF800–0x07FF (-2048–2047). In my case, each axis has different sensivity and assymetric range, e.g. different negative and positive values range…

I have tested different I2C clock frequences, with same result. Power supply is also stable.

I’ve spent days (and nights) trying to find the reason by myself, using different measurement modes, data rates, gains etc. With no effort. Still the same problem. Here is sample C code that demonstrates the problem:

[code]#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <linux/i2c-dev.h>

int main() {
int fp;
uint8_t x_msb, x_lsb, y_msb, y_lsb, z_msb, z_lsb;
int16_t x, y, z, x_min, x_max, y_min, y_max, z_min, z_max;

fp = open("/dev/i2c-1", O_RDWR);
ioctl(fp, I2C_SLAVE, 0x1E);

/* CRA (00) - 8-average, 15 Hz default, normal measurement */
i2c_smbus_write_byte_data(fp, 0x00, 0x70);

/* CRB (01) - Gain 1 (1.3 Ga) */
i2c_smbus_write_byte_data(fp, 0x01, 0x20);

/* Mode (02) - Continuous-measurement mode */
i2c_smbus_write_byte_data(fp, 0x02, 0x00);


x_min = y_min = z_min = 1;
x_max = y_max = z_max = -1;

for (;:wink: {
i2c_smbus_read_i2c_block_data(fp, 0x03, 1, &x_msb); /* X MSB /
i2c_smbus_read_i2c_block_data(fp, 0x04, 1, &x_lsb); /
i2c_smbus_read_i2c_block_data(fp, 0x05, 1, &z_msb); /
i2c_smbus_read_i2c_block_data(fp, 0x06, 1, &z_lsb); /
i2c_smbus_read_i2c_block_data(fp, 0x07, 1, &y_msb); /
i2c_smbus_read_i2c_block_data(fp, 0x08, 1, &y_lsb); /
Y LSB */

x = (int16_t) ((x_msb << 8) | x_lsb);
y = (int16_t) ((y_msb << 8) | y_lsb);
z = (int16_t) ((z_msb << 8) | z_lsb);

if (x_min > x) x_min = x; if (x_max < x) x_max = x;
if (y_min > y) y_min = y; if (y_max < y) y_max = y;
if (z_min > z) z_min = z; if (z_max < z) z_max = z;

printf("%c[1A", 27);
  "X: %i (range %i  %i)   Y: %i (range %i  %i)   Z: %i (range %i  %i)         \n",
  x, x_min, x_max,
  y, y_min, y_max,
  z, z_min, z_max

usleep(67000); /* 67 ms for 15 Hz */


return 0;

Whith the code running, I slowly rotated the module 360 degrees across all three axis, in order to get full possible range on each axis. Here is an output:

As you see, for example, “X” axis has assymetric range with a difference between positive and negative maximums of 30%. And all axis have different sensivity.

Ideas anyone?

I think it’s why you have to do a calibration about the magneto.
it’s what we do on all flight controllers before flying.

Thank you for reply,

I will add a calibration routine to the controller program.