ICM-20948 Self-Test

By rotemw , 17 December 2017

Hello,

I'm trying to understand the meaning of the self-test procedure on the ICM-20948.
What does it check actually? In my case, the result of running the self-test action return Low-Noise/Low-Power bias both for the accelerometer and gyroscope sensors.
What does each bias mean? How can I use it to calibrate the accelerometer and gyroscope sensors at system startup?
Attached here the relevant code from eMD 1.0.3 for SmartMotion Developer’s Kit (I use the DK-20948 board).

Thanks in advance!


int icm20948_run_selftest(void)
{
int raw_bias[12];
static int rc = 0; // Keep this value as we're only going to do this once.

if (icm_device.selftest_done == 1) {
INV_MSG(INV_MSG_LEVEL_INFO, "Self-test has already ran. Skipping.");
}
else {
/*
* Perform self-test
* For ICM20948 self-test is performed for both RAW_ACC/RAW_GYR
*/
INV_MSG(INV_MSG_LEVEL_INFO, "Running self-test...");

/* Run the self-test */
rc = inv_icm20948_run_selftest(&icm_device);
/* Check transport errors */
check_rc(rc, "Self-test failure");
if (rc == 0x0) {
/*
* Check for GYR success (1 << 0) and ACC success (1 << 1),
* but don't block as these are 'usage' failures.
*/
INV_MSG(INV_MSG_LEVEL_ERROR, "Self-test failure");
/* 0 would be considered OK, we want KO */
return INV_ERROR;
} else
/* On success, offset will be kept until reset */
icm_device.selftest_done = 1;

/* It's advised to re-init the icm20948 device after self-test for normal use */
icm20948_sensor_setup();
}

/*
* Get Low Noise / Low Power bias computed by self-tests scaled by 2^16
*/
INV_MSG(INV_MSG_LEVEL_INFO, "Getting LP/LN bias");
INV_MSG(INV_MSG_LEVEL_INFO, "GYR LN bias (FS=250dps) (dps): x=%f, y=%f, z=%f",
(float)(raw_bias[0] / (float)(1 << 16)), (float)(raw_bias[1] / (float)(1 << 16)), (float)(raw_bias[2] / (float)(1 << 16)));
INV_MSG(INV_MSG_LEVEL_INFO, "GYR LP bias (FS=250dps) (dps): x=%f, y=%f, z=%f",
(float)(raw_bias[3] / (float)(1 << 16)), (float)(raw_bias[4] / (float)(1 << 16)), (float)(raw_bias[5] / (float)(1 << 16)));
INV_MSG(INV_MSG_LEVEL_INFO, "ACC LN bias (FS=2g) (g): x=%f, y=%f, z=%f",
(float)(raw_bias[0 + 6] / (float)(1 << 16)), (float)(raw_bias[1 + 6] / (float)(1 << 16)), (float)(raw_bias[2 + 6] / (float)(1 << 16)));
INV_MSG(INV_MSG_LEVEL_INFO, "ACC LP bias (FS=2g) (g): x=%f, y=%f, z=%f",
(float)(raw_bias[3 + 6] / (float)(1 << 16)), (float)(raw_bias[4 + 6] / (float)(1 << 16)), (float)(raw_bias[5 + 6] / (float)(1 << 16)));

return rc;
}


int inv_icm20948_set_bias(struct inv_icm20948 * s, enum inv_icm20948_sensor sensor, const void * bias)
{
int bias_q16[3];
int bias_in[3];
int rc = 0;
short shift;
switch(sensor) {
case INV_ICM20948_SENSOR_ACCELEROMETER :
memcpy(bias_q16, bias, sizeof(bias_q16));
//convert from q16 to q25
bias_in[0] = bias_q16[0] << (25 - 16);
bias_in[1] = bias_q16[1] << (25 - 16);
bias_in[2] = bias_q16[2] << (25 - 16);
rc |= inv_icm20948_ctrl_set_acc_bias(s, bias_in);
break;
case INV_ICM20948_SENSOR_GYROSCOPE_UNCALIBRATED:
case INV_ICM20948_SENSOR_GYROSCOPE:
memcpy(bias_q16, bias, sizeof(bias_q16));
//convert from q16 to :
//Q19 => 2000dps
//Q20 => 1000dps
//Q21 => 500dps
//Q22 => 250dps
shift = ((20 + (MPU_FS_1000dps - inv_icm20948_get_gyro_fullscale(s))) - 16);
bias_in[0] = bias_q16[0] << shift;
bias_in[1] = bias_q16[1] << shift;
bias_in[2] = bias_q16[2] << shift;

rc |= inv_icm20948_ctrl_set_gyr_bias(s, bias_in);
break;
case INV_ICM20948_SENSOR_MAGNETIC_FIELD_UNCALIBRATED:
case INV_ICM20948_SENSOR_GEOMAGNETIC_FIELD:
memcpy(bias_q16, bias, sizeof(bias_q16));
// bias is already in q16
rc |= inv_icm20948_ctrl_set_mag_bias(s, bias_q16);
break;
default :
rc = -1;
break;
}
return (rc == 0) ? 1 : rc;
}
phpbb Topic ID
36665