Skip to content

Commit c6b6154

Browse files
committed
drivers/imu/icm40627: Add TDK InvenSense ICM-40627 IMU driver.
Adds I2C driver for the ICM-40627 6-axis MEMS motion tracking device with 3-axis accelerometer and 3-axis gyroscope. Includes configurable accelerometer range (±2g/4g/8g/16g), temperature sensor support, and basic usage example.
1 parent 34c4ee1 commit c6b6154

File tree

3 files changed

+188
-0
lines changed

3 files changed

+188
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# MIT license; Copyright (c) 2025 Planet Innovation
2+
# ICM-40627 6-axis accelerometer/gyroscope driver for MicroPython.
3+
4+
"""
5+
ICM-40627 6-axis accelerometer/gyroscope driver for MicroPython.
6+
7+
The ICM-40627 is a 6-axis MEMS Motion Tracking device that combines a
8+
3-axis accelerometer and 3-axis gyroscope on a single chip.
9+
"""
10+
11+
# Register addresses (ICM-40627 register map)
12+
_REG_WHO_AM_I = 0x75
13+
_REG_PWR_MGMT_1 = 0x4E
14+
_REG_PWR_MGMT_2 = 0x4F
15+
_REG_ACCEL_CONFIG0 = 0x50
16+
_REG_GYRO_CONFIG0 = 0x4F
17+
_REG_TEMP_CONFIG0 = 0x4D
18+
_REG_ACCEL_X_H = 0x1F
19+
_REG_GYRO_X_H = 0x25
20+
_REG_TEMP_H = 0x1D
21+
22+
# WHO_AM_I expected value
23+
_WHOAMI_VALUE = 0x4E
24+
25+
# Accelerometer scale factors (sensitivity in LSB/g)
26+
# ±2g: 16384 LSB/g, ±4g: 8192 LSB/g, ±8g: 4096 LSB/g, ±16g: 2048 LSB/g
27+
_ACCEL_SCALE_2G = 16384
28+
_ACCEL_SCALE_4G = 8192
29+
_ACCEL_SCALE_8G = 4096
30+
_ACCEL_SCALE_16G = 2048
31+
32+
# Gyroscope scale factors (sensitivity in LSB/°/s)
33+
# ±2000°/s: 16.4 LSB/°/s
34+
_GYRO_SCALE = 16.4
35+
36+
# Temperature scale factor: 1/333.87 °C per LSB, offset 21 °C at 0 LSB
37+
_TEMP_SCALE = 1.0 / 333.87
38+
_TEMP_OFFSET = 21.0
39+
40+
41+
class ICM40627:
42+
"""
43+
Driver for the ICM-40627 6-axis accelerometer/gyroscope.
44+
45+
Example usage:
46+
from machine import I2C
47+
from icm40627 import ICM40627
48+
49+
i2c = I2C(1)
50+
imu = ICM40627(i2c, addr=0x6B)
51+
52+
ax, ay, az = imu.acceleration
53+
gx, gy, gz = imu.gyro
54+
temp = imu.temperature
55+
"""
56+
57+
def __init__(self, i2c, addr=0x6B, accel_range=8):
58+
"""
59+
Initialize the ICM-40627.
60+
61+
Args:
62+
i2c: machine.I2C object for communication
63+
addr: I2C address (default 0x6B)
64+
accel_range: Accelerometer range in g (2, 4, 8, or 16; default 8)
65+
"""
66+
self.i2c = i2c
67+
self.addr = addr
68+
69+
# Validate device presence
70+
self._device_id = self._read_register(_REG_WHO_AM_I)
71+
if self._device_id != _WHOAMI_VALUE:
72+
raise RuntimeError(
73+
f"ICM-40627 not found at address 0x{addr:02X}. "
74+
f"Got ID 0x{self._device_id:02X}, expected 0x{_WHOAMI_VALUE:02X}"
75+
)
76+
77+
# Set accelerometer scale
78+
if accel_range == 2:
79+
self._accel_scale = _ACCEL_SCALE_2G
80+
self._accel_config = 0x00 # ±2g
81+
elif accel_range == 4:
82+
self._accel_scale = _ACCEL_SCALE_4G
83+
self._accel_config = 0x01 # ±4g
84+
elif accel_range == 8:
85+
self._accel_scale = _ACCEL_SCALE_8G
86+
self._accel_config = 0x02 # ±8g
87+
elif accel_range == 16:
88+
self._accel_scale = _ACCEL_SCALE_16G
89+
self._accel_config = 0x03 # ±16g
90+
else:
91+
raise ValueError("accel_range must be 2, 4, 8, or 16")
92+
93+
# Initialize the device
94+
self._initialize()
95+
96+
def _initialize(self):
97+
"""Initialize ICM-40627 with default configuration."""
98+
# Exit sleep mode
99+
self._write_register(_REG_PWR_MGMT_1, 0x00)
100+
101+
# Set accelerometer configuration
102+
self._write_register(_REG_ACCEL_CONFIG0, self._accel_config << 5)
103+
104+
# Set gyroscope configuration to ±2000°/s
105+
self._write_register(_REG_GYRO_CONFIG0, 0x00 << 5)
106+
107+
def _read_register(self, reg):
108+
"""Read a single register value."""
109+
data = self.i2c.readfrom_mem(self.addr, reg, 1)
110+
return data[0]
111+
112+
def _read_registers(self, reg, count):
113+
"""Read multiple consecutive registers."""
114+
return self.i2c.readfrom_mem(self.addr, reg, count)
115+
116+
def _write_register(self, reg, value):
117+
"""Write a single register value."""
118+
self.i2c.writeto_mem(self.addr, reg, bytes([value]))
119+
120+
def _read_int16(self, reg):
121+
"""Read a 16-bit signed integer from two consecutive registers."""
122+
data = self._read_registers(reg, 2)
123+
value = (data[0] << 8) | data[1]
124+
# Convert to signed
125+
if value & 0x8000:
126+
value -= 0x10000
127+
return value
128+
129+
@property
130+
def acceleration(self):
131+
"""
132+
Read accelerometer data.
133+
134+
Returns:
135+
Tuple of (x, y, z) acceleration in g units
136+
"""
137+
x = self._read_int16(_REG_ACCEL_X_H) / self._accel_scale
138+
y = self._read_int16(_REG_ACCEL_X_H + 2) / self._accel_scale
139+
z = self._read_int16(_REG_ACCEL_X_H + 4) / self._accel_scale
140+
return (x, y, z)
141+
142+
@property
143+
def gyro(self):
144+
"""
145+
Read gyroscope data.
146+
147+
Returns:
148+
Tuple of (x, y, z) angular velocity in degrees per second
149+
"""
150+
x = self._read_int16(_REG_GYRO_X_H) / _GYRO_SCALE
151+
y = self._read_int16(_REG_GYRO_X_H + 2) / _GYRO_SCALE
152+
z = self._read_int16(_REG_GYRO_X_H + 4) / _GYRO_SCALE
153+
return (x, y, z)
154+
155+
@property
156+
def temperature(self):
157+
"""
158+
Read temperature sensor data.
159+
160+
Returns:
161+
Temperature in degrees Celsius
162+
"""
163+
raw = self._read_int16(_REG_TEMP_H)
164+
return (raw * _TEMP_SCALE) + _TEMP_OFFSET
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# MIT license; Copyright (c) 2025 Planet Innovation
2+
# ICM-40627 basic example
3+
4+
import time
5+
from icm40627 import ICM40627
6+
from machine import I2C
7+
8+
# Initialize I2C and IMU
9+
i2c = I2C(1)
10+
imu = ICM40627(i2c, addr=0x6B, accel_range=8)
11+
12+
# Read and display sensor data
13+
while True:
14+
print("Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*imu.acceleration))
15+
print("Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*imu.gyro))
16+
print("Temperature: {:>8.2f}°C".format(imu.temperature))
17+
print("")
18+
time.sleep_ms(100)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
metadata(
2+
description="TDK InvenSense ICM-40627 6-axis IMU driver (I2C).",
3+
version="1.0.0",
4+
)
5+
6+
module("icm40627.py", opt=3)

0 commit comments

Comments
 (0)