SparkFun 9DoF IMU (ICM-20948) Breakout Hookup Guide

Contributors: Ell C, Liquid Soulder
Favorited Favorite 0

Software Setup and Example Code

Note: This example assumes you are using the latest version of the Arduino IDE on your desktop. If this is your first time using Arduino, please review our tutorial on installing the Arduino IDE. If you have not previously installed an Arduino library, please check out our installation guide.

In this example, we are using the SparkFun Esp32 Thing WROOM Plus. If you have not used this board before, head on over to the ESP32 Thing Plus Hookup Guide for a general overview, as well as information on getting set up with board definitions.

ESP32 Thing Plus Hookup Guide

March 7, 2019

Hookup guide for the ESP32 Thing Plus using the ESP32 WROOM's WiFi/Bluetooth system-on-chip in Arduino.

In order to use the ICM-20948 breakout, you'll need to install the SparkFun ICM-20948 Arduino Library. We recommend you install the library via the Arduino IDE by using the library manager and search for Sparkfun 9DoF IMU Breakout. Or you can download and manually install a zip of the library by clicking on the link below. For those who want to view the code, check out the GitHub repo.

Example 1

In this example, we've hookup up our ICM-20948 to an ESP32 Thing Plus using a short Qwiic cable.

Once you've installed the ICM-20948 library, load the first example sketch from File->Examples->SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library->Arduino->Example1_Basics.

Where to find Example 1 in the Arduino IDE

Having a hard time seeing? Click the image for a closer look.

The very first thing you'll see in the code is the #include statement for the library. Alongside that is a convenient link that will help you get the library through the Arduino library manager. Next is a commented out #define statement called 'USE_SPI'. If instead you have chosen to connect your ICM with the SPI pins all you need to do is uncomment that line.

#include "ICM_20948.h"  // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU

//#define USE_SPI       // Uncomment this to use SPI

Up next is a short section where you can configure your particular setup. First of all if you need to change your serial port, e.g. if you're using a SAMD21 board, you can change the 'SERIAL_PORT' define ('SerialUSB' for SAMD21). You can do the same to change your I2C port or SPI port, depending on which you're using. When using I2C you have the ability to change the I2C address of the sensor with the Address 0 bit. By default it is '1' but you could change it to 0 if you've closed the 'ADR' jumper. When using SPI you need to specify a chip select pin - in the example we default to pin 2.

#define SERIAL_PORT Serial

#define SPI_PORT SPI    // Your desired SPI port.       Used only when "USE_SPI" is defined
#define CS_PIN 2        // Which pin you connect CS to. Used only when "USE_SPI" is defined

#define WIRE_PORT Wire  // Your desired Wire port.      Used when "USE_SPI" is not defined
#define AD0_VAL   1     // The value of the last bit of the I2C address. 
                        // On the SparkFun 9DoF IMU breakout the default is 1, and when 
                        // the ADR jumper is closed the value becomes 0

That's it for stuff you (might) need to do to set up the example! Now we'll just all hop in the bus, take a tour, and I'll point out items on your right and left.

The next little block creates either a ICM_20948_I2C or ICM_20948_SPI object called 'myICM'. Since they have the same name, and they both inherit from the grandaddy ICM_20948 class, we'll be able to use them interchangeably later on in the example.

#ifdef USE_SPI
  ICM_20948_SPI myICM;  // If using SPI create an ICM_20948_SPI object
  ICM_20948_I2C myICM;  // Otherwise create an ICM_20948_I2C object

In the setup() function we have your standard Arduino initialization of your serial port, and then we have the last interface-dependent section. There you'll see the 'myICM' object being started up with the appropriate arguments for the chosen interface. This example shows all arguments being explicitly stated, but it is also possible to call the .begin() function with default arguments. The initialization will repeat with a delay until the device is successfully found. If it is not connecting try checking your wiring.

#ifdef USE_SPI
    myICM.begin( CS_PIN, SPI_PORT ); 
    myICM.begin( WIRE_PORT, AD0_VAL );

Here's a little trick for debugging the ICM - nearly all operations will update the internal 'myICM.status' value. You can check it directly (0 means all good, anything else is an error) or you can use the statusString() method to get the latest status in human-readable form.

    SERIAL_PORT.print( F("Initialization of the sensor returned: ") );
    SERIAL_PORT.println( myICM.statusString() );
    if( myICM.status != ICM_20948_Stat_Ok ){
      SERIAL_PORT.println( "Trying again..." );
      initialized = true;

The last part of the sketch is the loop() where the sensor gets polled for new data, and that data gets pushed over the serial port. All the data is contained in the 'AGMT' structure, which stands for Accelerometer, Gyroscope, Magnetometer, and Temperature sensors. For convenience this sketch also includes functions (that are not part of the library) to print the results in a pretty format.

void loop() {

  if( myICM.dataReady() ){
    myICM.getAGMT();                // The values are only updated when you call 'getAGMT'
//    printRawAGMT( myICM.agmt );     // Uncomment this to see the raw values, taken directly from the agmt structure
    printScaledAGMT( myICM.agmt);   // This function takes into account the sclae settings from when the measurement was made to calculate the values with units
    Serial.println("Waiting for data");


When you open up your Serial Monitor, you should see something like the following:

Serial Output

Having a hard time seeing? Click the image for a closer look.

There ya have it! Now go ahead and hack it up.