From 12b025367c1078ca8b75e54a57e72e45fc70b74e Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 23 Apr 2026 22:38:05 +0200 Subject: [PATCH] Fix AK09918 init: correct WIA2 expected value and broken retry loop AK09918 WIA2 device ID is 0x0C (not 0x09 which belongs to AK09916). Previous check falsely reported init failure for a working sensor. The retry loop was resetting the sensor on every attempt, which clears CNTL2 back to power-down before the sensor can produce a measurement. At 100 Hz the first sample takes ~10 ms; checking isDataReady immediately after switchMode always returned NOT_RDY, triggering another reset. New approach: switch to continuous mode once, then poll with 15 ms delay (one sample period + margin) up to 20 times without resetting. Only re-apply the mode if an actual I2C read failure occurs. Co-Authored-By: Claude Sonnet 4.6 --- IMU.cpp | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/IMU.cpp b/IMU.cpp index 1017059..c36e032 100644 --- a/IMU.cpp +++ b/IMU.cpp @@ -315,42 +315,41 @@ void imuInit() if (qmi8658_.begin() == 0) Serial.println("qmi8658_init fail"); - // Verify AK09918 is present on I2C before trying to configure it. - // WIA2 register (0x01) must return 0x09 on a real AK09918. + // Verify AK09918 is present on I2C. + // WIA1=0x48 (AKM company ID), WIA2=0x0C (AK09918 device ID). { const uint16_t devId = magnetometer_.getDeviceID(); + const uint8_t wia1 = (uint8_t)(devId >> 8); const uint8_t wia2 = (uint8_t)(devId & 0xFF); - if (wia2 != 0x09) { - Serial.printf("AK09918_init fail: WIA2=0x%02X (expected 0x09). " - "Check I2C wiring on SDA/SCL (GPIO32/33), " - "address 0x0C, and power supply.\n", wia2); + if (wia1 != 0x48 || wia2 != 0x0C) { + Serial.printf("AK09918 warning: WIA1=0x%02X WIA2=0x%02X (expected 0x48/0x0C). " + "Check I2C on SDA=GPIO32 SCL=GPIO33, address 0x0C.\n", wia1, wia2); } else { - Serial.println("AK09918 found on I2C."); + Serial.println("AK09918 found (WIA OK)."); } } - // Initialize to power-down first so the subsequent switchMode goes through - // a defined state (unlike AK09918_NORMAL which skips I2C entirely). + // Put sensor in a known state before switching to continuous mode. magnetometer_.initialize(AK09918_POWER_DOWN); - delay(1); + delay(10); // datasheet: >=100µs after power-down; 10ms is safe magnetometer_.switchMode(AK09918_CONTINUOUS_100HZ); - err = magnetometer_.isDataReady(); - int retry_times = 0; - while (err != AK09918_ERR_OK) { - Serial.printf("AK09918 not ready (err=%d), retry %d/10...\n", err, retry_times + 1); - delay(100); - magnetometer_.reset(); - delay(100); - magnetometer_.switchMode(AK09918_CONTINUOUS_100HZ); + + // At 100 Hz the first sample takes ~10 ms. Poll ST1 with a delay + // instead of resetting on every attempt (reset clears the mode setting). + err = AK09918_ERR_NOT_RDY; + for (int retry_times = 0; retry_times < 20 && err != AK09918_ERR_OK; retry_times++) { + delay(15); // wait one sample period (100Hz = 10ms) plus margin err = magnetometer_.isDataReady(); - retry_times ++; - if (retry_times > 10) { - Serial.println("AK09918 init timed out. Magnetometer will be unavailable."); - break; + if (err == AK09918_ERR_READ_FAILED) { + // I2C error – mode may have been lost, try re-applying it once. + Serial.printf("AK09918 I2C read failed on retry %d, re-applying mode...\n", retry_times + 1); + magnetometer_.switchMode(AK09918_CONTINUOUS_100HZ); } } if (err == AK09918_ERR_OK) { Serial.println("AK09918 ready."); + } else { + Serial.printf("AK09918 init timed out (last err=%d). Magnetometer will be unavailable.\n", err); } // Serial.println("Start figure-8 calibration after 1 seconds."); // delay(1000);