cancel
Showing results for 
Search instead for 
Did you mean: 

How to properly recalibrate the lis2mdl sensor with hard-iron?

ngrigoriadis
Senior

Hello everyone,
I am using the LIS2MDL sensor in a parking project, where it operates via interrupt using a threshold value of 60. Initially, the sensor is calibrated with hard-iron correction and is able to detect interrupts properly. However, when a car approaches the sensor, the magnetic field, in all axis, changes significantly, causing the interrupt threshold to be exceeded.

I want to recalibrate the sensor using hard-iron correction so that the X, Y, and Z axis readings return as close as possible to zero. This would allow the sensor to detect another interrupt after the car moves away. The problem is that the hard-iron correction function does not seem to work properly on its own. I’ve only been able to make it work by reinitializing the sensor and then applying the hard-iron calibration. I know this isn't the proper method, but I haven't found a better solution.

Do you have any suggestions on how to handle this more effectively?

I forgot to mention that I also tried disabling the interrupt, applying the hard-iron correction, and then re-enabling it—but that didn’t work either.

 

This is my init function:

int LIS2MDL_init(lis2mdlType magnet)
{
	/*Local variables*/
    lis2mdl_int_crtl_reg_t int_ctrl;

    /*Initialize driver interface*/
    dev_ctx.write_reg = platform_write;
    dev_ctx.read_reg = platform_read;
    dev_ctx.mdelay = platform_delay;
    dev_ctx.handle = &SENSOR_BUS;

    /*Wait for sensor boot*/
    platform_delay(20);

    /*Check device ID*/
    magnet.whoamI = LIS2MDL_get_id();
    if (magnet.whoamI != LIS2MDL_ID)
    {
        LOG_ERR("Device is not accessible");
        return -1;
    }

    /*Reset and reinitialize sensor*/
    lis2mdl_reset_set(&dev_ctx, PROPERTY_ENABLE);
    uint8_t rst;
    do {
        lis2mdl_reset_get(&dev_ctx, &rst);
    } while (rst);

    /*Enable block data update*/
    lis2mdl_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);

    /*Set output data rate to 10 Hz*/
    lis2mdl_data_rate_set(&dev_ctx, LIS2MDL_ODR_10Hz);

    /* Set / Reset sensor mode */
    lis2mdl_set_rst_mode_set(&dev_ctx, LIS2MDL_SET_SENS_ONLY_AT_POWER_ON);

    /*Enable temperature compensation*/
    lis2mdl_offset_temp_comp_set(&dev_ctx, PROPERTY_ENABLE);

    /*Set continuous mode for measurement*/
    lis2mdl_operating_mode_set(&dev_ctx, LIS2MDL_CONTINUOUS_MODE);

    /*Set low-power mode*/
    lis2mdl_power_mode_set(&dev_ctx, LIS2MDL_LOW_POWER);

    /*Enable interrupt on INT pin*/
    lis2mdl_int_on_pin_set(&dev_ctx, PROPERTY_ENABLE);

    /*comparison is made between magnetic data after hard-iron correction and the programmable threshold*/
    lis2mdl_offset_int_conf_set(&dev_ctx, LIS2MDL_CHECK_AFTER);

    /*Enable offset cancellation*/
    //LIS2MDL_enable_offset_cancellation(&dev_ctx, true);

    /*Set interrupt threshold*/
    lis2mdl_int_gen_threshold_set(&dev_ctx, NORMAL_THRESHOLD);

    /*Configure interrupt control*/
    int_ctrl.iea = PROPERTY_ENABLE;    // Interrupt signal active HIGH
    int_ctrl.ien = PROPERTY_ENABLE;    // Enable interrupt system
    int_ctrl.iel = PROPERTY_DISABLE;   // Pulse interrupt signal

    /*Enable X-axis interrupt only*/
    int_ctrl.zien = PROPERTY_DISABLE;  // Disable Z-axis interrupt
    int_ctrl.yien = PROPERTY_DISABLE;  // Disable Y-axis interrupt
    int_ctrl.xien = PROPERTY_ENABLE;   // Enable X-axis interrupt

    /*Apply interrupt configuration*/
    lis2mdl_int_gen_conf_set(&dev_ctx, &int_ctrl);

    LOG_INF("LIS2MDL configured for continuous low-power mode with X-axis interrupt enabled");

    return 0;
}

and this is the hard-iron correction function:

void LIS2MDL_hard_iron(int samples)
{
	/*Local variables*/
	int32_t ret;
	int32_t mag_bias[3] = {0, 0, 0};               // This is the center of the magnetic field offset caused by hard-iron distortion.
	int16_t mag_temp[3] = {0, 0, 0};               // Stores magnetic raw data values.
	int16_t mag_max[3] = {-32767, -32767, -32767}; // Stores maximum magnetometer readings for each axis during data collection.
	int16_t mag_min[3] = {32767, 32767, 32767};    // Stores minimum magnetometer readings for each axis during data collection.
	int16_t mag_offset[3]= {0, 0, 0};              // Offsets to write to registers

	LOG_INF("HARD-IRON CALLIBRATION ");


	/*Take samples from the axis to calibrate magnetometer*/
	for (int i=0 ; i<samples; i++)
	{
		/*Take raw measurements from magnetic sensor*/
		lis2mdl_magnetic_raw_get(&dev_ctx, mag_temp);

		/*Loop through the 3 axis, and update min and max readings*/
		for (int j=0; j<3; j++)
		{
			if (mag_temp[j] > mag_max[j])
			{
				mag_max[j] = mag_temp[j];
			}

			if (mag_temp[j] < mag_min[j])
			{
				mag_min[j] = mag_temp[j];
			}
		}

		/*Delay between measurements*/
		platform_delay(12);
	}

	/*Get hard-iron correction*/
	mag_bias[0] = (mag_max[0] + mag_min[0]) / 2; // Get average x mag bias
	mag_bias[1] = (mag_max[1] + mag_min[1]) / 2; // Get average y mag bias
	mag_bias[2] = (mag_max[2] + mag_min[2]) / 2; // Get average z mag bias


	/* Convert hard-iron bias into 16-bit values */
	mag_offset[0] = (int16_t)mag_bias[0];
	mag_offset[1] = (int16_t)mag_bias[1];
	mag_offset[2] = (int16_t)mag_bias[2];

    printf("[INFO] Magnetometer bias calculated: X = %d, Y = %d, Z = %d\n",
            mag_offset[0], mag_offset[1], mag_offset[2]);

    /*Write biases to LIS2MDL hard-iron offset registers*/
    ret = lis2mdl_mag_user_offset_set(&dev_ctx, mag_offset);
    if (ret != 0)
    {
    	LOG_ERR("Failed to write hard-iron offsets to LIS2MDL registers");
    } else
    {
    	LOG_INF("Hard-iron offsets written to LIS2MDL registers successfully");
    }
}
0 REPLIES 0