2025-05-12 10:29 PM
Hi everyone,
I'm working with the LSM303AGR magnetometer using an STM32 microcontroller and trying to run the built-in self-test as described in the datasheet. However, the self-test consistently fails — the delta values (normal vs self-test mode) fall outside the expected range.
Perform a successful magnetometer self-test and confirm the output is within the required limits (according to the datasheet).
Self-test bit is enabled in CFG_REG_C_M (0x62) → value reads back as 0x12.
Data output seems valid and updates regularly.
Delta between self-test and normal readings is either too small or too large, so the test fails.
Self-Test Code (Full Function)
void LSM303AGR_Mag_selfTest(void)
{
uint8_t addr = LSM303_MAG_ADR, status;
int16_t x_nost = 0, y_nost = 0, z_nost = 0;
int16_t x_st = 0, y_st = 0, z_st = 0;
int i;
// Configure magnetometer: 50 Hz, continuous mode
lsm303AGR_Write8b_res(addr, 0x60, 0x8C); // Temp disable, low power, ODR = 100 Hz, continuous mode
lsm303AGR_Write8b_res(addr, 0x61, 0x02);
lsm303AGR_Write8b_res(addr, 0x62, 0x10); // BDU = 1
HAL_Delay(200); // Wait for stabilization
// Collect baseline data (no self-test)
for (i = 0; i < 50; i++)
{
do {
status = lsm303AGR_Read8b_res(addr, 0x67);
HAL_Delay(5);
} while (!(status & 0x08)); // Wait for new ZYX data
x_nost += lsm303AGR_Read16b_res(addr, 0x68);
y_nost += lsm303AGR_Read16b_res(addr, 0x6A);
z_nost += lsm303AGR_Read16b_res(addr, 0x6C);
HAL_Delay(20);
}
x_nost /= 50;
y_nost /= 50;
z_nost /= 50;
// Enable self-test mode
lsm303AGR_Write8b_res(addr, 0x62, 0x12); // BDU = 1, Self-test = 1
HAL_Delay(500); // Wait for stabilization
uint8_t reg_val = lsm303AGR_Read8b_res(addr, 0x62);
if (reg_val & 0x02) {
printf("Self-test is ENABLED CTRL_REG4_A = 0x%02X\r\n", reg_val);
} else {
printf("Self-test is NOT enabled CTRL_REG4_A = 0x%02X\r\n", reg_val);
}
// Collect self-test data
for (i = 0; i < 50; i++)
{
do {
status = lsm303AGR_Read8b_res(addr, 0x67);
HAL_Delay(5);
} while (!(status & 0x08)); // Wait for new ZYX data
x_st += lsm303AGR_Read16b_res(addr, 0x68);
y_st += lsm303AGR_Read16b_res(addr, 0x6A);
z_st += lsm303AGR_Read16b_res(addr, 0x6C);
HAL_Delay(20);
}
x_st /= 50;
y_st /= 50;
z_st /= 50;
// Calculate deltas
int16_t deltaX = abs(x_st - x_nost);
int16_t deltaY = abs(y_st - y_nost);
int16_t deltaZ = abs(z_st - z_nost);
// Check against datasheet min/max (example range in LSB)
const int16_t ST_MIN = 100;
const int16_t ST_MAX = 1000;
// Check for pass/fail
bool x_pass = (deltaX >= ST_MIN && deltaX <= ST_MAX);
bool y_pass = (deltaY >= ST_MIN && deltaY <= ST_MAX);
bool z_pass = (deltaZ >= ST_MIN && deltaZ <= ST_MAX);
if (x_pass && y_pass && z_pass) {
printf(" LSM303AGR Magnetometer Self-Test PASSED\r\n");
} else {
printf(" LSM303AGR Magnetometer Self-Test FAILED\r\n");
}
// Disable self-test
lsm303AGR_Write8b_res(addr, 0x62, 0x10);
lsm303AGR_Write8b_res(addr, 0x60, 0x83);
}
Are the ST_MIN/ST_MAX values accurate?
The datasheet (Rev 2, Table 15) gives these thresholds but doesn’t specify units clearly. Should these be adjusted for specific gain settings?
Is the delay after enabling self-test (500 ms) sufficient, or is more time needed before sampling?
Do I need to read all six output registers in a burst (multibyte read) to ensure synchronized axis data?
Any known issues with self-test on LSM303AGR in continuous mode?
LSM303AGR Datasheet (STMicroelectronics)
MCU: STM32F4 series (STM32Cube HAL)
Sensor: LSM303AGR via I2C
IDE: STM32CubeIDE
OS: Bare-metal (no RTOS)
Thanks in advance for any insights, corrections, or working reference code.
Best regards,
Raj