cancel
Showing results for 
Search instead for 
Did you mean: 

MotionMC running algo but no output bias data calculated (all to default)

Pierre Castera
Associate II

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:

  • STM32F746VG and a custom board
  • NUCLEO-F401Re with a STEVAL-MK117V1

I followed the application note UM2192

Here are the steps I've taken:

 

https://www.st.com/content/ccc/resource/technical/document/user_manual/group0/dc/4f/b0/4d/e3/41/4f/4b/DM00382798/files/DM00382798.pdf/jcr:content/translations/en.DM00382798.pdf

 

1-Enabled CRC in Cube MX.

PierreCastera_1-1712827003482.png

 

2-Configured MotionMC in the software Pack and enabled it in the Middleware panel of Cube MX.

PierreCastera_0-1712826927220.png

PierreCastera_2-1712827054351.png

 

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

https://community.st.com/t5/mems-and-sensors/the-x-cube-mems1-libraries-in-detail-motionmc-application/ta-p/49755

https://community.st.com/t5/mems-sensors/inertial-sensor-how-to-correctly-use-motion-librarys/m-p/334949#M14171

https://community.st.com/t5/mems-sensors/motionmc-calibration-fails-all-params-have-default-value/m-p/406256

 

and attempted several solutions, including:

- upgrade the head size to 0x1000 and the stack size to 0x2000

PierreCastera_3-1712827219140.png

 

- wait for more than 20s, moving the sensor. 

 

However, none of these solutions have worked. Could someone please assist me with this?

Thank you

0 REPLIES 0