| Crates.io | icm20948-rs |
| lib.rs | icm20948-rs |
| version | 0.1.1 |
| created_at | 2025-12-28 11:43:52.609825+00 |
| updated_at | 2025-12-28 11:58:57.961054+00 |
| description | Platform-agnostic driver for the ICM-20948 9-axis IMU |
| homepage | |
| repository | https://github.com/1-rafael-1/ICM-20948-rs |
| max_upload_size | |
| id | 2008648 |
| size | 902,225 |
A platform-agnostic Rust driver for the ICM-20948 9-axis IMU (Inertial Measurement Unit), featuring:
This driver is built using the device-driver toolkit and supports both blocking and async operation modes.
Note: This driver draws extensively on the SparkFun ICM-20948 Arduino Library for guidance on register interactions and initialization sequences. The DMP firmware is also sourced from SparkFun's MIT-licensed library.
Note: Another invaluable source extensively used is the ICM-20948 component for ESP-IDF by Cybergear Robotics, which provided deep insights into the device's operation and configuration.
Note: This driver has been created with the help of agentic AI. Code has been self-reviewed but I am a hobbyist developer and have very little prior experience with IMUs, so I will not have spotted everything. To validate viability so far I have created a number of examples and ran them on hardware. Additionally I have made sure the agent added tests and CI, that run on every PR and every push to main.
I was hoping to make DMP work and was looking for some christmas holidays entertainment making it. I failed at DMP but was duly entertained. In its current form this driver has somewhat more features than other existing ICM-20948 drivers, so I decided to publish it anyway. Somebody somewhere may find it useful.
That being said, this driver works for me and my hobby needs so far but WILL contain bugs and imperfections. In case YOU find any issues, please consider submitting a PR or opening an issue so I can improve this driver over time. Thank you!
no_std compatible - Works in embedded environments without standard libraryAdd this to your Cargo.toml:
[dependencies]
icm20948-rs = "0.1"
The driver includes blocking I2C/SPI support by default. See the Features section below for optional features like async, defmt, and dmp.
async - Enable AsyncRegisterInterface trait implementations for embedded-hal-async 1.0defmt - Enable defmt formatting support for typesdmp - Enable Digital Motion Processor (DMP) firmware loading (not functional yet!)Note: The crate uses embedded-hal for blocking I2C/SPI traits and core functionality like DelayNs used by magnetometer operations. The async feature is additive and provides async trait implementations alongside the blocking ones.
use icm20948::{Icm20948Driver, I2cInterface};
use icm20948::sensors::{AccelConfig, AccelFullScale, AccelDlpf};
use icm20948::sensors::{GyroConfig, GyroFullScale, GyroDlpf};
// Create I2C interface with default address (0x68, AD0 pin LOW)
let interface = I2cInterface::default(i2c);
// Create driver and initialize
let mut imu = Icm20948Driver::new(interface)?;
imu.init()?;
// Configure accelerometer: ±2g range, 246 Hz DLPF
let accel_config = AccelConfig {
full_scale: AccelFullScale::G2,
dlpf: AccelDlpf::Hz246,
dlpf_enable: true,
sample_rate_div: 10,
};
imu.configure_accelerometer(accel_config)?;
// Configure gyroscope: ±250°/s range, 197 Hz DLPF
let gyro_config = GyroConfig {
full_scale: GyroFullScale::Dps250,
dlpf: GyroDlpf::Hz197,
dlpf_enable: true,
sample_rate_div: 10,
};
imu.configure_gyroscope(gyro_config)?;
// Read sensor data
let accel = imu.read_accelerometer()?; // Returns data in g
let gyro = imu.read_gyroscope()?; // Returns data in °/s
let temp = imu.read_temperature_celsius()?; // Returns °C
println!("Accel: x={:.2}g y={:.2}g z={:.2}g", accel.x, accel.y, accel.z);
println!("Gyro: x={:.2}°/s y={:.2}°/s z={:.2}°/s", gyro.x, gyro.y, gyro.z);
println!("Temp: {:.2}°C", temp);
For complete working examples with async Embassy, magnetometer, FIFO, self-test diagnostics, and more, see the examples/rp2350-blocking/ and examples/rp2350-async/ directories.
The ICM-20948 organizes registers into 4 banks:
The driver automatically handles bank switching, so you don't need to worry about it in normal usage.
The driver provides high-level APIs that return sensor data in physical units:
For raw 16-bit values, use the _raw() variants like read_accel_raw() and read_gyro_raw().
I2C Addresses:
0x68 when AD0 is LOW (default) - use I2cInterface::default(i2c)0x69 when AD0 is HIGH (alternative) - use I2cInterface::alternative(i2c)⚠️ SPI Status: The SPI interface is implemented but has not been tested with hardware. Pull Requests with fixes and/or examples are welcome!
SPI Configuration:
The driver includes unit tests, async tests, and integration tests with mock hardware interfaces.
# Run library unit tests
cargo test --lib
# Run async tests
cargo test --test async_tests --features std,async
# Run FIFO efficiency tests
cargo test --test fifo_efficiency_test --features std
Continuous Integration: See .github/workflows/ci.yml for the CI test suite, which includes:
All tests run automatically on every push and pull request.
Core Functionality:
WHO_AM_I verificationSensors:
Advanced Features:
Interrupts:
Wake-on-Motion:
Digital Motion Processor (DMP):
dmp feature flag)ahrs_euler.rs example) insteadLicensed under the MIT License (LICENSE or http://opensource.org/licenses/MIT).
This project extensively references the SparkFun ICM-20948 Arduino Library (also MIT licensed) for register sequences and DMP firmware. The DMP firmware binary is included from SparkFun's library under the MIT License (Copyright (c) 2016 SparkFun Electronics). See src/dmp/firmware.rs for the complete license text.
Contributions are welcome! Please feel free to submit a Pull Request.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be licensed under the MIT license, without any additional terms or conditions.