Modified Arduino library for ICM_20948 IMU for Nucleo boards

Revision:
0:894b603d32ee
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/ICM_20948_C.c	Mon Jan 31 03:25:31 2022 +0000
@@ -0,0 +1,2595 @@
+#include "ICM_20948_C.h"
+#include "ICM_20948_REGISTERS.h"
+#include "AK09916_REGISTERS.h"
+
+/*
+ * Icm20948 device require a DMP image to be loaded on init
+ * Provide such images by mean of a byte array
+*/
+#if defined(ICM_20948_USE_DMP) // Only include the 14301 Bytes of DMP if ICM_20948_USE_DMP is defined
+
+#if defined(ARDUINO_ARCH_MBED) // ARDUINO_ARCH_MBED (APOLLO3 v2) does not support or require pgmspace.h / PROGMEM
+const uint8_t dmp3_image[] = {
+#elif (defined(__AVR__) || defined(__arm__) || defined(__ARDUINO_ARC__)) && !defined(__linux__) // Store the DMP firmware in PROGMEM on older AVR (ATmega) platforms
+#define ICM_20948_USE_PROGMEM_FOR_DMP
+#include <avr/pgmspace.h>
+const uint8_t dmp3_image[] PROGMEM = {
+#else
+const uint8_t dmp3_image[] = {
+#endif
+
+#include "icm20948_img.dmp3a.h"
+};
+#endif
+
+// ICM-20948 data is big-endian. We need to make it little-endian when writing into icm_20948_DMP_data_t
+const int DMP_Quat9_Byte_Ordering[icm_20948_DMP_Quat9_Bytes] =
+    {
+        3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 13, 12 // Also used for Geomag
+};
+const int DMP_Quat6_Byte_Ordering[icm_20948_DMP_Quat6_Bytes] =
+    {
+        3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8 // Also used for Gyro_Calibr, Compass_Calibr
+};
+const int DMP_PQuat6_Byte_Ordering[icm_20948_DMP_PQuat6_Bytes] =
+    {
+        1, 0, 3, 2, 5, 4 // Also used for Raw_Accel, Compass
+};
+const int DMP_Raw_Gyro_Byte_Ordering[icm_20948_DMP_Raw_Gyro_Bytes + icm_20948_DMP_Gyro_Bias_Bytes] =
+    {
+        1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10};
+const int DMP_Activity_Recognition_Byte_Ordering[icm_20948_DMP_Activity_Recognition_Bytes] =
+    {
+        0, 1, 5, 4, 3, 2};
+const int DMP_Secondary_On_Off_Byte_Ordering[icm_20948_DMP_Secondary_On_Off_Bytes] =
+    {
+        1, 0};
+
+const uint16_t inv_androidSensor_to_control_bits[ANDROID_SENSOR_NUM_MAX] =
+    {
+        // Data output control 1 register bit definition
+        // 16-bit accel                                0x8000
+        // 16-bit gyro                                 0x4000
+        // 16-bit compass                              0x2000
+        // 16-bit ALS                                  0x1000
+        // 32-bit 6-axis quaternion                    0x0800
+        // 32-bit 9-axis quaternion + heading accuracy 0x0400
+        // 16-bit pedometer quaternion                 0x0200
+        // 32-bit Geomag rv + heading accuracy         0x0100
+        // 16-bit Pressure                             0x0080
+        // 32-bit calibrated gyro                      0x0040
+        // 32-bit calibrated compass                   0x0020
+        // Pedometer Step Detector                     0x0010
+        // Header 2                                    0x0008
+        // Pedometer Step Indicator Bit 2              0x0004
+        // Pedometer Step Indicator Bit 1              0x0002
+        // Pedometer Step Indicator Bit 0              0x0001
+        // Unsupported Sensors are 0xFFFF
+
+        0xFFFF, // 0  Meta Data
+        0x8008, // 1  Accelerometer
+        0x0028, // 2  Magnetic Field
+        0x0408, // 3  Orientation
+        0x4048, // 4  Gyroscope
+        0x1008, // 5  Light
+        0x0088, // 6  Pressure
+        0xFFFF, // 7  Temperature
+        0xFFFF, // 8  Proximity <----------- fixme
+        0x0808, // 9  Gravity
+        0x8808, // 10 Linear Acceleration
+        0x0408, // 11 Rotation Vector
+        0xFFFF, // 12 Humidity
+        0xFFFF, // 13 Ambient Temperature
+        0x2008, // 14 Magnetic Field Uncalibrated
+        0x0808, // 15 Game Rotation Vector
+        0x4008, // 16 Gyroscope Uncalibrated
+        0x0000, // 17 Significant Motion
+        0x0018, // 18 Step Detector
+        0x0010, // 19 Step Counter <----------- fixme
+        0x0108, // 20 Geomagnetic Rotation Vector
+        0xFFFF, // 21 ANDROID_SENSOR_HEART_RATE,
+        0xFFFF, // 22 ANDROID_SENSOR_PROXIMITY,
+
+        0x8008, // 23 ANDROID_SENSOR_WAKEUP_ACCELEROMETER,
+        0x0028, // 24 ANDROID_SENSOR_WAKEUP_MAGNETIC_FIELD,
+        0x0408, // 25 ANDROID_SENSOR_WAKEUP_ORIENTATION,
+        0x4048, // 26 ANDROID_SENSOR_WAKEUP_GYROSCOPE,
+        0x1008, // 27 ANDROID_SENSOR_WAKEUP_LIGHT,
+        0x0088, // 28 ANDROID_SENSOR_WAKEUP_PRESSURE,
+        0x0808, // 29 ANDROID_SENSOR_WAKEUP_GRAVITY,
+        0x8808, // 30 ANDROID_SENSOR_WAKEUP_LINEAR_ACCELERATION,
+        0x0408, // 31 ANDROID_SENSOR_WAKEUP_ROTATION_VECTOR,
+        0xFFFF, // 32 ANDROID_SENSOR_WAKEUP_RELATIVE_HUMIDITY,
+        0xFFFF, // 33 ANDROID_SENSOR_WAKEUP_AMBIENT_TEMPERATURE,
+        0x2008, // 34 ANDROID_SENSOR_WAKEUP_MAGNETIC_FIELD_UNCALIBRATED,
+        0x0808, // 35 ANDROID_SENSOR_WAKEUP_GAME_ROTATION_VECTOR,
+        0x4008, // 36 ANDROID_SENSOR_WAKEUP_GYROSCOPE_UNCALIBRATED,
+        0x0018, // 37 ANDROID_SENSOR_WAKEUP_STEP_DETECTOR,
+        0x0010, // 38 ANDROID_SENSOR_WAKEUP_STEP_COUNTER,
+        0x0108, // 39 ANDROID_SENSOR_WAKEUP_GEOMAGNETIC_ROTATION_VECTOR
+        0xFFFF, // 40 ANDROID_SENSOR_WAKEUP_HEART_RATE,
+        0x0000, // 41 ANDROID_SENSOR_WAKEUP_TILT_DETECTOR,
+        0x8008, // 42 Raw Acc
+        0x4048, // 43 Raw Gyr
+};
+
+const ICM_20948_Serif_t NullSerif = {
+    NULL, // write
+    NULL, // read
+    NULL, // user
+};
+
+// Private function prototypes
+
+// Function definitions
+ICM_20948_Status_e ICM_20948_init_struct(ICM_20948_Device_t *pdev)
+{
+  // Initialize all elements by 0 except for _last_bank
+  // Initialize _last_bank to 4 (invalid bank number)
+  // so ICM_20948_set_bank function does not skip issuing bank change operation
+  static const ICM_20948_Device_t init_device = { ._last_bank = 4 };
+  *pdev = init_device;
+  return ICM_20948_Stat_Ok;
+}
+
+ICM_20948_Status_e ICM_20948_link_serif(ICM_20948_Device_t *pdev, const ICM_20948_Serif_t *s)
+{
+  if (s == NULL)
+  {
+    return ICM_20948_Stat_ParamErr;
+  }
+  if (pdev == NULL)
+  {
+    return ICM_20948_Stat_ParamErr;
+  }
+  pdev->_serif = s;
+  return ICM_20948_Stat_Ok;
+}
+
+ICM_20948_Status_e ICM_20948_execute_w(ICM_20948_Device_t *pdev, uint8_t regaddr, uint8_t *pdata, uint32_t len)
+{
+  if (pdev->_serif->write == NULL)
+  {
+    return ICM_20948_Stat_NotImpl;
+  }
+  return (*pdev->_serif->write)(regaddr, pdata, len, pdev->_serif->user);
+}
+
+ICM_20948_Status_e ICM_20948_execute_r(ICM_20948_Device_t *pdev, uint8_t regaddr, uint8_t *pdata, uint32_t len)
+{
+  if (pdev->_serif->read == NULL)
+  {
+    return ICM_20948_Stat_NotImpl;
+  }
+  return (*pdev->_serif->read)(regaddr, pdata, len, pdev->_serif->user);
+}
+
+//Transact directly with an I2C device, one byte at a time
+//Used to configure a device before it is setup into a normal 0-3 peripheral slot
+ICM_20948_Status_e ICM_20948_i2c_controller_periph4_txn(ICM_20948_Device_t *pdev, uint8_t addr, uint8_t reg, uint8_t *data, uint8_t len, bool Rw, bool send_reg_addr)
+{
+  // Thanks MikeFair! // https://github.com/kriswiner/MPU9250/issues/86
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  addr = (((Rw) ? 0x80 : 0x00) | addr);
+
+  retval = ICM_20948_set_bank(pdev, 3);
+  retval = ICM_20948_execute_w(pdev, AGB3_REG_I2C_PERIPH4_ADDR, (uint8_t *)&addr, 1);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_set_bank(pdev, 3);
+  retval = ICM_20948_execute_w(pdev, AGB3_REG_I2C_PERIPH4_REG, (uint8_t *)&reg, 1);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  ICM_20948_I2C_PERIPH4_CTRL_t ctrl;
+  ctrl.EN = 1;
+  ctrl.INT_EN = false;
+  ctrl.DLY = 0;
+  ctrl.REG_DIS = !send_reg_addr;
+
+  ICM_20948_I2C_MST_STATUS_t i2c_mst_status;
+  bool txn_failed = false;
+  uint16_t nByte = 0;
+
+  while (nByte < len)
+  {
+    if (!Rw)
+    {
+      retval = ICM_20948_set_bank(pdev, 3);
+      retval = ICM_20948_execute_w(pdev, AGB3_REG_I2C_PERIPH4_DO, (uint8_t *)&(data[nByte]), 1);
+      if (retval != ICM_20948_Stat_Ok)
+      {
+        return retval;
+      }
+    }
+
+    // Kick off txn
+    retval = ICM_20948_set_bank(pdev, 3);
+    retval = ICM_20948_execute_w(pdev, AGB3_REG_I2C_PERIPH4_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_I2C_PERIPH4_CTRL_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+
+    // long tsTimeout = millis() + 3000;  // Emergency timeout for txn (hard coded to 3 secs)
+    uint32_t max_cycles = 1000;
+    uint32_t count = 0;
+    bool peripheral4Done = false;
+    while (!peripheral4Done)
+    {
+      retval = ICM_20948_set_bank(pdev, 0);
+      retval = ICM_20948_execute_r(pdev, AGB0_REG_I2C_MST_STATUS, (uint8_t *)&i2c_mst_status, 1);
+
+      peripheral4Done = (i2c_mst_status.I2C_PERIPH4_DONE /*| (millis() > tsTimeout) */); //Avoid forever-loops
+      peripheral4Done |= (count >= max_cycles);
+      count++;
+    }
+    txn_failed = (i2c_mst_status.I2C_PERIPH4_NACK /*| (millis() > tsTimeout) */);
+    txn_failed |= (count >= max_cycles);
+    if (txn_failed)
+      break;
+
+    if (Rw)
+    {
+      retval = ICM_20948_set_bank(pdev, 3);
+      retval = ICM_20948_execute_r(pdev, AGB3_REG_I2C_PERIPH4_DI, &data[nByte], 1);
+    }
+
+    nByte++;
+  }
+
+  if (txn_failed)
+  {
+    //We often fail here if mag is stuck
+    return ICM_20948_Stat_Err;
+  }
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_i2c_master_single_w(ICM_20948_Device_t *pdev, uint8_t addr, uint8_t reg, uint8_t *data)
+{
+  return ICM_20948_i2c_controller_periph4_txn(pdev, addr, reg, data, 1, false, true);
+}
+
+ICM_20948_Status_e ICM_20948_i2c_master_single_r(ICM_20948_Device_t *pdev, uint8_t addr, uint8_t reg, uint8_t *data)
+{
+  return ICM_20948_i2c_controller_periph4_txn(pdev, addr, reg, data, 1, true, true);
+}
+
+ICM_20948_Status_e ICM_20948_set_bank(ICM_20948_Device_t *pdev, uint8_t bank)
+{
+  if (bank > 3)
+  {
+    return ICM_20948_Stat_ParamErr;
+  } // Only 4 possible banks
+
+  if (bank == pdev->_last_bank) // Do we need to change bank?
+    return ICM_20948_Stat_Ok;   // Bail if we don't need to change bank to avoid unnecessary bus traffic
+
+  pdev->_last_bank = bank;   // Store the requested bank (before we bit-shift)
+  bank = (bank << 4) & 0x30; // bits 5:4 of REG_BANK_SEL
+  return ICM_20948_execute_w(pdev, REG_BANK_SEL, &bank, 1);
+}
+
+ICM_20948_Status_e ICM_20948_sw_reset(ICM_20948_Device_t *pdev)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  ICM_20948_PWR_MGMT_1_t reg;
+
+  ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  reg.DEVICE_RESET = 1;
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_sleep(ICM_20948_Device_t *pdev, bool on)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  ICM_20948_PWR_MGMT_1_t reg;
+
+  ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  if (on)
+  {
+    reg.SLEEP = 1;
+  }
+  else
+  {
+    reg.SLEEP = 0;
+  }
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_low_power(ICM_20948_Device_t *pdev, bool on)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  ICM_20948_PWR_MGMT_1_t reg;
+
+  ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  if (on)
+  {
+    reg.LP_EN = 1;
+  }
+  else
+  {
+    reg.LP_EN = 0;
+  }
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_set_clock_source(ICM_20948_Device_t *pdev, ICM_20948_PWR_MGMT_1_CLKSEL_e source)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  ICM_20948_PWR_MGMT_1_t reg;
+
+  ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  reg.CLKSEL = source;
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_PWR_MGMT_1, (uint8_t *)&reg, sizeof(ICM_20948_PWR_MGMT_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_get_who_am_i(ICM_20948_Device_t *pdev, uint8_t *whoami)
+{
+  if (whoami == NULL)
+  {
+    return ICM_20948_Stat_ParamErr;
+  }
+  ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+  return ICM_20948_execute_r(pdev, AGB0_REG_WHO_AM_I, whoami, 1);
+}
+
+ICM_20948_Status_e ICM_20948_check_id(ICM_20948_Device_t *pdev)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  uint8_t whoami = 0x00;
+  retval = ICM_20948_get_who_am_i(pdev, &whoami);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  if (whoami != ICM_20948_WHOAMI)
+  {
+    return ICM_20948_Stat_WrongID;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_data_ready(ICM_20948_Device_t *pdev)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  ICM_20948_INT_STATUS_1_t reg;
+  retval = ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_INT_STATUS_1, (uint8_t *)&reg, sizeof(ICM_20948_INT_STATUS_1_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  if (!reg.RAW_DATA_0_RDY_INT)
+  {
+    retval = ICM_20948_Stat_NoData;
+  }
+  return retval;
+}
+
+// Interrupt Configuration
+ICM_20948_Status_e ICM_20948_int_pin_cfg(ICM_20948_Device_t *pdev, ICM_20948_INT_PIN_CFG_t *write, ICM_20948_INT_PIN_CFG_t *read)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  retval = ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+  if (write != NULL)
+  { // write first, if available
+    retval = ICM_20948_execute_w(pdev, AGB0_REG_INT_PIN_CONFIG, (uint8_t *)write, sizeof(ICM_20948_INT_PIN_CFG_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+  }
+  if (read != NULL)
+  { // then read, to allow for verification
+    retval = ICM_20948_execute_r(pdev, AGB0_REG_INT_PIN_CONFIG, (uint8_t *)read, sizeof(ICM_20948_INT_PIN_CFG_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_int_enable(ICM_20948_Device_t *pdev, ICM_20948_INT_enable_t *write, ICM_20948_INT_enable_t *read)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_INT_ENABLE_t en_0;
+  ICM_20948_INT_ENABLE_1_t en_1;
+  ICM_20948_INT_ENABLE_2_t en_2;
+  ICM_20948_INT_ENABLE_3_t en_3;
+
+  retval = ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+
+  if (write != NULL)
+  { // If the write pointer is not NULL then write to the registers BEFORE reading
+    en_0.I2C_MST_INT_EN = write->I2C_MST_INT_EN;
+    en_0.DMP_INT1_EN = write->DMP_INT1_EN;
+    en_0.PLL_READY_EN = write->PLL_RDY_EN;
+    en_0.WOM_INT_EN = write->WOM_INT_EN;
+    en_0.reserved_0 = 0; // Clear RAM garbage
+    en_0.REG_WOF_EN = write->REG_WOF_EN;
+    en_1.RAW_DATA_0_RDY_EN = write->RAW_DATA_0_RDY_EN;
+    en_1.reserved_0 = 0; // Clear RAM garbage
+    en_2.individual.FIFO_OVERFLOW_EN_4 = write->FIFO_OVERFLOW_EN_4;
+    en_2.individual.FIFO_OVERFLOW_EN_3 = write->FIFO_OVERFLOW_EN_3;
+    en_2.individual.FIFO_OVERFLOW_EN_2 = write->FIFO_OVERFLOW_EN_2;
+    en_2.individual.FIFO_OVERFLOW_EN_1 = write->FIFO_OVERFLOW_EN_1;
+    en_2.individual.FIFO_OVERFLOW_EN_0 = write->FIFO_OVERFLOW_EN_0;
+    en_2.individual.reserved_0 = 0; // Clear RAM garbage
+    en_3.individual.FIFO_WM_EN_4 = write->FIFO_WM_EN_4;
+    en_3.individual.FIFO_WM_EN_3 = write->FIFO_WM_EN_3;
+    en_3.individual.FIFO_WM_EN_2 = write->FIFO_WM_EN_2;
+    en_3.individual.FIFO_WM_EN_1 = write->FIFO_WM_EN_1;
+    en_3.individual.FIFO_WM_EN_0 = write->FIFO_WM_EN_0;
+    en_3.individual.reserved_0 = 0; // Clear RAM garbage
+
+    retval = ICM_20948_execute_w(pdev, AGB0_REG_INT_ENABLE, (uint8_t *)&en_0, sizeof(ICM_20948_INT_ENABLE_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+    retval = ICM_20948_execute_w(pdev, AGB0_REG_INT_ENABLE_1, (uint8_t *)&en_1, sizeof(ICM_20948_INT_ENABLE_1_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+    retval = ICM_20948_execute_w(pdev, AGB0_REG_INT_ENABLE_2, (uint8_t *)&en_2, sizeof(ICM_20948_INT_ENABLE_2_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+    retval = ICM_20948_execute_w(pdev, AGB0_REG_INT_ENABLE_3, (uint8_t *)&en_3, sizeof(ICM_20948_INT_ENABLE_3_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+  }
+
+  if (read != NULL)
+  { // If read pointer is not NULL then read the registers (if write is not NULL then this should read back the results of write into read)
+    retval = ICM_20948_execute_r(pdev, AGB0_REG_INT_ENABLE, (uint8_t *)&en_0, sizeof(ICM_20948_INT_ENABLE_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+    retval = ICM_20948_execute_r(pdev, AGB0_REG_INT_ENABLE_1, (uint8_t *)&en_1, sizeof(ICM_20948_INT_ENABLE_1_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+    retval = ICM_20948_execute_r(pdev, AGB0_REG_INT_ENABLE_2, (uint8_t *)&en_2, sizeof(ICM_20948_INT_ENABLE_2_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+    retval = ICM_20948_execute_r(pdev, AGB0_REG_INT_ENABLE_3, (uint8_t *)&en_3, sizeof(ICM_20948_INT_ENABLE_3_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+
+    read->I2C_MST_INT_EN = en_0.I2C_MST_INT_EN;
+    read->DMP_INT1_EN = en_0.DMP_INT1_EN;
+    read->PLL_RDY_EN = en_0.PLL_READY_EN;
+    read->WOM_INT_EN = en_0.WOM_INT_EN;
+    read->REG_WOF_EN = en_0.REG_WOF_EN;
+    read->RAW_DATA_0_RDY_EN = en_1.RAW_DATA_0_RDY_EN;
+    read->FIFO_OVERFLOW_EN_4 = en_2.individual.FIFO_OVERFLOW_EN_4;
+    read->FIFO_OVERFLOW_EN_3 = en_2.individual.FIFO_OVERFLOW_EN_3;
+    read->FIFO_OVERFLOW_EN_2 = en_2.individual.FIFO_OVERFLOW_EN_2;
+    read->FIFO_OVERFLOW_EN_1 = en_2.individual.FIFO_OVERFLOW_EN_1;
+    read->FIFO_OVERFLOW_EN_0 = en_2.individual.FIFO_OVERFLOW_EN_0;
+    read->FIFO_WM_EN_4 = en_3.individual.FIFO_WM_EN_4;
+    read->FIFO_WM_EN_3 = en_3.individual.FIFO_WM_EN_3;
+    read->FIFO_WM_EN_2 = en_3.individual.FIFO_WM_EN_2;
+    read->FIFO_WM_EN_1 = en_3.individual.FIFO_WM_EN_1;
+    read->FIFO_WM_EN_0 = en_3.individual.FIFO_WM_EN_0;
+  }
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_wom_threshold(ICM_20948_Device_t *pdev, ICM_20948_ACCEL_WOM_THR_t *write, ICM_20948_ACCEL_WOM_THR_t *read)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_ACCEL_WOM_THR_t thr;
+
+  retval = ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+
+  if (write != NULL)
+  { // If the write pointer is not NULL then write to the registers BEFORE reading
+    thr.WOM_THRESHOLD = write->WOM_THRESHOLD;
+
+    retval = ICM_20948_execute_w(pdev, AGB2_REG_ACCEL_WOM_THR, (uint8_t *)&thr, sizeof(ICM_20948_ACCEL_WOM_THR_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+  }
+
+  if (read != NULL)
+  { // If read pointer is not NULL then read the registers (if write is not NULL then this should read back the results of write into read)
+    retval = ICM_20948_execute_r(pdev, AGB2_REG_ACCEL_WOM_THR, (uint8_t *)&thr, sizeof(ICM_20948_ACCEL_WOM_THR_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+
+    read->WOM_THRESHOLD = thr.WOM_THRESHOLD;
+  }
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_set_sample_mode(ICM_20948_Device_t *pdev, ICM_20948_InternalSensorID_bm sensors, ICM_20948_LP_CONFIG_CYCLE_e mode)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  ICM_20948_LP_CONFIG_t reg;
+
+  if (!(sensors & (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr | ICM_20948_Internal_Mst)))
+  {
+    return ICM_20948_Stat_SensorNotSupported;
+  }
+
+  retval = ICM_20948_set_bank(pdev, 0); // Must be in the right bank
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_LP_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_LP_CONFIG_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  if (sensors & ICM_20948_Internal_Acc)
+  {
+    reg.ACCEL_CYCLE = mode;
+  } // Set all desired sensors to this setting
+  if (sensors & ICM_20948_Internal_Gyr)
+  {
+    reg.GYRO_CYCLE = mode;
+  }
+  if (sensors & ICM_20948_Internal_Mst)
+  {
+    reg.I2C_MST_CYCLE = mode;
+  }
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_LP_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_LP_CONFIG_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  // Check the data was written correctly
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_LP_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_LP_CONFIG_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  if (sensors & ICM_20948_Internal_Acc)
+  {
+    if (reg.ACCEL_CYCLE != mode) retval = ICM_20948_Stat_Err;
+  }
+  if (sensors & ICM_20948_Internal_Gyr)
+  {
+    if (reg.GYRO_CYCLE != mode) retval = ICM_20948_Stat_Err;
+  }
+  if (sensors & ICM_20948_Internal_Mst)
+  {
+    if (reg.I2C_MST_CYCLE != mode) retval = ICM_20948_Stat_Err;
+  }
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_set_full_scale(ICM_20948_Device_t *pdev, ICM_20948_InternalSensorID_bm sensors, ICM_20948_fss_t fss)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  if (!(sensors & (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr)))
+  {
+    return ICM_20948_Stat_SensorNotSupported;
+  }
+
+  if (sensors & ICM_20948_Internal_Acc)
+  {
+    ICM_20948_ACCEL_CONFIG_t reg;
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    reg.ACCEL_FS_SEL = fss.a;
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    // Check the data was written correctly
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    if (reg.ACCEL_FS_SEL != fss.a) retval |= ICM_20948_Stat_Err;
+  }
+  if (sensors & ICM_20948_Internal_Gyr)
+  {
+    ICM_20948_GYRO_CONFIG_1_t reg;
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    reg.GYRO_FS_SEL = fss.g;
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    // Check the data was written correctly
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    if (reg.GYRO_FS_SEL != fss.g) retval |= ICM_20948_Stat_Err;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_set_dlpf_cfg(ICM_20948_Device_t *pdev, ICM_20948_InternalSensorID_bm sensors, ICM_20948_dlpcfg_t cfg)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  if (!(sensors & (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr)))
+  {
+    return ICM_20948_Stat_SensorNotSupported;
+  }
+
+  if (sensors & ICM_20948_Internal_Acc)
+  {
+    ICM_20948_ACCEL_CONFIG_t reg;
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    reg.ACCEL_DLPFCFG = cfg.a;
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    // Check the data was written correctly
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    if (reg.ACCEL_DLPFCFG != cfg.a) retval |= ICM_20948_Stat_Err;
+  }
+  if (sensors & ICM_20948_Internal_Gyr)
+  {
+    ICM_20948_GYRO_CONFIG_1_t reg;
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    reg.GYRO_DLPFCFG = cfg.g;
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    // Check the data was written correctly
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    if (reg.GYRO_DLPFCFG != cfg.g) retval |= ICM_20948_Stat_Err;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_enable_dlpf(ICM_20948_Device_t *pdev, ICM_20948_InternalSensorID_bm sensors, bool enable)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  if (!(sensors & (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr)))
+  {
+    return ICM_20948_Stat_SensorNotSupported;
+  }
+
+  if (sensors & ICM_20948_Internal_Acc)
+  {
+    ICM_20948_ACCEL_CONFIG_t reg;
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    if (enable)
+    {
+      reg.ACCEL_FCHOICE = 1;
+    }
+    else
+    {
+      reg.ACCEL_FCHOICE = 0;
+    }
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    // Check the data was written correctly
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_ACCEL_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_ACCEL_CONFIG_t));
+    if (enable)
+    {
+      if (reg.ACCEL_FCHOICE != 1) retval |= ICM_20948_Stat_Err;
+    }
+    else
+    {
+      if (reg.ACCEL_FCHOICE != 0) retval |= ICM_20948_Stat_Err;
+    }
+  }
+  if (sensors & ICM_20948_Internal_Gyr)
+  {
+    ICM_20948_GYRO_CONFIG_1_t reg;
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    if (enable)
+    {
+      reg.GYRO_FCHOICE = 1;
+    }
+    else
+    {
+      reg.GYRO_FCHOICE = 0;
+    }
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    // Check the data was written correctly
+    retval |= ICM_20948_execute_r(pdev, AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&reg, sizeof(ICM_20948_GYRO_CONFIG_1_t));
+    if (enable)
+    {
+      if (reg.GYRO_FCHOICE != 1) retval |= ICM_20948_Stat_Err;
+    }
+    else
+    {
+      if (reg.GYRO_FCHOICE != 0) retval |= ICM_20948_Stat_Err;
+    }
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_set_sample_rate(ICM_20948_Device_t *pdev, ICM_20948_InternalSensorID_bm sensors, ICM_20948_smplrt_t smplrt)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  if (!(sensors & (ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr)))
+  {
+    return ICM_20948_Stat_SensorNotSupported;
+  }
+
+  if (sensors & ICM_20948_Internal_Acc)
+  {
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    uint8_t div1 = (smplrt.a << 8);
+    uint8_t div2 = (smplrt.a & 0xFF);
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_ACCEL_SMPLRT_DIV_1, &div1, 1);
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_ACCEL_SMPLRT_DIV_2, &div2, 1);
+  }
+  if (sensors & ICM_20948_Internal_Gyr)
+  {
+    retval |= ICM_20948_set_bank(pdev, 2); // Must be in the right bank
+    uint8_t div = (smplrt.g);
+    retval |= ICM_20948_execute_w(pdev, AGB2_REG_GYRO_SMPLRT_DIV, &div, 1);
+  }
+  return retval;
+}
+
+// Interface Things
+ICM_20948_Status_e ICM_20948_i2c_master_passthrough(ICM_20948_Device_t *pdev, bool passthrough)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_INT_PIN_CFG_t reg;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_INT_PIN_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_INT_PIN_CFG_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  reg.BYPASS_EN = passthrough;
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_INT_PIN_CONFIG, (uint8_t *)&reg, sizeof(ICM_20948_INT_PIN_CFG_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_i2c_master_enable(ICM_20948_Device_t *pdev, bool enable)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  // Disable BYPASS_EN
+  retval = ICM_20948_i2c_master_passthrough(pdev, false);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  ICM_20948_I2C_MST_CTRL_t ctrl;
+  retval = ICM_20948_set_bank(pdev, 3);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  retval = ICM_20948_execute_r(pdev, AGB3_REG_I2C_MST_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_I2C_MST_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  ctrl.I2C_MST_CLK = 0x07; // corresponds to 345.6 kHz, good for up to 400 kHz
+  ctrl.I2C_MST_P_NSR = 1;
+  retval = ICM_20948_execute_w(pdev, AGB3_REG_I2C_MST_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_I2C_MST_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  ICM_20948_USER_CTRL_t reg;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&reg, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  if (enable)
+  {
+    reg.I2C_MST_EN = 1;
+  }
+  else
+  {
+    reg.I2C_MST_EN = 0;
+  }
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&reg, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_i2c_master_reset(ICM_20948_Device_t *pdev)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_USER_CTRL_t ctrl;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  ctrl.I2C_MST_RST = 1; //Reset!
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_i2c_controller_configure_peripheral(ICM_20948_Device_t *pdev, uint8_t peripheral, uint8_t addr, uint8_t reg, uint8_t len, bool Rw, bool enable, bool data_only, bool grp, bool swap, uint8_t dataOut)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  uint8_t periph_addr_reg;
+  uint8_t periph_reg_reg;
+  uint8_t periph_ctrl_reg;
+  uint8_t periph_do_reg;
+
+  switch (peripheral)
+  {
+  case 0:
+    periph_addr_reg = AGB3_REG_I2C_PERIPH0_ADDR;
+    periph_reg_reg = AGB3_REG_I2C_PERIPH0_REG;
+    periph_ctrl_reg = AGB3_REG_I2C_PERIPH0_CTRL;
+    periph_do_reg = AGB3_REG_I2C_PERIPH0_DO;
+    break;
+  case 1:
+    periph_addr_reg = AGB3_REG_I2C_PERIPH1_ADDR;
+    periph_reg_reg = AGB3_REG_I2C_PERIPH1_REG;
+    periph_ctrl_reg = AGB3_REG_I2C_PERIPH1_CTRL;
+    periph_do_reg = AGB3_REG_I2C_PERIPH1_DO;
+    break;
+  case 2:
+    periph_addr_reg = AGB3_REG_I2C_PERIPH2_ADDR;
+    periph_reg_reg = AGB3_REG_I2C_PERIPH2_REG;
+    periph_ctrl_reg = AGB3_REG_I2C_PERIPH2_CTRL;
+    periph_do_reg = AGB3_REG_I2C_PERIPH2_DO;
+    break;
+  case 3:
+    periph_addr_reg = AGB3_REG_I2C_PERIPH3_ADDR;
+    periph_reg_reg = AGB3_REG_I2C_PERIPH3_REG;
+    periph_ctrl_reg = AGB3_REG_I2C_PERIPH3_CTRL;
+    periph_do_reg = AGB3_REG_I2C_PERIPH3_DO;
+    break;
+  default:
+    return ICM_20948_Stat_ParamErr;
+  }
+
+  retval = ICM_20948_set_bank(pdev, 3);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  // Set the peripheral address and the Rw flag
+  ICM_20948_I2C_PERIPHX_ADDR_t address;
+  address.ID = addr;
+  if (Rw)
+  {
+    address.RNW = 1;
+  }
+  else
+  {
+    address.RNW = 0; // Make sure bit is clear (just in case there is any garbage in that RAM location)
+  }
+  retval = ICM_20948_execute_w(pdev, periph_addr_reg, (uint8_t *)&address, sizeof(ICM_20948_I2C_PERIPHX_ADDR_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  // If we are setting up a write, configure the Data Out register too
+  if (!Rw)
+  {
+    ICM_20948_I2C_PERIPHX_DO_t dataOutByte;
+    dataOutByte.DO = dataOut;
+    retval = ICM_20948_execute_w(pdev, periph_do_reg, (uint8_t *)&dataOutByte, sizeof(ICM_20948_I2C_PERIPHX_DO_t));
+    if (retval != ICM_20948_Stat_Ok)
+    {
+      return retval;
+    }
+  }
+
+  // Set the peripheral sub-address (register address)
+  ICM_20948_I2C_PERIPHX_REG_t subaddress;
+  subaddress.REG = reg;
+  retval = ICM_20948_execute_w(pdev, periph_reg_reg, (uint8_t *)&subaddress, sizeof(ICM_20948_I2C_PERIPHX_REG_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  // Set up the control info
+  ICM_20948_I2C_PERIPHX_CTRL_t ctrl;
+  ctrl.LENG = len;
+  ctrl.EN = enable;
+  ctrl.REG_DIS = data_only;
+  ctrl.GRP = grp;
+  ctrl.BYTE_SW = swap;
+  retval = ICM_20948_execute_w(pdev, periph_ctrl_reg, (uint8_t *)&ctrl, sizeof(ICM_20948_I2C_PERIPHX_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  return retval;
+}
+
+// Higher Level
+ICM_20948_Status_e ICM_20948_get_agmt(ICM_20948_Device_t *pdev, ICM_20948_AGMT_t *pagmt)
+{
+  if (pagmt == NULL)
+  {
+    return ICM_20948_Stat_ParamErr;
+  }
+
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+  const uint8_t numbytes = 14 + 9; //Read Accel, gyro, temp, and 9 bytes of mag
+  uint8_t buff[numbytes];
+
+  // Get readings
+  retval |= ICM_20948_set_bank(pdev, 0);
+  retval |= ICM_20948_execute_r(pdev, (uint8_t)AGB0_REG_ACCEL_XOUT_H, buff, numbytes);
+
+  pagmt->acc.axes.x = ((buff[0] << 8) | (buff[1] & 0xFF));
+  pagmt->acc.axes.y = ((buff[2] << 8) | (buff[3] & 0xFF));
+  pagmt->acc.axes.z = ((buff[4] << 8) | (buff[5] & 0xFF));
+
+  pagmt->gyr.axes.x = ((buff[6] << 8) | (buff[7] & 0xFF));
+  pagmt->gyr.axes.y = ((buff[8] << 8) | (buff[9] & 0xFF));
+  pagmt->gyr.axes.z = ((buff[10] << 8) | (buff[11] & 0xFF));
+
+  pagmt->tmp.val = ((buff[12] << 8) | (buff[13] & 0xFF));
+
+  pagmt->magStat1 = buff[14];
+  pagmt->mag.axes.x = ((buff[16] << 8) | (buff[15] & 0xFF)); //Mag data is read little endian
+  pagmt->mag.axes.y = ((buff[18] << 8) | (buff[17] & 0xFF));
+  pagmt->mag.axes.z = ((buff[20] << 8) | (buff[19] & 0xFF));
+  pagmt->magStat2 = buff[22];
+
+  // Get settings to be able to compute scaled values
+  retval |= ICM_20948_set_bank(pdev, 2);
+  ICM_20948_ACCEL_CONFIG_t acfg;
+  retval |= ICM_20948_execute_r(pdev, (uint8_t)AGB2_REG_ACCEL_CONFIG, (uint8_t *)&acfg, 1 * sizeof(acfg));
+  pagmt->fss.a = acfg.ACCEL_FS_SEL; // Worth noting that without explicitly setting the FS range of the accelerometer it was showing the register value for +/- 2g but the reported values were actually scaled to the +/- 16g range
+                                    // Wait a minute... now it seems like this problem actually comes from the digital low-pass filter. When enabled the value is 1/8 what it should be...
+  retval |= ICM_20948_set_bank(pdev, 2);
+  ICM_20948_GYRO_CONFIG_1_t gcfg1;
+  retval |= ICM_20948_execute_r(pdev, (uint8_t)AGB2_REG_GYRO_CONFIG_1, (uint8_t *)&gcfg1, 1 * sizeof(gcfg1));
+  pagmt->fss.g = gcfg1.GYRO_FS_SEL;
+  ICM_20948_ACCEL_CONFIG_2_t acfg2;
+  retval |= ICM_20948_execute_r(pdev, (uint8_t)AGB2_REG_ACCEL_CONFIG_2, (uint8_t *)&acfg2, 1 * sizeof(acfg2));
+
+  return retval;
+}
+
+// FIFO
+
+ICM_20948_Status_e ICM_20948_enable_FIFO(ICM_20948_Device_t *pdev, bool enable)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_USER_CTRL_t ctrl;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  if (enable)
+    ctrl.FIFO_EN = 1;
+  else
+    ctrl.FIFO_EN = 0;
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_reset_FIFO(ICM_20948_Device_t *pdev)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_FIFO_RST_t ctrl;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_FIFO_RST, (uint8_t *)&ctrl, sizeof(ICM_20948_FIFO_RST_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  ctrl.FIFO_RESET = 0x1F; // Datasheet says "FIFO_RESET[4:0]"
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_FIFO_RST, (uint8_t *)&ctrl, sizeof(ICM_20948_FIFO_RST_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  //delay ???
+
+  ctrl.FIFO_RESET = 0x1E; // The InvenSense Nucleo examples write 0x1F followed by 0x1E
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_FIFO_RST, (uint8_t *)&ctrl, sizeof(ICM_20948_FIFO_RST_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_set_FIFO_mode(ICM_20948_Device_t *pdev, bool snapshot)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_FIFO_MODE_t ctrl;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_FIFO_MODE, (uint8_t *)&ctrl, sizeof(ICM_20948_FIFO_MODE_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  if (snapshot)
+    ctrl.FIFO_MODE = 0x1F; // Datasheet says "FIFO_MODE[4:0]"
+  else
+    ctrl.FIFO_MODE = 0;
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_FIFO_MODE, (uint8_t *)&ctrl, sizeof(ICM_20948_FIFO_MODE_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_get_FIFO_count(ICM_20948_Device_t *pdev, uint16_t *count)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_FIFO_COUNTH_t ctrlh;
+  ICM_20948_FIFO_COUNTL_t ctrll;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_FIFO_COUNT_H, (uint8_t *)&ctrlh, sizeof(ICM_20948_FIFO_COUNTH_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  ctrlh.FIFO_COUNTH &= 0x1F; // Datasheet says "FIFO_CNT[12:8]"
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_FIFO_COUNT_L, (uint8_t *)&ctrll, sizeof(ICM_20948_FIFO_COUNTL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  *count = (((uint16_t)ctrlh.FIFO_COUNTH) << 8) | (uint16_t)ctrll.FIFO_COUNTL;
+
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_read_FIFO(ICM_20948_Device_t *pdev, uint8_t *data, uint8_t len)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_FIFO_R_W, data, len);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  return retval;
+}
+
+// DMP
+
+ICM_20948_Status_e ICM_20948_enable_DMP(ICM_20948_Device_t *pdev, bool enable)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_USER_CTRL_t ctrl;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  if (enable)
+    ctrl.DMP_EN = 1;
+  else
+    ctrl.DMP_EN = 0;
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_reset_DMP(ICM_20948_Device_t *pdev)
+{
+  ICM_20948_Status_e retval = ICM_20948_Stat_Ok;
+
+  ICM_20948_USER_CTRL_t ctrl;
+  retval = ICM_20948_set_bank(pdev, 0);
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  retval = ICM_20948_execute_r(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+
+  ctrl.DMP_RST = 1;
+
+  retval = ICM_20948_execute_w(pdev, AGB0_REG_USER_CTRL, (uint8_t *)&ctrl, sizeof(ICM_20948_USER_CTRL_t));
+  if (retval != ICM_20948_Stat_Ok)
+  {
+    return retval;
+  }
+  return retval;
+}
+
+ICM_20948_Status_e ICM_20948_firmware_load(ICM_20948_Device_t *pdev)
+{
+#if defined(ICM_20948_USE_DMP)
+  return (inv_icm20948_firmware_load(pdev, dmp3_image, sizeof(dmp3_image), DMP_LOAD_START));
+#else
+  return ICM_20948_Stat_DMPNotSupported;
+#endif
+}
+
+/** @brief Loads the DMP firmware from SRAM
+* @param[in] data  pointer where the image
+* @param[in] size  size if the image
+* @param[in] load_addr  address to loading the image
+* @return 0 in case of success, -1 for any error
+*/
+ICM_20948_Status_e inv_icm20948_firmware_load(ICM_20948_Device_t *pdev, const unsigned char *data_start, unsigned short size_start, unsigned short load_addr)
+{
+  int write_size;
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+  unsigned short memaddr;
+  const unsigned char *data;
+  unsigned short size;
+  unsigned char data_cmp[INV_MAX_SERIAL_READ];
+  int flag = 0;
+
+  if (pdev->_dmp_firmware_available == false)
+    return ICM_20948_Stat_DMPNotSupported;
+
+  if (pdev->_firmware_loaded)
+    return ICM_20948_Stat_Ok; // Bail with no error if firmware is already loaded
+
+  result = ICM_20948_sleep(pdev, false); // Make sure chip is awake
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  result = ICM_20948_low_power(pdev, false); // Make sure chip is not in low power state
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  // Write DMP memory
+
+  data = data_start;
+  size = size_start;
+  memaddr = load_addr;
+  #ifdef ICM_20948_USE_PROGMEM_FOR_DMP
+  unsigned char data_not_pg[INV_MAX_SERIAL_READ]; // Suggested by @HyperKokichi in Issue #63
+  #endif
+  while (size > 0)
+  {
+    //write_size = min(size, INV_MAX_SERIAL_WRITE); // Write in chunks of INV_MAX_SERIAL_WRITE
+    if (size <= INV_MAX_SERIAL_WRITE) // Write in chunks of INV_MAX_SERIAL_WRITE
+      write_size = size;
+    else
+      write_size = INV_MAX_SERIAL_WRITE;
+    if ((memaddr & 0xff) + write_size > 0x100)
+    {
+      // Moved across a bank
+      write_size = (memaddr & 0xff) + write_size - 0x100;
+    }
+#ifdef ICM_20948_USE_PROGMEM_FOR_DMP
+    memcpy_P(data_not_pg, data, write_size);  // Suggested by @HyperKokichi in Issue #63
+    result = inv_icm20948_write_mems(pdev, memaddr, write_size, (unsigned char *)data_not_pg);
+#else
+    result = inv_icm20948_write_mems(pdev, memaddr, write_size, (unsigned char *)data);
+#endif
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    data += write_size;
+    size -= write_size;
+    memaddr += write_size;
+  }
+
+  // Verify DMP memory
+
+  data = data_start;
+  size = size_start;
+  memaddr = load_addr;
+  while (size > 0)
+  {
+    //write_size = min(size, INV_MAX_SERIAL_READ); // Read in chunks of INV_MAX_SERIAL_READ
+    if (size <= INV_MAX_SERIAL_READ) // Read in chunks of INV_MAX_SERIAL_READ
+      write_size = size;
+    else
+      write_size = INV_MAX_SERIAL_READ;
+    if ((memaddr & 0xff) + write_size > 0x100)
+    {
+      // Moved across a bank
+      write_size = (memaddr & 0xff) + write_size - 0x100;
+    }
+    result = inv_icm20948_read_mems(pdev, memaddr, write_size, data_cmp);
+    if (result != ICM_20948_Stat_Ok)
+      flag++;                               // Error, DMP not written correctly
+#ifdef ICM_20948_USE_PROGMEM_FOR_DMP
+    memcpy_P(data_not_pg, data, write_size);  // Suggested by @HyperKokichi in Issue #63
+    if (memcmp(data_cmp, data_not_pg, write_size))
+#else
+    if (memcmp(data_cmp, data, write_size)) // Compare the data
+#endif
+      return ICM_20948_Stat_DMPVerifyFail;
+    data += write_size;
+    size -= write_size;
+    memaddr += write_size;
+  }
+
+  //Enable LP_EN since we disabled it at begining of this function.
+  result = ICM_20948_low_power(pdev, true); // Put chip into low power state
+  if (result != ICM_20948_Stat_Ok)
+    return result;
+
+  if (!flag)
+  {
+    //Serial.println("DMP Firmware was updated successfully..");
+    pdev->_firmware_loaded = true;
+  }
+
+  return result;
+}
+
+ICM_20948_Status_e ICM_20948_set_dmp_start_address(ICM_20948_Device_t *pdev, unsigned short address)
+{
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+
+  if (pdev->_dmp_firmware_available == false)
+    return ICM_20948_Stat_DMPNotSupported;
+
+  unsigned char start_address[2];
+
+  start_address[0] = (unsigned char)(address >> 8);
+  start_address[1] = (unsigned char)(address & 0xff);
+
+  // result = ICM_20948_sleep(pdev, false); // Make sure chip is awake
+  // if (result != ICM_20948_Stat_Ok)
+  // {
+  // 		return result;
+  // }
+  //
+  // result = ICM_20948_low_power(pdev, false); // Make sure chip is not in low power state
+  // if (result != ICM_20948_Stat_Ok)
+  // {
+  // 		return result;
+  // }
+
+  result = ICM_20948_set_bank(pdev, 2); // Set bank 2
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  // Write the sensor control bits into memory address AGB2_REG_PRGM_START_ADDRH
+  result = ICM_20948_execute_w(pdev, AGB2_REG_PRGM_START_ADDRH, (uint8_t *)start_address, 2);
+
+  return result;
+}
+
+/**
+*  @brief       Write data to a register in DMP memory
+*  @param[in]   DMP memory address
+*  @param[in]   number of byte to be written
+*  @param[out]  output data from the register
+*  @return     0 if successful.
+*/
+ICM_20948_Status_e inv_icm20948_write_mems(ICM_20948_Device_t *pdev, unsigned short reg, unsigned int length, const unsigned char *data)
+{
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+  unsigned int bytesWritten = 0;
+  unsigned int thisLen;
+  unsigned char lBankSelected;
+  unsigned char lStartAddrSelected;
+
+  if (!data)
+  {
+    return ICM_20948_Stat_NoData;
+  }
+
+  result = ICM_20948_set_bank(pdev, 0); // Set bank 0
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  lBankSelected = (reg >> 8);
+
+  if (lBankSelected != pdev->_last_mems_bank)
+  {
+    pdev->_last_mems_bank = lBankSelected;
+    result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_BANK_SEL, &lBankSelected, 1);
+    if (result != ICM_20948_Stat_Ok)
+    {
+      return result;
+    }
+  }
+
+  while (bytesWritten < length)
+  {
+    lStartAddrSelected = (reg & 0xff);
+
+    /* Sets the starting read or write address for the selected memory, inside of the selected page (see MEM_SEL Register).
+           Contents are changed after read or write of the selected memory.
+           This register must be written prior to each access to initialize the register to the proper starting address.
+           The address will auto increment during burst transactions.  Two consecutive bursts without re-initializing the start address would skip one address. */
+
+    result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_START_ADDR, &lStartAddrSelected, 1);
+    if (result != ICM_20948_Stat_Ok)
+    {
+      return result;
+    }
+
+    if (length - bytesWritten <= INV_MAX_SERIAL_WRITE)
+      thisLen = length - bytesWritten;
+    else
+      thisLen = INV_MAX_SERIAL_WRITE;
+
+    /* Write data */
+
+    result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_R_W, (uint8_t *)&data[bytesWritten], thisLen);
+    if (result != ICM_20948_Stat_Ok)
+    {
+      return result;
+    }
+
+    bytesWritten += thisLen;
+    reg += thisLen;
+  }
+
+  return result;
+}
+
+/**
+*  @brief      Read data from a register in DMP memory
+*  @param[in]  DMP memory address
+*  @param[in]  number of byte to be read
+*  @param[in]  input data from the register
+*  @return     0 if successful.
+*/
+ICM_20948_Status_e inv_icm20948_read_mems(ICM_20948_Device_t *pdev, unsigned short reg, unsigned int length, unsigned char *data)
+{
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+  unsigned int bytesRead = 0;
+  unsigned int thisLen;
+  unsigned char lBankSelected;
+  unsigned char lStartAddrSelected;
+
+  if (!data)
+  {
+    return ICM_20948_Stat_NoData;
+  }
+
+  result = ICM_20948_set_bank(pdev, 0); // Set bank 0
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  lBankSelected = (reg >> 8);
+
+  if (lBankSelected != pdev->_last_mems_bank)
+  {
+    pdev->_last_mems_bank = lBankSelected;
+    result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_BANK_SEL, &lBankSelected, 1);
+    if (result != ICM_20948_Stat_Ok)
+    {
+      return result;
+    }
+  }
+
+  while (bytesRead < length)
+  {
+    lStartAddrSelected = (reg & 0xff);
+
+    /* Sets the starting read or write address for the selected memory, inside of the selected page (see MEM_SEL Register).
+		   Contents are changed after read or write of the selected memory.
+		   This register must be written prior to each access to initialize the register to the proper starting address.
+		   The address will auto increment during burst transactions.  Two consecutive bursts without re-initializing the start address would skip one address. */
+
+    result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_START_ADDR, &lStartAddrSelected, 1);
+    if (result != ICM_20948_Stat_Ok)
+    {
+      return result;
+    }
+
+    if (length - bytesRead <= INV_MAX_SERIAL_READ)
+      thisLen = length - bytesRead;
+    else
+      thisLen = INV_MAX_SERIAL_READ;
+
+    /* Read data */
+
+    result = ICM_20948_execute_r(pdev, AGB0_REG_MEM_R_W, &data[bytesRead], thisLen);
+    if (result != ICM_20948_Stat_Ok)
+    {
+      return result;
+    }
+
+    bytesRead += thisLen;
+    reg += thisLen;
+  }
+
+  return result;
+}
+
+ICM_20948_Status_e inv_icm20948_set_dmp_sensor_period(ICM_20948_Device_t *pdev, enum DMP_ODR_Registers odr_reg, uint16_t interval)
+{
+  // Set the ODR registers and clear the ODR counter
+
+  // In order to set an ODR for a given sensor data, write 2-byte value to DMP using key defined above for a particular sensor.
+  // Setting value can be calculated as follows:
+  // Value = (DMP running rate (225Hz) / ODR ) - 1
+  // E.g. For a 25Hz ODR rate, value= (225/25) -1 = 8.
+
+  // During run-time, if an ODR is changed, the corresponding rate counter must be reset.
+  // To reset, write 2-byte {0,0} to DMP using keys below for a particular sensor:
+
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+  ICM_20948_Status_e result2 = ICM_20948_Stat_Ok;
+
+  if (pdev->_dmp_firmware_available == false)
+    return ICM_20948_Stat_DMPNotSupported;
+
+  unsigned char odr_reg_val[2];
+  odr_reg_val[0] = (unsigned char)(interval >> 8);
+  odr_reg_val[1] = (unsigned char)(interval & 0xff);
+
+  unsigned char odr_count_zero[2] = {0x00, 0x00};
+
+  result = ICM_20948_sleep(pdev, false); // Make sure chip is awake
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  result = ICM_20948_low_power(pdev, false); // Make sure chip is not in low power state
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  switch (odr_reg)
+  {
+  case DMP_ODR_Reg_Cpass_Calibr:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_CPASS_CALIBR, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_CPASS_CALIBR, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Gyro_Calibr:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_GYRO_CALIBR, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_GYRO_CALIBR, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Pressure:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_PRESSURE, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_PRESSURE, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Geomag:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_GEOMAG, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_GEOMAG, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_PQuat6:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_PQUAT6, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_PQUAT6, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Quat9:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_QUAT9, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_QUAT9, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Quat6:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_QUAT6, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_QUAT6, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_ALS:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_ALS, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_ALS, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Cpass:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_CPASS, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_CPASS, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Gyro:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_GYRO, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_GYRO, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  case DMP_ODR_Reg_Accel:
+  {
+    result = inv_icm20948_write_mems(pdev, ODR_ACCEL, 2, (const unsigned char *)&odr_reg_val);
+    result2 = inv_icm20948_write_mems(pdev, ODR_CNTR_ACCEL, 2, (const unsigned char *)&odr_count_zero);
+  }
+  break;
+  default:
+    result = ICM_20948_Stat_InvalDMPRegister;
+    break;
+  }
+
+  result = ICM_20948_low_power(pdev, true); // Put chip into low power state
+  if (result != ICM_20948_Stat_Ok)
+    return result;
+
+  if (result2 > result)
+    result = result2; // Return the highest error
+
+  return result;
+}
+
+ICM_20948_Status_e inv_icm20948_enable_dmp_sensor(ICM_20948_Device_t *pdev, enum inv_icm20948_sensor sensor, int state)
+{
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+
+  uint16_t inv_event_control = 0; // Use this to store the value for MOTION_EVENT_CTL
+  uint16_t data_rdy_status = 0;   // Use this to store the value for DATA_RDY_STATUS
+
+  if (pdev->_dmp_firmware_available == false)
+    return ICM_20948_Stat_DMPNotSupported; // Bail if DMP is not supported
+
+  uint8_t androidSensor = sensor_type_2_android_sensor(sensor); // Convert sensor from enum inv_icm20948_sensor to Android numbering
+
+  if (androidSensor >= ANDROID_SENSOR_NUM_MAX)
+    return ICM_20948_Stat_SensorNotSupported; // Bail if the sensor is not supported (TO DO: Support B2S etc)
+
+  // Convert the Android sensor into a bit mask for DATA_OUT_CTL1
+  uint16_t delta = inv_androidSensor_to_control_bits[androidSensor];
+  if (delta == 0xFFFF)
+    return ICM_20948_Stat_SensorNotSupported; // Bail if the sensor is not supported
+
+  // Convert the Android sensor number into a bitmask and set or clear that bit in _enabled_Android_0 / _enabled_Android_1
+  unsigned long androidSensorAsBitMask;
+  if (androidSensor < 32) // Sensors 0-31
+  {
+    androidSensorAsBitMask = 1L << androidSensor;
+    if (state == 0) // Should we disable the sensor?
+    {
+      pdev->_enabled_Android_0 &= ~androidSensorAsBitMask; // Clear the bit to disable the sensor
+    }
+    else
+    {
+      pdev->_enabled_Android_0 |= androidSensorAsBitMask; // Set the bit to enable the sensor
+    }
+  }
+  else // Sensors 32-
+  {
+    androidSensorAsBitMask = 1L << (androidSensor - 32);
+    if (state == 0) // Should we disable the sensor?
+    {
+      pdev->_enabled_Android_1 &= ~androidSensorAsBitMask; // Clear the bit to disable the sensor
+    }
+    else
+    {
+      pdev->_enabled_Android_1 |= androidSensorAsBitMask; // Set the bit to enable the sensor
+    }
+  }
+
+  // Now we know androidSensor is valid, reconstruct the value for DATA_OUT_CTL1 from _enabled_Android_0 and _enabled_Android_0
+  delta = 0; // Clear delta
+  for (int i = 0; i < 32; i++)
+  {
+    androidSensorAsBitMask = 1L << i;
+    if ((pdev->_enabled_Android_0 & androidSensorAsBitMask) > 0) // Check if the Android sensor (0-31) is enabled
+    {
+      delta |= inv_androidSensor_to_control_bits[i]; // If it is, or the required bits into delta
+    }
+    if ((pdev->_enabled_Android_1 & androidSensorAsBitMask) > 0) // Check if the Android sensor (32-) is enabled
+    {
+      delta |= inv_androidSensor_to_control_bits[i + 32]; // If it is, or the required bits into delta
+    }
+    // Also check which bits need to be set in the Data Ready Status and Motion Event Control registers
+    // Compare to INV_NEEDS_ACCEL_MASK, INV_NEEDS_GYRO_MASK and INV_NEEDS_COMPASS_MASK
+    if (((androidSensorAsBitMask & INV_NEEDS_ACCEL_MASK) > 0) || ((androidSensorAsBitMask & INV_NEEDS_ACCEL_MASK1) > 0))
+    {
+      data_rdy_status |= DMP_Data_ready_Accel;
+      inv_event_control |= DMP_Motion_Event_Control_Accel_Calibr;
+    }
+    if (((androidSensorAsBitMask & INV_NEEDS_GYRO_MASK) > 0) || ((androidSensorAsBitMask & INV_NEEDS_GYRO_MASK1) > 0))
+    {
+      data_rdy_status |= DMP_Data_ready_Gyro;
+      inv_event_control |= DMP_Motion_Event_Control_Gyro_Calibr;
+    }
+    if (((androidSensorAsBitMask & INV_NEEDS_COMPASS_MASK) > 0) || ((androidSensorAsBitMask & INV_NEEDS_COMPASS_MASK1) > 0))
+    {
+      data_rdy_status |= DMP_Data_ready_Secondary_Compass;
+      inv_event_control |= DMP_Motion_Event_Control_Compass_Calibr;
+    }
+  }
+
+  result = ICM_20948_sleep(pdev, false); // Make sure chip is awake
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  result = ICM_20948_low_power(pdev, false); // Make sure chip is not in low power state
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  // Check if Accel, Gyro/Gyro_Calibr or Compass_Calibr/Quat9/GeoMag/Compass are to be enabled. If they are then we need to request the accuracy data via header2.
+  uint16_t delta2 = 0;
+  if ((delta & DMP_Data_Output_Control_1_Accel) > 0)
+  {
+    delta2 |= DMP_Data_Output_Control_2_Accel_Accuracy;
+  }
+  if (((delta & DMP_Data_Output_Control_1_Gyro_Calibr) > 0) || ((delta & DMP_Data_Output_Control_1_Gyro) > 0))
+  {
+    delta2 |= DMP_Data_Output_Control_2_Gyro_Accuracy;
+  }
+  if (((delta & DMP_Data_Output_Control_1_Compass_Calibr) > 0) || ((delta & DMP_Data_Output_Control_1_Compass) > 0) || ((delta & DMP_Data_Output_Control_1_Quat9) > 0) || ((delta & DMP_Data_Output_Control_1_Geomag) > 0))
+  {
+    delta2 |= DMP_Data_Output_Control_2_Compass_Accuracy;
+  }
+  // TO DO: Add DMP_Data_Output_Control_2_Pickup etc. if required
+
+  // Write the sensor control bits into memory address DATA_OUT_CTL1
+  unsigned char data_output_control_reg[2];
+  data_output_control_reg[0] = (unsigned char)(delta >> 8);
+  data_output_control_reg[1] = (unsigned char)(delta & 0xff);
+  pdev->_dataOutCtl1 = delta; // Diagnostics
+  result = inv_icm20948_write_mems(pdev, DATA_OUT_CTL1, 2, (const unsigned char *)&data_output_control_reg);
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  // Write the 'header2' sensor control bits into memory address DATA_OUT_CTL2
+  data_output_control_reg[0] = (unsigned char)(delta2 >> 8);
+  data_output_control_reg[1] = (unsigned char)(delta2 & 0xff);
+  pdev->_dataOutCtl2 = delta2; // Diagnostics
+  result = inv_icm20948_write_mems(pdev, DATA_OUT_CTL2, 2, (const unsigned char *)&data_output_control_reg);
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  // Set the DATA_RDY_STATUS register
+  data_output_control_reg[0] = (unsigned char)(data_rdy_status >> 8);
+  data_output_control_reg[1] = (unsigned char)(data_rdy_status & 0xff);
+  pdev->_dataRdyStatus = data_rdy_status; // Diagnostics
+  result = inv_icm20948_write_mems(pdev, DATA_RDY_STATUS, 2, (const unsigned char *)&data_output_control_reg);
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  // Check which extra bits need to be set in the Motion Event Control register
+  if ((delta & DMP_Data_Output_Control_1_Quat9) > 0)
+  {
+    inv_event_control |= DMP_Motion_Event_Control_9axis;
+  }
+  if (((delta & DMP_Data_Output_Control_1_Step_Detector) > 0) || ((delta & DMP_Data_Output_Control_1_Step_Ind_0) > 0) || ((delta & DMP_Data_Output_Control_1_Step_Ind_1) > 0) || ((delta & DMP_Data_Output_Control_1_Step_Ind_2) > 0))
+  {
+    inv_event_control |= DMP_Motion_Event_Control_Pedometer_Interrupt;
+  }
+  if ((delta & DMP_Data_Output_Control_1_Geomag) > 0)
+  {
+    inv_event_control |= DMP_Motion_Event_Control_Geomag;
+  }
+
+  // Set the MOTION_EVENT_CTL register
+  data_output_control_reg[0] = (unsigned char)(inv_event_control >> 8);
+  data_output_control_reg[1] = (unsigned char)(inv_event_control & 0xff);
+  pdev->_motionEventCtl = inv_event_control; // Diagnostics
+  result = inv_icm20948_write_mems(pdev, MOTION_EVENT_CTL, 2, (const unsigned char *)&data_output_control_reg);
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  result = ICM_20948_low_power(pdev, true); // Put chip into low power state
+  if (result != ICM_20948_Stat_Ok)
+    return result;
+
+  return result;
+}
+
+ICM_20948_Status_e inv_icm20948_enable_dmp_sensor_int(ICM_20948_Device_t *pdev, enum inv_icm20948_sensor sensor, int state)
+{
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+
+  if (pdev->_dmp_firmware_available == false)
+    return ICM_20948_Stat_DMPNotSupported; // Bail if DMP is not supported
+
+  uint8_t androidSensor = sensor_type_2_android_sensor(sensor); // Convert sensor from enum inv_icm20948_sensor to Android numbering
+
+  if (androidSensor > ANDROID_SENSOR_NUM_MAX)
+    return ICM_20948_Stat_SensorNotSupported; // Bail if the sensor is not supported
+
+  // Convert the Android sensor into a bit mask for DATA_OUT_CTL1
+  uint16_t delta = inv_androidSensor_to_control_bits[androidSensor];
+  if (delta == 0xFFFF)
+    return ICM_20948_Stat_SensorNotSupported; // Bail if the sensor is not supported
+
+  // Convert the Android sensor number into a bitmask and set or clear that bit in _enabled_Android_intr_0 / _enabled_Android_intr_1
+  unsigned long androidSensorAsBitMask;
+  if (androidSensor < 32) // Sensors 0-31
+  {
+    androidSensorAsBitMask = 1L << androidSensor;
+    if (state == 0) // Should we disable the sensor interrupt?
+    {
+      pdev->_enabled_Android_intr_0 &= ~androidSensorAsBitMask; // Clear the bit to disable the sensor interrupt
+    }
+    else
+    {
+      pdev->_enabled_Android_intr_0 |= androidSensorAsBitMask; // Set the bit to enable the sensor interrupt
+    }
+  }
+  else // Sensors 32-
+  {
+    androidSensorAsBitMask = 1L << (androidSensor - 32);
+    if (state == 0) // Should we disable the sensor?
+    {
+      pdev->_enabled_Android_intr_1 &= ~androidSensorAsBitMask; // Clear the bit to disable the sensor interrupt
+    }
+    else
+    {
+      pdev->_enabled_Android_intr_1 |= androidSensorAsBitMask; // Set the bit to enable the sensor interrupt
+    }
+  }
+
+  // Now we know androidSensor is valid, reconstruct the value for DATA_INTR_CTL from _enabled_Android_intr_0 and _enabled_Android_intr_0
+  delta = 0; // Clear delta
+  for (int i = 0; i < 32; i++)
+  {
+    androidSensorAsBitMask = 1L << i;
+    if ((pdev->_enabled_Android_intr_0 & androidSensorAsBitMask) > 0) // Check if the Android sensor (0-31) interrupt is enabled
+    {
+      delta |= inv_androidSensor_to_control_bits[i]; // If it is, or the required bits into delta
+    }
+    if ((pdev->_enabled_Android_intr_1 & androidSensorAsBitMask) > 0) // Check if the Android sensor (32-) interrupt is enabled
+    {
+      delta |= inv_androidSensor_to_control_bits[i + 32]; // If it is, or the required bits into delta
+    }
+  }
+
+  result = ICM_20948_sleep(pdev, false); // Make sure chip is awake
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  result = ICM_20948_low_power(pdev, false); // Make sure chip is not in low power state
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  unsigned char data_intr_ctl[2];
+
+  data_intr_ctl[0] = (unsigned char)(delta >> 8);
+  data_intr_ctl[1] = (unsigned char)(delta & 0xff);
+  pdev->_dataIntrCtl = delta; // Diagnostics
+  
+  // Write the interrupt control bits into memory address DATA_INTR_CTL
+  result = inv_icm20948_write_mems(pdev, DATA_INTR_CTL, 2, (const unsigned char *)&data_intr_ctl);
+
+  result = ICM_20948_low_power(pdev, true); // Put chip into low power state
+  if (result != ICM_20948_Stat_Ok)
+    return result;
+
+  return result;
+}
+
+ICM_20948_Status_e inv_icm20948_read_dmp_data(ICM_20948_Device_t *pdev, icm_20948_DMP_data_t *data)
+{
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+  uint8_t fifoBytes[icm_20948_DMP_Maximum_Bytes]; // Interim storage for the FIFO data
+
+  if (pdev->_dmp_firmware_available == false)
+    return ICM_20948_Stat_DMPNotSupported;
+
+  // Check how much data is in the FIFO
+  uint16_t fifo_count;
+  result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+  if (result != ICM_20948_Stat_Ok)
+    return result;
+
+  if (fifo_count < icm_20948_DMP_Header_Bytes) // Has a 2-byte header arrived?
+    return ICM_20948_Stat_FIFONoDataAvail;     // Bail if no header is available
+
+  // Read the header (2 bytes)
+  data->header = 0; // Clear the existing header
+  uint16_t aShort = 0;
+  result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Header_Bytes);
+  if (result != ICM_20948_Stat_Ok)
+    return result;
+  for (int i = 0; i < icm_20948_DMP_Header_Bytes; i++)
+  {
+    aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+  }
+  data->header = aShort;                    // Store the header in data->header
+  fifo_count -= icm_20948_DMP_Header_Bytes; // Decrement the count
+
+  // If the header indicates a header2 is present then read that now
+  data->header2 = 0;                                  // Clear the existing header2
+  if ((data->header & DMP_header_bitmap_Header2) > 0) // If the header2 bit is set
+  {
+    if (fifo_count < icm_20948_DMP_Header2_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Header2_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if no header2 is available
+    // Read the header (2 bytes)
+    aShort = 0;
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Header2_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Header2_Bytes; i++)
+    {
+      aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+    }
+    data->header2 = aShort;                    // Store the header2 in data->header2
+    fifo_count -= icm_20948_DMP_Header2_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Accel) > 0) // case DMP_header_bitmap_Accel:
+  {
+    if (fifo_count < icm_20948_DMP_Raw_Accel_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Raw_Accel_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Raw_Accel_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Raw_Accel_Bytes; i++)
+    {
+      data->Raw_Accel.Bytes[DMP_PQuat6_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= icm_20948_DMP_Raw_Accel_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Gyro) > 0) // case DMP_header_bitmap_Gyro:
+  {
+    if (fifo_count < (icm_20948_DMP_Raw_Gyro_Bytes + icm_20948_DMP_Gyro_Bias_Bytes)) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < (icm_20948_DMP_Raw_Gyro_Bytes + icm_20948_DMP_Gyro_Bias_Bytes))
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], (icm_20948_DMP_Raw_Gyro_Bytes + icm_20948_DMP_Gyro_Bias_Bytes));
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < (icm_20948_DMP_Raw_Gyro_Bytes + icm_20948_DMP_Gyro_Bias_Bytes); i++)
+    {
+      data->Raw_Gyro.Bytes[DMP_Raw_Gyro_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= (icm_20948_DMP_Raw_Gyro_Bytes + icm_20948_DMP_Gyro_Bias_Bytes); // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Compass) > 0) // case DMP_header_bitmap_Compass:
+  {
+    if (fifo_count < icm_20948_DMP_Compass_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Compass_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Compass_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Compass_Bytes; i++)
+    {
+      data->Compass.Bytes[DMP_PQuat6_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= icm_20948_DMP_Compass_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_ALS) > 0) // case DMP_header_bitmap_ALS:
+  {
+    if (fifo_count < icm_20948_DMP_ALS_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_ALS_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_ALS_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_ALS_Bytes; i++)
+    {
+      data->ALS[i] = fifoBytes[i];
+    }
+    fifo_count -= icm_20948_DMP_ALS_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Quat6) > 0) // case DMP_header_bitmap_Quat6:
+  {
+    if (fifo_count < icm_20948_DMP_Quat6_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Quat6_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Quat6_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Quat6_Bytes; i++)
+    {
+      data->Quat6.Bytes[DMP_Quat6_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= icm_20948_DMP_Quat6_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Quat9) > 0) // case DMP_header_bitmap_Quat9:
+  {
+    if (fifo_count < icm_20948_DMP_Quat9_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Quat9_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Quat9_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Quat9_Bytes; i++)
+    {
+      data->Quat9.Bytes[DMP_Quat9_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= icm_20948_DMP_Quat9_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_PQuat6) > 0) // case DMP_header_bitmap_PQuat6:
+  {
+    if (fifo_count < icm_20948_DMP_PQuat6_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_PQuat6_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_PQuat6_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_PQuat6_Bytes; i++)
+    {
+      data->PQuat6.Bytes[DMP_PQuat6_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= icm_20948_DMP_PQuat6_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Geomag) > 0) // case DMP_header_bitmap_Geomag:
+  {
+    if (fifo_count < icm_20948_DMP_Geomag_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Geomag_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Geomag_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Geomag_Bytes; i++)
+    {
+      data->Geomag.Bytes[DMP_Quat9_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= icm_20948_DMP_Geomag_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Pressure) > 0) // case DMP_header_bitmap_Pressure:
+  {
+    if (fifo_count < icm_20948_DMP_Pressure_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Pressure_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Pressure_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Pressure_Bytes; i++)
+    {
+      data->Pressure[i] = fifoBytes[i];
+    }
+    fifo_count -= icm_20948_DMP_Pressure_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Gyro_Calibr) > 0) // case DMP_header_bitmap_Gyro_Calibr:
+  {
+    // lcm20948MPUFifoControl.c suggests icm_20948_DMP_Gyro_Calibr_Bytes is not supported
+    // and looking at DMP frames which have the Gyro_Calibr bit set, that certainly seems to be true.
+    // So, we'll skip this...:
+    /*
+			if (fifo_count < icm_20948_DMP_Gyro_Calibr_Bytes) // Check if we need to read the FIFO count again
+			{
+					result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+					if (result != ICM_20948_Stat_Ok)
+							return result;
+			}
+			if (fifo_count < icm_20948_DMP_Gyro_Calibr_Bytes)
+					return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+			result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Gyro_Calibr_Bytes);
+			if (result != ICM_20948_Stat_Ok)
+					return result;
+			for (int i = 0; i < icm_20948_DMP_Gyro_Calibr_Bytes; i++)
+			{
+					data->Gyro_Calibr.Bytes[DMP_Quat6_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+			}
+			fifo_count -= icm_20948_DMP_Gyro_Calibr_Bytes; // Decrement the count
+			*/
+  }
+
+  if ((data->header & DMP_header_bitmap_Compass_Calibr) > 0) // case DMP_header_bitmap_Compass_Calibr:
+  {
+    if (fifo_count < icm_20948_DMP_Compass_Calibr_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Compass_Calibr_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Compass_Calibr_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Compass_Calibr_Bytes; i++)
+    {
+      data->Compass_Calibr.Bytes[DMP_Quat6_Byte_Ordering[i]] = fifoBytes[i]; // Correct the byte order (map big endian to little endian)
+    }
+    fifo_count -= icm_20948_DMP_Compass_Calibr_Bytes; // Decrement the count
+  }
+
+  if ((data->header & DMP_header_bitmap_Step_Detector) > 0) // case DMP_header_bitmap_Step_Detector:
+  {
+    if (fifo_count < icm_20948_DMP_Step_Detector_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Step_Detector_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Step_Detector_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    uint32_t aWord = 0;
+    for (int i = 0; i < icm_20948_DMP_Step_Detector_Bytes; i++)
+    {
+      aWord |= ((uint32_t)fifoBytes[i]) << (24 - (i * 8));
+    }
+    data->Pedometer_Timestamp = aWord;
+    fifo_count -= icm_20948_DMP_Step_Detector_Bytes; // Decrement the count
+  }
+
+  // Now check for header2 features
+
+  if ((data->header2 & DMP_header2_bitmap_Accel_Accuracy) > 0) // case DMP_header2_bitmap_Accel_Accuracy:
+  {
+    if (fifo_count < icm_20948_DMP_Accel_Accuracy_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Accel_Accuracy_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    aShort = 0;
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Accel_Accuracy_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Accel_Accuracy_Bytes; i++)
+    {
+      aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+    }
+    data->Accel_Accuracy = aShort;
+    fifo_count -= icm_20948_DMP_Accel_Accuracy_Bytes; // Decrement the count
+  }
+
+  if ((data->header2 & DMP_header2_bitmap_Gyro_Accuracy) > 0) // case DMP_header2_bitmap_Gyro_Accuracy:
+  {
+    if (fifo_count < icm_20948_DMP_Gyro_Accuracy_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Gyro_Accuracy_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    aShort = 0;
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Gyro_Accuracy_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Gyro_Accuracy_Bytes; i++)
+    {
+      aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+    }
+    data->Gyro_Accuracy = aShort;
+    fifo_count -= icm_20948_DMP_Gyro_Accuracy_Bytes; // Decrement the count
+  }
+
+  if ((data->header2 & DMP_header2_bitmap_Compass_Accuracy) > 0) // case DMP_header2_bitmap_Compass_Accuracy:
+  {
+    if (fifo_count < icm_20948_DMP_Compass_Accuracy_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Compass_Accuracy_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    aShort = 0;
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Compass_Accuracy_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Compass_Accuracy_Bytes; i++)
+    {
+      aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+    }
+    data->Compass_Accuracy = aShort;
+    fifo_count -= icm_20948_DMP_Compass_Accuracy_Bytes; // Decrement the count
+  }
+
+  if ((data->header2 & DMP_header2_bitmap_Fsync) > 0) // case DMP_header2_bitmap_Fsync:
+  {
+    // lcm20948MPUFifoControl.c suggests icm_20948_DMP_Fsync_Detection_Bytes is not supported.
+    // So, we'll skip this just in case...:
+    /*
+			if (fifo_count < icm_20948_DMP_Fsync_Detection_Bytes) // Check if we need to read the FIFO count again
+			{
+					result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+					if (result != ICM_20948_Stat_Ok)
+							return result;
+			}
+			if (fifo_count < icm_20948_DMP_Fsync_Detection_Bytes)
+					return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+			aShort = 0;
+			result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Fsync_Detection_Bytes);
+			if (result != ICM_20948_Stat_Ok)
+					return result;
+			for (int i = 0; i < icm_20948_DMP_Fsync_Detection_Bytes; i++)
+			{
+					aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+			}
+			data->Fsync_Delay_Time = aShort;
+			fifo_count -= icm_20948_DMP_Fsync_Detection_Bytes; // Decrement the count
+			*/
+  }
+
+  if ((data->header2 & DMP_header2_bitmap_Pickup) > 0) // case DMP_header2_bitmap_Pickup:
+  {
+    if (fifo_count < icm_20948_DMP_Pickup_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Pickup_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    aShort = 0;
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Pickup_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Pickup_Bytes; i++)
+    {
+      aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+    }
+    data->Pickup = aShort;
+    fifo_count -= icm_20948_DMP_Pickup_Bytes; // Decrement the count
+  }
+
+  if ((data->header2 & DMP_header2_bitmap_Activity_Recog) > 0) // case DMP_header2_bitmap_Activity_Recog:
+  {
+    if (fifo_count < icm_20948_DMP_Activity_Recognition_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Activity_Recognition_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Activity_Recognition_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Activity_Recognition_Bytes; i++)
+    {
+      data->Activity_Recognition.Bytes[DMP_Activity_Recognition_Byte_Ordering[i]] = fifoBytes[i];
+    }
+    fifo_count -= icm_20948_DMP_Activity_Recognition_Bytes; // Decrement the count
+  }
+
+  if ((data->header2 & DMP_header2_bitmap_Secondary_On_Off) > 0) // case DMP_header2_bitmap_Secondary_On_Off:
+  {
+    if (fifo_count < icm_20948_DMP_Secondary_On_Off_Bytes) // Check if we need to read the FIFO count again
+    {
+      result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+      if (result != ICM_20948_Stat_Ok)
+        return result;
+    }
+    if (fifo_count < icm_20948_DMP_Secondary_On_Off_Bytes)
+      return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+    result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Secondary_On_Off_Bytes);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+    for (int i = 0; i < icm_20948_DMP_Secondary_On_Off_Bytes; i++)
+    {
+      data->Secondary_On_Off.Bytes[DMP_Secondary_On_Off_Byte_Ordering[i]] = fifoBytes[i];
+    }
+    fifo_count -= icm_20948_DMP_Secondary_On_Off_Bytes; // Decrement the count
+  }
+
+  // Finally, extract the footer (gyro count)
+  if (fifo_count < icm_20948_DMP_Footer_Bytes) // Check if we need to read the FIFO count again
+  {
+    result = ICM_20948_get_FIFO_count(pdev, &fifo_count);
+    if (result != ICM_20948_Stat_Ok)
+      return result;
+  }
+  if (fifo_count < icm_20948_DMP_Footer_Bytes)
+    return ICM_20948_Stat_FIFOIncompleteData; // Bail if not enough data is available
+  aShort = 0;
+  result = ICM_20948_read_FIFO(pdev, &fifoBytes[0], icm_20948_DMP_Footer_Bytes);
+  if (result != ICM_20948_Stat_Ok)
+    return result;
+  for (int i = 0; i < icm_20948_DMP_Footer_Bytes; i++)
+  {
+    aShort |= ((uint16_t)fifoBytes[i]) << (8 - (i * 8));
+  }
+  data->Footer = aShort;
+  fifo_count -= icm_20948_DMP_Footer_Bytes; // Decrement the count
+
+  if (fifo_count > 0) // Check if there is still data waiting to be read
+    return ICM_20948_Stat_FIFOMoreDataAvail;
+
+  return result;
+}
+
+uint8_t sensor_type_2_android_sensor(enum inv_icm20948_sensor sensor)
+{
+  switch (sensor)
+  {
+  case INV_ICM20948_SENSOR_ACCELEROMETER:
+    return ANDROID_SENSOR_ACCELEROMETER; // 1
+  case INV_ICM20948_SENSOR_GYROSCOPE:
+    return ANDROID_SENSOR_GYROSCOPE; // 4
+  case INV_ICM20948_SENSOR_RAW_ACCELEROMETER:
+    return ANDROID_SENSOR_RAW_ACCELEROMETER; // 42
+  case INV_ICM20948_SENSOR_RAW_GYROSCOPE:
+    return ANDROID_SENSOR_RAW_GYROSCOPE; // 43
+  case INV_ICM20948_SENSOR_MAGNETIC_FIELD_UNCALIBRATED:
+    return ANDROID_SENSOR_MAGNETIC_FIELD_UNCALIBRATED; // 14
+  case INV_ICM20948_SENSOR_GYROSCOPE_UNCALIBRATED:
+    return ANDROID_SENSOR_GYROSCOPE_UNCALIBRATED; // 16
+  case INV_ICM20948_SENSOR_ACTIVITY_CLASSIFICATON:
+    return ANDROID_SENSOR_ACTIVITY_CLASSIFICATON; // 47
+  case INV_ICM20948_SENSOR_STEP_DETECTOR:
+    return ANDROID_SENSOR_STEP_DETECTOR; // 18
+  case INV_ICM20948_SENSOR_STEP_COUNTER:
+    return ANDROID_SENSOR_STEP_COUNTER; // 19
+  case INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR:
+    return ANDROID_SENSOR_GAME_ROTATION_VECTOR; // 15
+  case INV_ICM20948_SENSOR_ROTATION_VECTOR:
+    return ANDROID_SENSOR_ROTATION_VECTOR; // 11
+  case INV_ICM20948_SENSOR_GEOMAGNETIC_ROTATION_VECTOR:
+    return ANDROID_SENSOR_GEOMAGNETIC_ROTATION_VECTOR; // 20
+  case INV_ICM20948_SENSOR_GEOMAGNETIC_FIELD:
+    return ANDROID_SENSOR_GEOMAGNETIC_FIELD; // 2
+  case INV_ICM20948_SENSOR_WAKEUP_SIGNIFICANT_MOTION:
+    return ANDROID_SENSOR_WAKEUP_SIGNIFICANT_MOTION; // 17
+  case INV_ICM20948_SENSOR_FLIP_PICKUP:
+    return ANDROID_SENSOR_FLIP_PICKUP; // 46
+  case INV_ICM20948_SENSOR_WAKEUP_TILT_DETECTOR:
+    return ANDROID_SENSOR_WAKEUP_TILT_DETECTOR; // 41
+  case INV_ICM20948_SENSOR_GRAVITY:
+    return ANDROID_SENSOR_GRAVITY; // 9
+  case INV_ICM20948_SENSOR_LINEAR_ACCELERATION:
+    return ANDROID_SENSOR_LINEAR_ACCELERATION; // 10
+  case INV_ICM20948_SENSOR_ORIENTATION:
+    return ANDROID_SENSOR_ORIENTATION; // 3
+  case INV_ICM20948_SENSOR_B2S:
+    return ANDROID_SENSOR_B2S; // 45
+  default:
+    return ANDROID_SENSOR_NUM_MAX;
+  }
+}
+
+enum inv_icm20948_sensor inv_icm20948_sensor_android_2_sensor_type(int sensor)
+{
+  switch (sensor)
+  {
+  case ANDROID_SENSOR_ACCELEROMETER:
+    return INV_ICM20948_SENSOR_ACCELEROMETER;
+  case ANDROID_SENSOR_GYROSCOPE:
+    return INV_ICM20948_SENSOR_GYROSCOPE;
+  case ANDROID_SENSOR_RAW_ACCELEROMETER:
+    return INV_ICM20948_SENSOR_RAW_ACCELEROMETER;
+  case ANDROID_SENSOR_RAW_GYROSCOPE:
+    return INV_ICM20948_SENSOR_RAW_GYROSCOPE;
+  case ANDROID_SENSOR_MAGNETIC_FIELD_UNCALIBRATED:
+    return INV_ICM20948_SENSOR_MAGNETIC_FIELD_UNCALIBRATED;
+  case ANDROID_SENSOR_GYROSCOPE_UNCALIBRATED:
+    return INV_ICM20948_SENSOR_GYROSCOPE_UNCALIBRATED;
+  case ANDROID_SENSOR_ACTIVITY_CLASSIFICATON:
+    return INV_ICM20948_SENSOR_ACTIVITY_CLASSIFICATON;
+  case ANDROID_SENSOR_STEP_DETECTOR:
+    return INV_ICM20948_SENSOR_STEP_DETECTOR;
+  case ANDROID_SENSOR_STEP_COUNTER:
+    return INV_ICM20948_SENSOR_STEP_COUNTER;
+  case ANDROID_SENSOR_GAME_ROTATION_VECTOR:
+    return INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR;
+  case ANDROID_SENSOR_ROTATION_VECTOR:
+    return INV_ICM20948_SENSOR_ROTATION_VECTOR;
+  case ANDROID_SENSOR_GEOMAGNETIC_ROTATION_VECTOR:
+    return INV_ICM20948_SENSOR_GEOMAGNETIC_ROTATION_VECTOR;
+  case ANDROID_SENSOR_GEOMAGNETIC_FIELD:
+    return INV_ICM20948_SENSOR_GEOMAGNETIC_FIELD;
+  case ANDROID_SENSOR_WAKEUP_SIGNIFICANT_MOTION:
+    return INV_ICM20948_SENSOR_WAKEUP_SIGNIFICANT_MOTION;
+  case ANDROID_SENSOR_FLIP_PICKUP:
+    return INV_ICM20948_SENSOR_FLIP_PICKUP;
+  case ANDROID_SENSOR_WAKEUP_TILT_DETECTOR:
+    return INV_ICM20948_SENSOR_WAKEUP_TILT_DETECTOR;
+  case ANDROID_SENSOR_GRAVITY:
+    return INV_ICM20948_SENSOR_GRAVITY;
+  case ANDROID_SENSOR_LINEAR_ACCELERATION:
+    return INV_ICM20948_SENSOR_LINEAR_ACCELERATION;
+  case ANDROID_SENSOR_ORIENTATION:
+    return INV_ICM20948_SENSOR_ORIENTATION;
+  case ANDROID_SENSOR_B2S:
+    return INV_ICM20948_SENSOR_B2S;
+  default:
+    return INV_ICM20948_SENSOR_MAX;
+  }
+}
+
+ICM_20948_Status_e inv_icm20948_set_gyro_sf(ICM_20948_Device_t *pdev, unsigned char div, int gyro_level)
+{
+  ICM_20948_Status_e result = ICM_20948_Stat_Ok;
+
+  if (pdev->_dmp_firmware_available == false)
+    return ICM_20948_Stat_DMPNotSupported;
+
+  // gyro_level should be set to 4 regardless of fullscale, due to the addition of API dmp_icm20648_set_gyro_fsr()
+  gyro_level = 4;
+
+  // First read the TIMEBASE_CORRECTION_PLL register from Bank 1
+  int8_t pll; // Signed. Typical value is 0x18
+  result = ICM_20948_set_bank(pdev, 1);
+  result = ICM_20948_execute_r(pdev, AGB1_REG_TIMEBASE_CORRECTION_PLL, (uint8_t *)&pll, 1);
+  if (result != ICM_20948_Stat_Ok)
+  {
+    return result;
+  }
+
+  pdev->_gyroSFpll = pll; // Record the PLL value so we can debug print it
+
+  // Now calculate the Gyro SF using code taken from the InvenSense example (inv_icm20948_set_gyro_sf)
+
+  long gyro_sf;
+
+  unsigned long long const MagicConstant = 264446880937391LL;
+  unsigned long long const MagicConstantScale = 100000LL;
+  unsigned long long ResultLL;
+
+  if (pll & 0x80)
+  {
+    ResultLL = (MagicConstant * (long long)(1ULL << gyro_level) * (1 + div) / (1270 - (pll & 0x7F)) / MagicConstantScale);
+  }
+  else
+  {
+    ResultLL = (MagicConstant * (long long)(1ULL << gyro_level) * (1 + div) / (1270 + pll) / MagicConstantScale);
+  }
+  /*
+	    In above deprecated FP version, worst case arguments can produce a result that overflows a signed long.
+	    Here, for such cases, we emulate the FP behavior of setting the result to the maximum positive value, as
+	    the compiler's conversion of a u64 to an s32 is simple truncation of the u64's high half, sadly....
+	*/
+  if (ResultLL > 0x7FFFFFFF)
+    gyro_sf = 0x7FFFFFFF;
+  else
+    gyro_sf = (long)ResultLL;
+
+  pdev->_gyroSF = gyro_sf; // Record value so we can debug print it
+
+  // Finally, write the value to the DMP GYRO_SF register
+  unsigned char gyro_sf_reg[4];
+  gyro_sf_reg[0] = (unsigned char)(gyro_sf >> 24);
+  gyro_sf_reg[1] = (unsigned char)(gyro_sf >> 16);
+  gyro_sf_reg[2] = (unsigned char)(gyro_sf >> 8);
+  gyro_sf_reg[3] = (unsigned char)(gyro_sf & 0xff);
+  result = inv_icm20948_write_mems(pdev, GYRO_SF, 4, (const unsigned char *)&gyro_sf_reg);
+
+  return result;
+}