2024-04-11 02:59 AM
Hi,
I'm attempting to use an LSM303agr magnetometer and calibrate it using the MotionMC library.
My issue is that the MotionMC MMC_Output_t struct always remains at its default value.
I've tried different hardware setups:
I followed the application note UM2192
Here are the steps I've taken:
1-Enabled CRC in Cube MX.
2-Configured MotionMC in the software Pack and enabled it in the Middleware panel of Cube MX.
3-Configured the I2C to communicate with the LSM303agr.
4-At the beginning of the main code, I set up the magnetometer like this:
/*
@brief configure the contol register of the magnetometer
@param lsm303agr : pointer to the struct associate to the device to read
@retval status of the execution
*/
lsm303agr_status_t lsm303agr_setup_magnetometer(lsm303agr_t *lsm303agr)
{
uint8_t cfg_reg_a_m=0;
uint8_t cfg_reg_b_m=0;
uint8_t cfg_reg_c_m=0;
lsm303agr_read_register(lsm303agr,LSM303AGR_CFG_REG_A_M,&cfg_reg_a_m);
printf("CFG_REG_A_M 0x%x\n",cfg_reg_a_m);
lsm303agr_read_register(lsm303agr,LSM303AGR_CFG_REG_B_M,&cfg_reg_b_m);
printf("CFG_REG_B_M 0x%x\n",cfg_reg_b_m);
lsm303agr_read_register(lsm303agr,LSM303AGR_CFG_REG_C_M,&cfg_reg_c_m);
printf("CFG_REG_C_M 0x%x\n",cfg_reg_c_m);
//0b100001100 = 0x8C
//COMP_TEMP_EN = 1 -> mag temp compensation enabled
//REBOOT = 0 -> reboot memory content disabled
//SOFT_RST = 0 -> soft reset disabled
//LP = 0 -> low power mode disabled
//ODR[1:0] = 0x11 -> 100Hz
//MD[1:0] = 0x00 -> continous mode
lsm303agr_write_register(lsm303agr,LSM303AGR_CFG_REG_A_M,0x8C);
//0b00000010 = 0x02
//OFF_CAN_ONE_SHOT = 0 -> offset cancelation in single mode disabled
//INT_on_Data_OFF = 0 -> interutp block recognition do not checks data after HI correction to discover the interupt
//set_FREQ = 0 -> frequency of the pulse is set to every 63 ODR
//OFF_CANC = 1 -> offset cancelation enabled
//LPF = 0 -> low pass filter disabled
lsm303agr_write_register(lsm303agr,LSM303AGR_CFG_REG_B_M,0x02);
//0b00010000 = 0x10
//INT_MAG_PIN = 0 -> interupt signal is not driven on INT_MAG_PIN
//I2C_DIS = 0 -> I2C is enabled
//BDU = 1 -> protection over wrong data enabled
//BLE = 0 -> LSB and MSB not inverted
//SELF_TEST = 0 -> self test disabled
//INT_MAG = 0 -> DRDY pin is not configure as GPIO Output
lsm303agr_write_register(lsm303agr,LSM303AGR_CFG_REG_C_M,0x10);
//set delay to let time to power up
HAL_Delay(LSM303AGR_DELAY_MAGNETOMETER_POWER_UP);
return LSM303AGR_OK;
}
5 - I initialized the MotionMC library and read the MotionMC library version (I obtained "ST MotionMC v2.6.1").
#define LSM303AGR_MAGNETOMETER_CALIBRATION_SAMPLE_TIME 200
.
.
.
MotionMC_Initialize(LSM303AGR_MAGNETOMETER_CALIBRATION_SAMPLE_TIME, 1);
char motion_mc_version[35] = {0};
MotionMC_GetLibVersion(motion_mc_version);
printf("motion mc version : %s \n",motion_mc_version);
6 - I configured a timer to call my calibration function every 200ms.
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if (htim->Instance == TIM6) { //1ms
counter_200ms++;
if (counter_200ms > 200){
token_200ms = true;
counter_200ms = 0;
}
}
}
if (token_200ms){
lsm303agr_magnetometer_run_calib(&lsm303agr);
token_200ms = false;
}
MMC_CalQuality_t lsm303agr_magnetometer_run_calib(lsm303agr_t *lsm303agr)
{
//increment time count
lsm303agr->calib_time_count++;
MMC_Input_t data_in;
MMC_Output_t data_out;
// Get magnetic field X/Y/Z
lsm303agr_read_mag_output_register(lsm303agr);
data_in.Mag[0] = lsm303agr_mag_val_to_uT(lsm303agr->mag.x);
data_in.Mag[1] = lsm303agr_mag_val_to_uT(lsm303agr->mag.y);
data_in.Mag[2] = lsm303agr_mag_val_to_uT(lsm303agr->mag.z);
// Get current sample time in [ms]
data_in.TimeStamp = lsm303agr->calib_time_count * LSM303AGR_MAGNETOMETER_CALIBRATION_SAMPLE_TIME;
// Magnetometer calibration algorithm update
MotionMC_Update(&data_in);
// Get the magnetometer calibration coefficients
MotionMC_GetCalParams(&data_out);
printf("HI x %f\n",data_out.HI_Bias[0]);
printf("HI y %f\n",data_out.HI_Bias[1]);
printf("HI z %f\n",data_out.HI_Bias[2]);
printf("SF x %f %f %f \n",data_out.SF_Matrix[0][0],data_out.SF_Matrix[0][1],data_out.SF_Matrix[0][2]);
printf("SF x %f %f %f \n",data_out.SF_Matrix[1][0],data_out.SF_Matrix[1][1],data_out.SF_Matrix[1][2]);
printf("SF x %f %f %f \n",data_out.SF_Matrix[2][0],data_out.SF_Matrix[2][1],data_out.SF_Matrix[2][2]);
/*
// Apply calibration coefficients
mag_cal_x = (int)((data_in.Mag[0] - data_out.HI_Bias[0]) * data_out.SF_Matrix[0][0]
+ (data_in.Mag[1] - data_out.HI_Bias[1]) * data_out.SF_Matrix[0][1]
+ (data_in.Mag[2] - data_out.HI_Bias[2]) * data_out.SF_Matrix[0][2]);
mag_cal_y = (int)((data_in.Mag[0] - data_out.HI_Bias[0]) * data_out.SF_Matrix[1][0]
+ (data_in.Mag[1] - data_out.HI_Bias[1]) * data_out.SF_Matrix[1][1]
+ (data_in.Mag[2] - data_out.HI_Bias[2]) * data_out.SF_Matrix[1][2]);
mag_cal_z = (int)((data_in.Mag[0] - data_out.HI_Bias[0]) * data_out.SF_Matrix[2][0]
+ (data_in.Mag[1] - data_out.HI_Bias[1]) * data_out.SF_Matrix[2][1]
+ (data_in.Mag[2] - data_out.HI_Bias[2]) * data_out.SF_Matrix[2][2]);
*/
return data_out.CalQuality;
}
I read the magnetometer register as follows:
lsm303agr_status_t lsm303agr_read_mag_output_register(lsm303agr_t *lsm303agr)
{
//create a timeout and init it
timeout_t update_value_timeout;
//variable to store the different register value
uint8_t out_x_lsb =0;
uint8_t out_x_msb =0;
uint8_t out_y_lsb =0;
uint8_t out_y_msb =0;
uint8_t out_z_lsb =0;
uint8_t out_z_msb =0;
// variable to store the status register value
uint8_t status_reg_m = 0;
bool zyxda = 0;
//wait for new data read or for timeout
timeout_start(&update_value_timeout);
do{
lsm303agr_read_register(lsm303agr,LSM303AGR_STATUS_REG_M,&status_reg_m);
zyxda = status_reg_m && 0b00001000;
}
while ((zyxda == false) && (timeout_check(&update_value_timeout, LSM303AGR_UPDATE_MAGNETOMETER_VALUE_TIMEOUT) == false));
if (zyxda == true)
{
lsm303agr_read_register(lsm303agr,LSM303AGR_OUTX_L_REG_M,&out_x_lsb);
lsm303agr_read_register(lsm303agr,LSM303AGR_OUTX_H_REG_M,&out_x_msb);
lsm303agr_read_register(lsm303agr,LSM303AGR_OUTY_L_REG_M,&out_y_lsb);
lsm303agr_read_register(lsm303agr,LSM303AGR_OUTY_H_REG_M,&out_y_msb);
lsm303agr_read_register(lsm303agr,LSM303AGR_OUTZ_L_REG_M,&out_z_lsb);
lsm303agr_read_register(lsm303agr,LSM303AGR_OUTZ_H_REG_M,&out_z_msb);
lsm303agr->mag.x = (out_x_msb<<8) + out_x_lsb;
lsm303agr->mag.y = (out_y_msb<<8) + out_y_lsb;
lsm303agr->mag.z = (out_z_msb<<8) + out_z_lsb;
lsm303agr->mag.d = lsm303agr_mag_val_to_degres(lsm303agr->mag,lsm303agr->accel.horizon_parallel_plan);
return LSM303AGR_OK;
}
else
{
return LSM303AGR_ERROR_UPDATE_MAGNETOMETER_VALUE;
}
}
And convert the value in microtesla (uT):
/*
@brief Convert magnetometer data value to [uT]
@param mag_val : magnetometer data value
@retval magnetic field in [uT]
*/
float lsm303agr_mag_val_to_uT(int16_t mag_val)
{
float mgauss = lsm303agr_mag_val_to_mgauss(mag_val);
float uT = lsm303agr_mgauss_to_uT(mgauss);
return uT;
}
/*
@brief Convert magnetometer data value to [mGauss]
@param mag_val : magnetometer data value
@retval magnetometer data value [mGauss]
*/
float lsm303agr_mag_val_to_mgauss(int16_t mag_val)
{
//according to datasheet 1LSB = 1.5 mGauss
float mgauss = mag_val*1.5f;
return mgauss;
}
/*
@brief Convert [gauss] to [uT]
@param gauss : magnetic field value in [gauss]
@retval magnetic field value in [uT]
*/
float lsm303agr_mgauss_to_uT(float mgauss)
{
//1 Gauss = 0.0001 T <=> 1 mGauss = 0.1uT
float uT = mgauss/10.0f;
return uT;
}
However, I consistently receive the following output:
HI x 0.000000
HI y 0.000000
HI z 0.000000
SF x 1.000000 0.000000 0.000000
SF x 0.000000 1.000000 0.000000
SF x 0.000000 0.000000 1.000000
return MMC_CALQSTATUSUNKNOWN
I've checked the communication with the sensor, and it seems fine since I can read and write to its registers. I've also verified the timer period, which appears to be correct.
I've explored the following topics
and attempted several solutions, including:
- upgrade the head size to 0x1000 and the stack size to 0x2000
- wait for more than 20s, moving the sensor.
However, none of these solutions have worked. Could someone please assist me with this?
Thank you
2024-05-21 10:57 PM
Hi everyone!!!!
I am also facing the same issue and i am using STM32F401CBU6 controller with ISM303DAC Mems Sensor, can able to read raw data of both Accelerometer and Magnetometer but after parsing magnetometer data for calibration and calling MotionMC_GetCalParams(data_out); function
I consistently receive the following output:
HI x 0.000000
HI y 0.000000
HI z 0.000000
SF x 1.000000 0.000000 0.000000
SF x 0.000000 1.000000 0.000000
SF x 0.000000 0.000000 1.000000
return MMC_CALQSTATUSUNKNOWN
Got stuck at this point.
ANIL.
2024-05-23 06:03 AM
Hello @Pierre Castera,
Could you please send me the datalog containing all your input data including timestamp that you feed to library?
Attached is the example of the datalog format I'd be able to use for offline analysis.
Thanks and regards,
Petr