LSM303AGR Magnetometer Self-Test Fails – Help Diagnosing with STM32
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.
Goal
Perform a successful magnetometer self-test and confirm the output is within the required limits (according to the datasheet).
Summary of the Issue
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);
}
Questions for the Community
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?
Datasheet Link (Magnetometer Section):
LSM303AGR Datasheet (STMicroelectronics)
System Details
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
