2025-05-23 7:07 AM
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");
}
}