Bosch Sensortec Community

    Showing results for 
    Search instead for 
    Did you mean: 

    BMX160 magnetometer trimming registers values

    BMX160 magnetometer trimming registers values



    I've noticed a weird problem in the compensated magnetometer data. The x ,y axes showed extremely low values(up to 0.03 gauss, and the earth's magnetic field was interpreted as 0.01, as if the scale is wrong), while the z axis seems okay(raw data for x and y axes was between -50 to 50).

    After searching the forum i came across the "bmm150-step-by-step-temperature-compensation-sample.pdf", and checked the sensor trimming data.

    Most of the values seemed okay except dig_xyz1(between 50000 and 60000), dig_xy1(around 250), which were about 10 times bigger than the values shown in the temperature-compensation-manual file.

    After looking at the BMM-Sensor-API, I've noticed that the mathematic operations in compenstaion_x and compensation_y functions with the trim parameters we received resulted in a value larger than the uint16 scale(data_rhall is about 6300).

    >>process_comp_x0 = data_rhall;

    >>process_comp_x1 = ((int32_t)dev->trim_data.dig_xyz1) * 16384;
    >>process_comp_x2 = ((uint16_t)(process_comp_x1 / process_comp_x0)) - ((uint16_t)0x4000);
    >>retval = ((int16_t)process_comp_x2);

    The results are:

    process_comp_x0 = 6300

    process_comp_x1 = 60000*16384 = 983x10^6

    process_comp_x2 = ((uint16_t)(983x10^6/ 6300)) - ((uint16_t)16384) = ((uint16_t)156038) - ((uint16_t)16384)  when 65535 is the maximum value for uint...

    afterwards I noticed in the driver that when it reads the dig_xyz register it excludes the MSB bit:

    >> temp_msb = ((uint16_t)(trim_xy1xy2[5] & 0x7F)) << 8;
    >>dev->trim_data.dig_xyz1 = (uint16_t)(temp_msb | trim_xy1xy2[4]);

    While the temperature compensation document doesn't mention it. Even with the trim corrent the values are still high and when casting the result of  process_comp_x2  to int16 in the following line it filps sign and becomes negative.

    The Issue appeared in 3 sensor out of 10.

    At this point I'm a bit confused and wanted to know if the trimming values we received are normal.

    In case they are not, can I calibration the value myself or should I disregard the temperature compensation?

    Best Regards,


    6 REPLIES 6

    Community Moderator
    Community Moderator


    Thanks for your inquiry.

    BMX160 = BMI160 + BMM150 where BMM150 magnetometer is connected to BMI160's secondary I2C interface inside BMX160 chip. The trimmed values inside BMM150 are fixed and you cannot change those values.

    Please see the attached "BMM150_temperature_compensation.pdf" so that you can check your code to see if those signed and unsigned variables are defined correctly. In addition, you cannot skip temperature compensation. Otherwise, the magnetometer x/y/z axes values in the unit of uT will not be accurate.

    If you get 3 out of 10 BMX160 that output wrong magnetometer compensated values, then it means your code is working fine and those 3 BMX160 chips may be failure parts. Please let us know which country and city you are located. We will contact you to get those parts from you to do failure analysis for the root cause.



    About the trim_dig_xyz1, is it supposed to be only 15bit(Two bytes without the MSB), and if so, are values of 18000 to 28000 are normal for that parameter?

    Best Regards,



    Hi Jason,

    According to the "BMM150_temperature_compensation.pdf" file I just attached here, dig_xyz1 is an unsigned integer from register (0x6D << 😎 | 0x6C. So its valid value is from 0 to 65535. And it is used in all x/y/z compensated data calculations.

    In order to check if the magnetometer inside BMX160 is working or not, you can log magnetometer x/y/z data when you rotate your device around x axis, y axis and z axis full-round respectively and slowly on a wooden or plastic surface. Then you can plot x-y data when you rotate your device around z axis to see if it is a circle or ellipse or not. z axis data should be almost constant. You can also repeat the plot for y-z and x-z to see the shape. In addition, you can also log x/y/z data when you rotate your device randomly in 3D space slowly in all directions. Then you can plot x-y-z data in 3D to see if you can get a ball or an ellipsoid or not.

    If it is yes to the above data collections and plots, then BMX160 magnetometer is working fine. If it is no, then the magnetometer is not working fine. We need to find out the root cause of this failure BMX160 part.



    I agree with you about the dig_xyz1 trim register that its unsigned 16 bit int acording to the document, but on the other hand, the function that extracts the trim registers from the BMM150-Sensor-API is:

    static int8_t read_trim_registers(struct bmm150_dev *dev)
    int8_t rslt;
    uint8_t trim_x1y1[2] = { 0 };
    uint8_t trim_xyz_data[4] = { 0 };
    uint8_t trim_xy1xy2[10] = { 0 };
    uint16_t temp_msb = 0;

    /* Trim register value is read */
    rslt = bmm150_get_regs(BMM150_DIG_X1, trim_x1y1, 2, dev);

    if (rslt == BMM150_OK)
    rslt = bmm150_get_regs(BMM150_DIG_Z4_LSB, trim_xyz_data, 4, dev);

    if (rslt == BMM150_OK)
    rslt = bmm150_get_regs(BMM150_DIG_Z2_LSB, trim_xy1xy2, 10, dev);

    if (rslt == BMM150_OK)
    /* Trim data which is read is updated
    * in the device structure
    dev->trim_data.dig_x1 = (int8_t)trim_x1y1[0];
    dev->trim_data.dig_y1 = (int8_t)trim_x1y1[1];
    dev->trim_data.dig_x2 = (int8_t)trim_xyz_data[2];
    dev->trim_data.dig_y2 = (int8_t)trim_xyz_data[3];
    temp_msb = ((uint16_t)trim_xy1xy2[3]) << 8;
    dev->trim_data.dig_z1 = (uint16_t)(temp_msb | trim_xy1xy2[2]);
    temp_msb = ((uint16_t)trim_xy1xy2[1]) << 8;
    dev->trim_data.dig_z2 = (int16_t)(temp_msb | trim_xy1xy2[0]);
    temp_msb = ((uint16_t)trim_xy1xy2[7]) << 8;
    dev->trim_data.dig_z3 = (int16_t)(temp_msb | trim_xy1xy2[6]);
    temp_msb = ((uint16_t)trim_xyz_data[1]) << 8;
    dev->trim_data.dig_z4 = (int16_t)(temp_msb | trim_xyz_data[0]);
    dev->trim_data.dig_xy1 = trim_xy1xy2[9];
    dev->trim_data.dig_xy2 = (int8_t)trim_xy1xy2[8];
    temp_msb = ((uint16_t)(trim_xy1xy2[5] & 0x7F)) << 8;                                        //This line takes only the 7 LSB from that register
    dev->trim_data.dig_xyz1 = (uint16_t)(temp_msb | trim_xy1xy2[4]);

    return rslt;

    The function takes only the 15bit LSB of those two bytes, so what should i do?


    Best Regards,