ICM-20948: Complete Guide to TDK’s 9-Axis MEMS MotionTracking Sensor
The ICM-20948 is a 9-axis inertial measurement unit (IMU) manufactured by TDK InvenSense that integrates a 3-axis gyroscope, 3-axis accelerometer, 3-axis magnetometer, and an onboard Digital Motion Processor (DMP) into a single 3 × 3 × 1 mm QFN package. Rated at 2.5 mW of power consumption, it was marketed as the world’s lowest-power 9-axis MotionTracking device at launch. Target applications span drones, wearables, and IoT systems. Note: As of 2024, TDK has transitioned the ICM-20948 to NRND (Not Recommended for New Designs) status due to limited magnetometer wafer availability.
ICM-20948 = 9-axis IMU: accelerometer + gyroscope + magnetometer (AK09916) + DMP
Power consumption: 2.5 mW typical — one-third the power of comparable 9-axis devices
Communication: I2C (400 kHz) and SPI (7 MHz); I2C addresses 0x68 / 0x69
Critical: VDDIO accepts only 1.71–1.95 V — applying 3.3V or 5V damages the IC
NRND status means limited availability — consider alternatives for new production designs
Available libraries: SparkFun (DMP support), ICM20948_WE (Wolle's library, 59 functions)
What Is the ICM-20948?
The ICM-20948 is a 9-axis MEMS (Micro-Electro-Mechanical Systems) motion tracking sensor that combines four distinct sensing elements:
| Gyroscope | X, Y, Z | Measures rotational rate (±250 to ±2000 °/s) |
|---|---|---|
| Magnetometer | X, Y, Z | Measures magnetic field strength (±4900 µT) |
| Thermometer | — | On-chip temperature sensor |
The magnetometer is an AK09916 from AKM, integrated into the package but controlled through the ICM-20948’s auxiliary I2C interface. It is not a native part of the ICM-20948 die — it communicates through a separate bus and has its own register set. This distinction matters when debugging magnetometer issues.
The sensor is controlled via either I2C (up to 400 kHz Fast Mode) or SPI (up to 7 MHz). The I2C address is selectable: 0x68 when the AD0 pin is pulled LOW, and 0x69 when pulled HIGH.
ICM-20948 Specifications
| VDD (supply) | 1.71 V to 3.6 V |
|---|---|
| VDDIO (I/O voltage) | 1.71 V to 1.95 V |
| Operating current | ~3.1 mA (typical, DMP off) |
| Power consumption | 2.5 mW |
| Accelerometer ranges | ±2g, ±4g, ±8g, ±16g |
| Accelerometer resolution | 16-bit (16384 LSB/g at ±2g) |
| Gyroscope ranges | ±250, ±500, ±1000, ±2000 °/s |
| Gyroscope data rate | 4.4 Hz to 9 kHz |
| Accelerometer data rate | 4.5 Hz to 4.5 kHz |
| Magnetometer range | ±4900 µT |
| Magnetometer data rate | Up to 100 Hz |
| Digital interfaces | I2C (400 kHz), SPI (7 MHz) |
| Operating temperature | -40°C to +85°C |
| Digital Motion Processor | Yes (embedded 3rd gen DMP) |
The Digital Motion Processor (DMP) is an onboard coprocessor that offloads sensor fusion calculations from the host microcontroller. It supports 6-axis and 9-axis quaternion output, game rotation vector, and ultra-low-power runtime calibration of all three sensors. The DMP requires 14 KB of program memory on the host — an important consideration for constrained microcontrollers like the ATmega328P.
ICM-20948 vs MPU-9250: What Changed?
The ICM-20948 was designed as the direct successor to the MPU-9250, which reached End of Life (EOL) on December 31, 2018. While they share the same package footprint (3 × 3 × 1 mm QFN) and cover the same sensing axes, several engineering differences matter in practice:
| Accelerometer ranges | ±2g to ±16g | ±2g to ±16g |
|---|---|---|
| Magnetometer range | ±4900 µT | ±4800 µT |
| DMP fusion | **9-axis** | **6-axis** |
| Supply voltage range | 1.71–3.6 V (VDD) | 2.4–3.6 V (VDD) |
| Typical current | **3.1 mA** | 3.7 mA |
| SPI max speed | **7 MHz** | 1 MHz |
| I2C auxiliary bus | Yes (controls magnetometer) | Yes |
| NRND / EOL | **NRND (since ~2024)** | EOL (since 2018) |
The most significant practical upgrade is the 9-axis DMP fusion in the ICM-20948 versus the 6-axis fusion in the MPU-9250. With 9-axis fusion, the DMP incorporates magnetometer data into its orientation calculations, producing more accurate heading estimates over time. The ICM-20948 also supports a wider VDD range and lower power consumption.
However, the NRND status of the ICM-20948 is a critical factor for new product designs. TDK recommends evaluating the ICM-42688 (6-axis) or IAM-20680 for new designs requiring motion sensing. The ICM-20648 is a 6-axis alternative that remains active in TDK’s portfolio.
Hardware Overview: Breakout Boards and Module Variants
The ICM-20948 sensor itself operates at 1.8 V on its I/O pins, making direct connection to 5 V Arduino boards dangerous without level shifting. Most hobbyist use comes through breakout boards that add voltage regulation, level shifters, and Qwiic/Stemma QT connectors.
SparkFun 9DoF IMU Breakout (SEN-15335)
The SparkFun breakout is the most popular development board for the ICM-20948. It includes:
- On-board 1.8 V voltage regulator accepting 1.8–5.5 V input
- TXS0108 level shifters on all I/O pins (bi-directional, up to 7 MHz SPI)
- Two Qwiic connectors for daisy-chaining via I2C
- Onboard power LED (disableable via jumper)
- I2C address jumper (ADR) — closed = address 0x68, open = 0x69
- Dual COM headers (I2C and SPI broken out separately)
The SparkFun board accepts 1.8–5.5 V on its VIN pin and handles level shifting internally, making it compatible with Arduino Uno, ESP32, Raspberry Pi, and other popular platforms without additional circuitry.
Generic ICM-20948 Modules (“Version 2”)
Budget modules labeled “v2” or “v2.0” from generic suppliers include voltage regulators but may not include level shifters. These boards typically regulate VIN to 1.8 V but connect VDDIO directly to VIN. On such boards:
- If VIN = 3.3 V or 5 V, the I/O pins output 3.3 V or 5 V — which exceeds the 1.95 V maximum VDDIO rating
- You must use external level shifters (e.g., TXS0108E, TXB0108) or a 1.8 V logic microcontroller
- Some v2 boards include MOSFETs on SDA and SCL but leave CS and INT unprotected
Always verify your module’s pinout and level-shifting capability before connecting it to a 5 V Arduino.
VDDIO: The Most Commonly Missed Detail
The ICM-20948 has two separate power pins: VDD (core supply, 1.71–3.6 V) and VDDIO (I/O supply, 1.71–1.95 V). On many breakout boards, these are tied together internally. If your module connects VDDIO to VDD and you apply 3.3 V, you are operating the I/O at 3.3 V — outside the 1.95 V absolute maximum. This may work temporarily but risks premature failure or erratic behavior.
Connecting ICM-20948 to Arduino, ESP32, and Raspberry Pi
Arduino (I2C)
Parts needed:
- Arduino Uno/Nano/Mega or ESP32
- SparkFun 9DoF ICM-20948 breakout (or equivalent with level shifters)
- Qwiic cable (or 4 dupont wires)
Wiring (Qwiic):
| Red (3.3V) | 3.3V |
|---|---|
| Yellow (SDA) | A4 (Uno/Nano) / GPIO21 (ESP32) |
| Blue (SCL) | A5 (Uno/Nano) / GPIO22 (ESP32) |
Wiring (Dupont, generic module):
| GND | GND |
|---|---|
| SDA | A4 |
| SCL | A5 |
| AD0 | GND (→ 0x68) or 3.3V (→ 0x69) |
⚠️ **Warning for ESP32 users:** Some 5.1 V power supplies cause voltage spikes that damage the ESP32 Thing Plus. Keep supply cables under 6 feet and use a clean 5 V rail.
Raspberry Pi (I2C via Python)
- Enable I2C:
sudo raspi-config→ Interface Options → I2C → Enable - Install the Pimoroni library:
curl https://get.pimoroni.com/icm20948 | bash - Run the example:
import icm20948
from icm20948 import ICM20948
imu = ICM20948()
imu.init()
while True:
accel = imu.get_accel_data()
gyro = imu.get_gyro_data()
mag = imu.get_mag_data()
print(f"Accel: {accel}, Gyro: {gyro}, Mag: {mag}")
time.sleep(0.1)
SPI Connection (Advanced)
To use SPI (up to 7 MHz, faster than I2C’s 400 kHz):
| SCLK | Pin 13 |
|---|---|
| MISO | Pin 12 |
| CS | Pin 2 (or any digital pin) |
| VIN | 3.3V or 5V |
| GND | GND |
In your Arduino sketch, uncomment #define USE_SPI and specify the CS pin.
ICM-20948 Arduino Library Setup and Configuration
Installing the SparkFun Library
- Open Arduino IDE
- Go to Sketch → Include Library → Manage Libraries
- Search for “SparkFun 9DoF IMU Breakout”
- Install version 1.2.5 or later
Basic I2C Example (Example1_Basics)
#include "ICM_20948.h" // http://librarymanager/All#SparkFun_ICM_20948_IMU
#define WIRE_PORT Wire
#define I2C_ADDR ICM_20948_I2C_ADDR_SECONDARY // 0x69; use PRIMARY (0x68) if AD0 = GND
ICM_20948_I2C myICM;
void setup() {
WIRE_PORT.begin();
WIRE_PORT.setClock(400000); // Fast I2C mode
Serial.begin(115200);
myICM.begin(WIRE_PORT, I2C_ADDR);
if (myICM.status != ICM_20948_Stat_Ok) {
Serial.println("ICM-20948 not responding — check wiring");
while (1);
}
}
void loop() {
if (myICM.dataReady()) {
myICM.getAGMT(); // Reads Accelerometer, Gyro, Mag, Temp
Serial.print("Accel X: "); Serial.print(myICM.accX());
Serial.print(" Y: "); Serial.print(myICM.accY());
Serial.print(" Z: "); Serial.println(myICM.accZ());
Serial.print("Gyro X: "); Serial.print(myICM.gyrX());
Serial.print(" Y: "); Serial.print(myICM.gyrY());
Serial.print(" Z: "); Serial.println(myICM.gyrZ());
Serial.print("Mag X: "); Serial.print(myICM.magX());
Serial.print(" Y: "); Serial.print(myICM.magY());
Serial.print(" Z: "); Serial.println(myICM.magZ());
Serial.print("Temp: "); Serial.println(myICM.temp());
}
delay(30);
}
Enabling DMP Support
The DMP is disabled by default in the SparkFun library because it consumes 14 KB of program memory. To enable it:
- Navigate to Documents/Arduino/libraries/SparkFun_ICM_20948_ArduinoLibrary/src/util/
- Open ICM_20948_C.h
- Uncomment line 29: #define ICM_20948_USE_DMP
Library version 1.2.5+ provides an initializeDMP() helper function that automatically downloads DMP firmware and configures registers. Once enabled, DMP outputs include:
- Raw and calibrated sensor data with accuracy estimates
- 6-axis and 9-axis quaternion data
- Game Rotation Vector
- Ultra-low-power runtime calibration
Alternative: ICM20948_WE Library
For deeper register-level control, Wolle Waldmann’s ICM20948_WE library (available in the Arduino Library Manager) provides 59 public functions across 13 example sketches. This library is ideal for applications that need:
- Custom DLPF (Digital Low Pass Filter) configurations
- Precise calibration with manual offset values
- Low-power cycle mode operation
- Extended auxiliary I2C bus usage
The library supports both I2C and SPI on any TwoWire port (useful for dual-I2C microcontrollers like the ESP32).
ICM-20948 Calibration: Getting Accurate Readings
Factory-calibrated sensors still exhibit zero-point offsets. For precision applications, run the auto-calibration routine at startup:
Accelerometer and Gyroscope Auto-Offset
Place the ICM-20948 flat (x,y plane horizontal) before calling autoOffsets(). The function:
- Measures the acceleration vector under gravity
- Calculates zero-point offsets for each axis
- Applies corrections to all future readings
- Also measures and corrects gyroscope drift
Serial.println("Place ICM-20948 flat — calibrating...");
delay(1000);
myIMU.autoOffsets(); // Blocks for ~1 second
Serial.println("Calibration complete.");
Manual Calibration (Advanced)
For non-flat mounting orientations, use setAccOffsets() with pre-measured minimum and maximum raw values:
// Measure raw values at +1g and -1g for each axis, then:
myIMU.setAccOffsets(-16330.0, 16450.0, -16600.0, 16180.0, -16640.0, 16560.0);
This approach corrects both zero-point offset and slope/ratio errors, giving better accuracy at arbitrary angles.
Gyroscope Offset
myIMU.setGyrOffsets(-115.0, 130.0, 105.0); // Values from your specific module
Store calibration constants in EEPROM if your application requires them to persist across power cycles.
ICM-20948 Digital Low Pass Filter Configuration
The DLPF reduces noise in exchange for reduced bandwidth. Both the accelerometer and gyroscope have independent DLPF settings:
Gyroscope DLPF (lowest noise at DLPF_6):
| 5 | 11.6 Hz | 1125/(1+GSRD) Hz |
|---|---|---|
| 6 | 5.7 Hz | 1125/(1+GSRD) Hz |
| OFF | 12106 Hz | 9000 Hz |
Accelerometer DLPF (lowest noise at DLPF_6):
| 5 | 11.5 Hz | 1125/(1+ASRD) Hz |
|---|---|---|
| 6 | 5.7 Hz | 1125/(1+ASRD) Hz |
| OFF | 1209.0 Hz | 4500 Hz |
For most motion tracking applications, DLPF_6 provides the best balance between noise reduction and response time.
Common Issues and Troubleshooting
ICM-20948 not responding:
- Verify wiring: SDA → A4, SCL → A5 (Uno/Nano), or correct pins for your board
- Check that VIN receives 3.3 V or 5 V (not 12 V)
- Confirm AD0 is connected to either GND (0x68) or 3.3 V (0x69)
- If using a generic module without level shifters, VDDIO damage may have occurred
Magnetometer reads 0,0,0:
- The AK09916 magnetometer requires a separate initialization. The SparkFun library handles this automatically in begin().
- If readings are stuck at zero, try calling myICM.initMagnetometer() explicitly.
- Magnetic interference from nearby motors, speakers, or ferrous metals distorts readings.
Inaccurate heading from magnetometer:
- Run manual hard and soft iron calibration (figure-8 motion)
- The magnetometer must be calibrated in the final product’s environment, not on a bench
- Keep the ICM-20948 away from DC motors and permanent magnets
DMP quaternion jumps:
- Ensure DMP firmware download completed successfully (requires ~2 seconds at startup)
- Disable autoOffsets() if you are using manual calibration — they conflict
- Check that you are reading the correct quaternion data type (DMP outputs 6-axis or 9-axis quaternions)
Alternatives to the ICM-20948
Given the NRND status, consider these active alternatives:
| ICM-42670 | 6-axis | Cost-optimized alternative |
|---|---|---|
| MPU-9250 | 9-axis | EOL but widely available in surplus |
| BNO055 | 9-axis | Integrated sensor fusion, easier to use, 3.3 V only |
| LSM9DS1 | 9-axis | STM sensor, I2C + SPI, active |
The BNO055 from Bosch is the most practical drop-in replacement for projects prioritizing ease of use — it includes automatic sensor fusion without DMP programming. However, it lacks the raw sensor access and configurability of the ICM-20948.
Conclusion
The ICM-20948 remains a capable 9-axis motion tracking sensor for embedded projects, provided its NRND status is factored into supply chain planning. Its key strengths — 2.5 mW power consumption, 9-axis DMP fusion, dual I2C/SPI interface, and compact 3 × 3 × 1 mm package — make it well-suited for drones, wearables, and IoT applications where power budget is constrained. The critical engineering gotchas — VDDIO voltage limits, the AK09916’s auxiliary I2C dependency, and the 14 KB DMP memory footprint — are manageable with proper hardware selection and library configuration. For new designs, evaluate active alternatives like the ICM-42688 or BNO055 unless the specific 9-axis form factor and magnetometer integration are required.
Sources: TDK InvenSense ICM-20948 Product Page, TDK MPU-9250 to ICM-20948 Migration Guide, SparkFun ICM-20948 Arduino Library, Wolles Elektronikkiste ICM-20948 Guide