Skip to content

feat: auto-detect IMU at I2C address 0x68 or 0x69 - #2

Open
Michaelvvt wants to merge 2 commits into
stratux:stratux_masterfrom
Michaelvvt:feat/i2c-address-autodetect
Open

feat: auto-detect IMU at I2C address 0x68 or 0x69#2
Michaelvvt wants to merge 2 commits into
stratux:stratux_masterfrom
Michaelvvt:feat/i2c-address-autodetect

Conversation

@Michaelvvt

Copy link
Copy Markdown

Problem

The ICM-20948 and MPU-9250 drivers hardcode MPU_ADDRESS = 0x68 for every I2C read/write. Both chips have a hardware-strapped I2C address controlled by the AD0 pin:

  • AD0 low → 0x68 (datasheet default)
  • AD0 high → 0x69 (used by many breakout boards: Adafruit, Sparkfun, generic AliExpress GY-91 etc.)

Stratux users with AD0-high boards see the IMU show up at 0x69 on i2cdetect, but the driver only ever talks to 0x68, so the chip is undetectable.

Reproduction (Pi 5, Stratux EU image, AHRS hat with AD0 pulled high):

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
60: -- -- -- -- -- -- -- -- -- 69 -- -- -- -- -- --
70: -- -- -- -- -- -- -- 77

0x69 = ICM-20948, 0x77 = BMP-388. With the unpatched driver, Stratux logs:

Error identifying IMU: remote I/O error
Error identifying IMU: remote I/O error
... (repeats every 4 seconds)

This is the same symptom as stratux/stratux#115.

Fix

Each driver constructor now probes both 0x68 and 0x69 for a valid WHO_AM_I response at startup and remembers the address that answered:

  • Add MPU_ADDRESS_ALT = 0x69 constant alongside the existing MPU_ADDRESS = 0x68.
  • Add address byte field to ICM20948 and MPU9250 structs.
  • In NewICM20948 / NewMPU9250: probe both addresses, store the one that responds with a valid WHO_AM_I value, return a clear error if neither answers.
  • Replace all MPU_ADDRESS uses with mpu.address in I2C read/write helpers.

Backward compatible: public function signatures unchanged. Existing callers get the new behavior for free.

For the ICM-20948, a strict WHO_AM_I == 0xEA check is used. For the MPU-9250, any value in the 0x68-0x75 range is accepted (matches the existing acceptance list in Stratux's initIMU: MPU6000/6050/6500/9150/9250/9255/unknown-gy91-variant).

Verification on hardware (Pi 5 / Bookworm / ICM-20948 at 0x69)

Before:

2026/03/02 21:03:26 Error identifying IMU: remote I/O error
2026/03/02 21:03:30 Error identifying IMU: remote I/O error
2026/03/02 21:03:34 Error identifying IMU: remote I/O error

After:

2026/05/14 21:52:09 ICM20948: detected at I2C address 0x69
2026/05/14 21:52:09 ICM-20948 detected.
2026/05/14 21:52:11 AHRS Info: IMU calibration attempt #1
2026/05/14 21:52:11 AHRS Info: IMU gyro calibration: -0.165368 1.343702 -0.363738
2026/05/14 22:02:05 - Last IMU read: now

IMU samples flowing continuously; AHRS calibrated and producing attitude output.

Companion PR

Stratux's initIMU currently does its own hardcoded-0x68 WHO_AM_I probe before invoking these constructors, which gates them from running for AD0-high chips. A companion PR simplifies initIMU to delegate detection entirely to the driver: stratux/stratux#TBD

Either PR alone helps — together they remove the bug and the duplicated probe logic.

Notes

  • MPU_ADDRESS constant retained at 0x68 for backward compatibility (kept as the documented default).
  • Single new log line per driver on successful detection; no change otherwise.
  • No new dependencies.

The ICM-20948 and MPU-9250 chips have a hardware-strapped I2C address
controlled by the AD0 pin: low = 0x68 (default), high = 0x69. Many
breakout boards (Adafruit, Sparkfun, etc.) ship with AD0 tied high,
making the chip respond at 0x69. The previous code hardcoded 0x68
everywhere, so chips at 0x69 were undetectable.

This change makes each driver probe both addresses at construction time:
- Add MPU_ADDRESS_ALT = 0x69 constant in both drivers
- Add ICMREG_WHO_AM_I / ICMREG_WHO_AM_I_VAL constants to icm20948
- Add `address byte` field to ICM20948 and MPU9250 structs
- In NewICM20948 / NewMPU9250, probe both addresses for a valid
  WHO_AM_I response and store the detected address
- Replace all I2C read/write calls to use mpu.address instead of
  the MPU_ADDRESS constant
- Return a clear error if the chip is found at neither address

The public function signatures are unchanged, so this is fully
backward compatible for existing callers.
Go does not auto-dereference pointer-to-interface like pointer-to-struct.
Calling ReadByteFromReg on the *embd.I2CBus parameter failed to compile;
use the dereferenced copy stored at mpu.i2cbus instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant