View on GitHub

ICM-20948 STM32 Driver

â„šī¸ Current Support: SPI Interface Only

From Noisy Data to Robot-Ready Orientation

Taming the 9-DOF Beast

The ICM-20948 is a powerful 9-DOF sensor, but its raw output is noisy, uncalibrated, and misaligned. This driver provides a complete software suite to transform this chaotic data into a stable, accurate, and intuitive data stream for any robotics, drone, or motion-tracking project.

The Core Problem: Raw vs. Processed

BEFORE: Raw Magnetometer Data

Without calibration, the sensor data is offset (not centered at zero) and has a distorted scale, making it useless for calculating direction.

AFTER: Calibrated Data

Using the driver's calibration suite, the Hard Iron (Bias) and Soft Iron (Scale) errors are corrected, providing a clean, centered data stream.

Driver Key Features

Complete 9-DOF Access

The driver unifies all 9 axes (plus temperature) from the three internal sensors into a single, easy-to-use structure.

Advanced Calibration Suite

A three-stage process to correct all common sensor errors, turning raw values into physically accurate measurements.

🔄 Gyroscope (Stationary)
↓
đŸ“Ļ Accelerometer (6-Point)
↓
🌐 Magnetometer (Figure-8)

Axis Remapping Engine

Translates the sensor's physical orientation (Sensor Frame) to match your vehicle's frame (Body Frame) with one simple function.

Sensor Frame

(X, Y, Z on the chip)

→
SetMounting()
→

Body Frame

(Vehicle Front, Right, Up)

Interactive Axis Remapping Engine

Configure how your sensor is mounted. Drag to rotate the 3D view, Scroll to zoom. The visualization updates in real-time.

đŸ–ąī¸ Drag to Rotate | 🔍 Scroll to Zoom

Mounting Configuration

Robot Front (X)
=
Robot Right (Y)
=
Robot Up (Z)
=
Generated Code
                                // Initializing...
                            

Implementation Examples

📡 Standard Usage

main.c
#include "ICM20948.h"

// 0. Define Handle with Hardware Config
ICM20948_HandleTypeDef ICM = {
    .hspi = &hspi5,
    .CS_GPIO_Port = GPIOA,
    .CS_Pin = GPIO_PIN_4
};

void main() {
    // 1. Initialize & Load Calibration
    ICM20948.Init(&ICM);

    while (1) {
        // 2. Read & Process
        ICM20948.ReadData(&ICM);
        
        float ax = ICM.sensor.accel.x;
        printf("Accel X: %.2f g\n", ax);
        
        HAL_Delay(2);
    }
}

đŸ› ī¸ Calibration Routine

setup.c
void RunCalibration() {
    printf("Starting Calibration...\n");

    // 1. Gyro: Place sensor FLAT and STATIONARY
    ICM20948.CalibrateGyro(&ICM);

    // 2. Accel: Follow terminal prompts (6 positions)
    ICM20948.CalibrateAccel(&ICM);

    // 3. Mag: Wave sensor in Figure-8 motion
    ICM20948.CalibrateMag(&ICM);
    
    // Result: Values printed to terminal
}

💾 Saving Calibration Data

ICM20948.c

Copy the values from your terminal and paste them at the top of the ICM20948_Init function:

void ICM20948_Init(ICM20948_HandleTypeDef *icm)
{
    // ------------------------------------------------------------------
    // [USER CONFIG] Pre-calibrated values (Hardcoded)
    // ------------------------------------------------------------------
    
    // Reset Bias (0)
    icm->bias.gyro.x = -8.2528f;
    icm->bias.gyro.y = 3.1247f;
    icm->bias.gyro.z = 5.9230f;
    icm->bias.mag.x = -215.5f;
    icm->bias.mag.y = 137.0f;
    icm->bias.mag.z = 94.0f;
    icm->bias.accel.x = -18.9f;
    icm->bias.accel.y = -14.8f;
    icm->bias.accel.z = 141.7f;

    // Set Scale (1)
    icm->scale.gyro.x = 1.0f;
    icm->scale.gyro.y = 1.0f;
    icm->scale.gyro.z = 1.0f;
    icm->scale.mag.x = 1.5012f;
    icm->scale.mag.y = 0.8863f;
    icm->scale.mag.z = 0.8295f;
    icm->scale.accel.x = 1.0021f;
    icm->scale.accel.y = 1.0010f;
    icm->scale.accel.z = 0.9980f;

    // ... rest of init code ...
}

🔄 Remapping Setup

main.c

âš ī¸ IMPORTANT: Place this code AFTER calling Init() in your main function.

void main() {
    // 1. Initialize Sensor (Loads calibration & default mounting)
    ICM20948.Init(&ICM);

    // 2. Configure Sensor Mounting Orientation (Body Frame)
    // Use the tool above to generate this code block
    ICM20948.SetMounting(&ICM,
        AXIS_Y, SIGN_POS,  // Robot Front (X) = Sensor Y
        AXIS_X, SIGN_NEG,  // Robot Right (Y) = Sensor -X
        AXIS_Z, SIGN_POS   // Robot Up (Z)    = Sensor Z
    );

    while (1) {
        // ... Loop ...
    }
}