Skip to main content
Graduate
May 23, 2025
Question

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

  • May 23, 2025
  • 0 replies
  • 559 views

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");
 }
}
    This topic has been closed for replies.