IMU ICM-42688P Guide
The ICM-42688P is connected to SPI1 on the Just a Jetson. See the pinmux spreadsheet for the GPIO assignments.
The device shows up in linux under /dev/spidev1.0
To enable the SPI bus using the Jetson Expansion Header Tool, enable spi3.
sudo /opt/nvidia/jetson-io/jetson-io.py
Configure Jetson 40pin Header
Configure header pins manually
=================== Jetson Expansion Header Tool ===================
| |
| |
| Select desired functions (for pins): |
| |
| [ ] aud (7) |
| [ ] extperiph3_clk (29) |
| [ ] extperiph4_clk (31) |
| [ ] i2s2 (12,35,38,40) |
| [ ] pwm1 (15) |
[ ] pwm5 (33) |
| [ ] pwm7 (32) |
| [ ] spi1 (19,21,23,24,26) |
| [*] spi3 (13,16,18,22,37) |
| [*] uarta-cts/rts (11,36) |
| |
| Back |
| |
====================================================================
An example Python driver is provided here.
https://github.com/ARK-Electronics/ARK-OS/blob/main/platform/jetson/scripts/icm42688p_driver.py
import spidev
import time
import Jetson.GPIO as GPIO
# SPI and GPIO Configuration
SPI_BUS = 1 # SPI1
SPI_DEVICE = 0 # CSN0
DRDY_PIN = 7 # GPIO07 (BCM numbering assumed)
# Register Constants
WHO_AM_I = 0x75
DEVICE_ID = 0x47
DEVICE_CONFIG = 0x11
SOFT_RESET = 0x01
REG_BANK_SEL = 0x76
# Register Bank 0 (default)
PWR_MGMT0 = 0x4E
GYRO_CONFIG0 = 0x4F
ACCEL_CONFIG0 = 0x50
INT_STATUS = 0x2D
ACCEL_XOUT_H = 0x1F
ACCEL_SCALE = 9.80665 / 2048 # m/s^2 per LSB
GYRO_SCALE = (3.141592653589793 / 180) / 16.4 # rad/s per LSB
class ICM42688P:
def __init__(self):
self.spi = spidev.SpiDev()
self.spi.open(SPI_BUS, SPI_DEVICE)
self.spi.max_speed_hz = 1000000
self.spi.mode = 0b00
GPIO.setmode(GPIO.BOARD)
GPIO.setup(DRDY_PIN, GPIO.IN)
self._initialize_device()
def _write_register(self, reg, value):
self.spi.xfer2([reg & 0x7F, value]) # MSB=0 for write
def _read_register(self, reg, length=1):
result = self.spi.xfer2([reg | 0x80] + [0x00]*length)
return result[1:] if length > 1 else result[1]
def _select_register_bank(self, bank):
self._write_register(REG_BANK_SEL, bank << 4)
def _initialize_device(self):
self._write_register(DEVICE_CONFIG, SOFT_RESET)
time.sleep(0.1)
whoami = self._read_register(WHO_AM_I)
if whoami != DEVICE_ID:
raise RuntimeError(f"ICM-42688-P not found! WHO_AM_I={whoami:#x}")
self._write_register(PWR_MGMT0, 0x0F) # Enable accel & gyro, low-noise mode
self._write_register(GYRO_CONFIG0, 0x06) # 1kHz ODR, ±2000 dps
self._write_register(ACCEL_CONFIG0, 0x06) # 1kHz ODR, ±16g
print("ICM-42688-P initialized.")
def _read_sensor_data(self):
data = self._read_register(ACCEL_XOUT_H, 14)
ax = self._combine(data[0], data[1]) * (9.80665 / 2048)
ay = self._combine(data[2], data[3]) * (9.80665 / 2048)
az = self._combine(data[4], data[5]) * (9.80665 / 2048)
gx = self._combine(data[6], data[7]) * (3.141592653589793 / 180 / 16.4)
gy = self._combine(data[8], data[9]) * (3.141592653589793 / 180 / 16.4)
gz = self._combine(data[10], data[11]) * (3.141592653589793 / 180 / 16.4)
raw_temp = self._combine(data[12], data[13])
temp_c = (raw_temp / 132.48) + 25
return {
'accel': (ax, ay, az), # in m/s^2
'gyro': (gx, gy, gz), # in rad/s
'temp': temp_c # raw
}
def _combine(self, high, low):
val = (high << 8) | low
return val - 65536 if val & 0x8000 else val
def close(self):
self.spi.close()
GPIO.cleanup()
def wait_for_data_ready(self):
GPIO.wait_for_edge(DRDY_PIN, GPIO.RISING)
# Example usage
if __name__ == '__main__':
imu = ICM42688P()
try:
while True:
#imu.wait_for_data_ready()
data = imu._read_sensor_data()
print(f"Accel: {data['accel']}, Gyro: {data['gyro']}, Temp: {data['temp']}")
finally:
imu.close()
Last updated