Speeding up I2C Communication with MPU-6050

I am using the MPU-6050 for an Arduino Project with the I2Cdev library and have used code that I have found form other sources.

I was wondering if there was any way to speed up the code? I found that to go through the loop its takes about 4200us. After reading the MPU-6050 datasheet I found that the DMP refreshes at a rate of 1000Hz so this 4200us time should not be limited by the MPU. After testing the code, I found that one line in the code takes up 2400us alone.

mpu.getFIFOBytes(fifoBuffer, packetSize);

I am assuming this is where the Arduino gives the MPU its DMP data. Is there anyway to speed this process up? I have attached the full code below.

#include "MPU6050_6Axis_MotionApps20.h"

#define interruptPin 7
volatile byte MPUinterrupt;

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif

bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements 
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector

MPU6050 mpu;

float roll, pitch, yaw;
float yawLast, yawX;

unsigned long timer;

void setup() {
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(interruptPin), [ ] ( ) { MPUinterrupt = 1;}, FALLING);  //inline autonomous function "lambda function" sets MPUinterrupt variable to 1 this is a cool trick!

  // join I2C bus (I2Cdev library doesn't do this automatically)
  #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();
  TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
  #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
  #endif

  mpu.initialize();
  devStatus = mpu.dmpInitialize();

  mpu.setXGyroOffset(30); //70
  mpu.setYGyroOffset(4); //23
  mpu.setZGyroOffset(12); //-55
  mpu.setZAccelOffset(1906); // 1688 factory default for my test chip

  if (devStatus == 0) {
    mpu.setDMPEnabled(true);
    dmpReady = true;
    packetSize = mpu.dmpGetFIFOPacketSize();
  } 
}

void loop() {
  timer = micros();
  if (MPUinterrupt){ MPUinterrupt=0; //clear the flag
  fifoCount = mpu.getFIFOCount(); //300us
  if ((!fifoCount) || (fifoCount % packetSize)) {//36us
    mpu.resetFIFO();
  } else {
    while (fifoCount  >= packetSize) {
      mpu.getFIFOBytes(fifoBuffer, packetSize);//2400us!!!!!!!!!!
      fifoCount -= packetSize;
    }
  //////////////////////////////////////////////MPU-LOOP-Math/////////////////////////////////////////////////////
  // display Euler angles in degrees
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  yawX = ypr[0] * 180 / M_PI;
  roll = ypr[1] * 180 / M_PI;
  pitch = ypr[2] * 180 / M_PI;

 ///////////////////////MPU Acclermeter//////////////
  mpu.dmpGetAccel(&aa, fifoBuffer);
  mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
  mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

  ///////Compounded Yaw Calculations///////
  if ( abs(yawX-yawLast) < 11) {
  yaw += (yawX-yawLast);
  }
  yawLast=yawX;

//          Serial.print("\tYaw: ");   Serial.print(yaw);
//          Serial.print("\tRoll: ");  Serial.print(roll);
//          Serial.print("\tPitch: "); Serial.print(pitch); Serial.print("\t");
//
//          Serial.print("aworld\t"); Serial.print(aaWorld.x); //1g = 8192
//          Serial.print("\t");       Serial.print(aaWorld.y);
//          Serial.print("\t");       Serial.print(aaWorld.z); //set for +- 4g's
//          Serial.print("\t");
          Serial.println(micros()-timer);
  }
 }
}

mschindl:
I am using the MPU-6050 for an Arduino Project with the I2Cdev library and have used code that I have found form other sources.

I was wondering if there was any way to speed up the code? I found that to go through the loop its takes about 4200us. After reading the MPU-6050 datasheet I found that the DMP refreshes at a rate of 1000Hz so this 4200us time should not be limited by the MPU. After testing the code, I found that one line in the code takes up 2400us alone.

mpu.getFIFOBytes(fifoBuffer, packetSize);

I am assuming this is where the Arduino gives the MPU its DMP data. Is there anyway to speed this process up? I have attached the full code below.

#include "MPU6050_6Axis_MotionApps20.h"

#define interruptPin 7
volatile byte MPUinterrupt;

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif

bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector

MPU6050 mpu;

float roll, pitch, yaw;
float yawLast, yawX;

unsigned long timer;

void setup() {
 Serial.begin(115200);
 attachInterrupt(digitalPinToInterrupt(interruptPin), [ ] ( ) { MPUinterrupt = 1;}, FALLING);  //inline autonomous function "lambda function" sets MPUinterrupt variable to 1 this is a cool trick!

// join I2C bus (I2Cdev library doesn't do this automatically)
 #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
 Wire.begin();
 TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
 #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
 Fastwire::setup(400, true);
 #endif

mpu.initialize();
 devStatus = mpu.dmpInitialize();

mpu.setXGyroOffset(30); //70
 mpu.setYGyroOffset(4); //23
 mpu.setZGyroOffset(12); //-55
 mpu.setZAccelOffset(1906); // 1688 factory default for my test chip

if (devStatus == 0) {
   mpu.setDMPEnabled(true);
   dmpReady = true;
   packetSize = mpu.dmpGetFIFOPacketSize();
 }
}

void loop() {
 timer = micros();
 if (MPUinterrupt){ MPUinterrupt=0; //clear the flag
 fifoCount = mpu.getFIFOCount(); //300us
 if ((!fifoCount) || (fifoCount % packetSize)) {//36us
   mpu.resetFIFO();
 } else {
   while (fifoCount  >= packetSize) {
     mpu.getFIFOBytes(fifoBuffer, packetSize);//2400us!!!!!!!!!!
     fifoCount -= packetSize;
   }
 //////////////////////////////////////////////MPU-LOOP-Math/////////////////////////////////////////////////////
 // display Euler angles in degrees
 mpu.dmpGetQuaternion(&q, fifoBuffer);
 mpu.dmpGetGravity(&gravity, &q);
 mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
 yawX = ypr[0] * 180 / M_PI;
 roll = ypr[1] * 180 / M_PI;
 pitch = ypr[2] * 180 / M_PI;

///////////////////////MPU Acclermeter//////////////
 mpu.dmpGetAccel(&aa, fifoBuffer);
 mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
 mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

///////Compounded Yaw Calculations///////
 if ( abs(yawX-yawLast) < 11) {
 yaw += (yawX-yawLast);
 }
 yawLast=yawX;

//          Serial.print("\tYaw: ");   Serial.print(yaw);
//          Serial.print("\tRoll: ");  Serial.print(roll);
//          Serial.print("\tPitch: "); Serial.print(pitch); Serial.print("\t");
//
//          Serial.print("aworld\t"); Serial.print(aaWorld.x); //1g = 8192
//          Serial.print("\t");       Serial.print(aaWorld.y);
//          Serial.print("\t");       Serial.print(aaWorld.z); //set for +- 4g's
//          Serial.print("\t");
         Serial.println(micros()-timer);
 }
}
}

yes
line 305 of MPU6050_6Axis_MotionApps20.h sets the rate of the DMP (Digital Motion Processing) of the program loaded into the mpu60500.

    0x02,   0x16,   0x02,   0x00, 0x01                // D_0_22 inv_set_fifo_rate

    // This very last 0x01 WAS a 0x09, which drops the FIFO rate down to 20 Hz. 0x07 is 25 Hz,
    // 0x01 is 100Hz. Going faster than 100Hz (0x00=200Hz) tends to result in very noisy data.
    // DMP output frequency is calculated easily using this equation: (200Hz / (1 + value))

    // It is important to make sure the host processor can keep up with reading and processing
    // the FIFO output at the desired rate. Handling FIFO overflow cleanly is also a good idea.
};

with this said the DMP is a program written by someone and you load it into the mpu6050 if you are only needing the rates access this data directly and use the UNO to calculate it.
Z

Thanks for the help! When I change this value to 200Hz it does not speed up the reading of the data, only the frequency of when it is available. Does this mean the limitation is the speed of the Arduino reading the data?

Also, if the FIFO speed is set to 100Hz does that mean it will only send 100 data readings a second? When I count how many readings I get from the MPU I get around 138 a second? So where is the extra 38 coming from?

mschindl:
Thanks for the help! When I change this value to 200Hz it does not speed up the reading of the data, only the frequency of when it is available. Does this mean the limitation is the speed of the Arduino reading the data?

Also, if the FIFO speed is set to 100Hz does that mean it will only send 100 data readings a second? When I count how many readings I get from the MPU I get around 138 a second? So where is the extra 38 coming from?

The mpu6050 has its own microprocessor that can be programmed. InvenSense developed software you install into the mpu6050 that generates the fifo buffer and calculates a smooth value from all the readings in between. this embed motion driver has been updated service this software was developed... But I can't get it (version 6.1.2) to fit in the Arduino uno so we are left with an older version.

Embedded MotionDriver 6.12
Embedded MotionDriver 6.12 is our first ever 9-axis solution not locked to a specific MCU.Version 6.1.2 is an update to 6.1 that includes bug fixes and new libraries. This release is supported across all ARM Mx core architectures and supports the InvenSense MPU-6000, 6050, 6500, 9150, and 9250. The release includes optimized libraries and example projects for M3 and M4cores as well the generic ARM library for any Mx core and an additional library and project for the TI MSP430. eMD 6.1 also includes a Python client for both visualizing the sensor performance and commands for printing data. This solution will allow you to easily leverage and configure numerous features of the DMP and also benefit from dynamic features in the MPL software library. Libraries specific to IAR, Keil, and GCC are included.

From the features pdf available in invenSense download package

5.2 Sensor Data Many other types of data can be derived from the quaternion data. These conversions to the other data types outside the 3 main sensors are provided in the Motion Driver 6.12. With MD6.12, users will be able to get thefollowing data -

 Compass – magnetic field data in micro tesla on each axis

 Gyro – X, Y, Z axis rotational acceleration data in degrees per second

 Accel – X, Y, Z axis linear acceleration data in Gees

 Heading – 360 degrees from North with Y+ axis as the pointer

 Rotational Matrix – linear math 9 element matrix representation

 Euler Angles – Pitch, roll, yaw based in degrees with frame reference

 Quaternions – sensor fused w, x, y, z rotational angles

 Linear Acceleration – linear acceleration in body frame coordinates

 Gravity Vector – Which access gravity effects

The DMP features

The DMP is a fast, low power, programmable, embedded lightweight processor in the MPU devices. It is design to offload functionality, like sensor fusion and gesture recognition, from the MCU to save overall power in the system. The DMP has many features which can be dynamically turned off and on at run-time. Individual feature can also be disabled while leaving others running. All DMP data is outputted to the FIFO except for pedometer. The DMP can also be programmed to generate an interrupt via gesture or if data ready. For details on flashing and enabling the DMP please read the porting guide.

 3 Axis Low Power Quaternions – gyro only quaternions. This feature when enabled will integrate the gyro data at 200Hz while outputting the sensor fusion data to the FIFO at the user requested rate. The 200Hz integration will allow for more accurate sensor fusion data. In MD6, if this feature is enabled, the driver will push the 3-axis quaternion into the MPL library and the MPL will handle the accel and compass integrations.

 6 Axis Low Power Quaternions – gyro and accel quaternions. Similar to the 3-axis LPQ, integrates the accel and gyro at 200Hz sampling rates will outputting to the FIFO at the user requested rates. The 3-axis LPQ and 6-axis LPQ are mutually exclusive and should not be run concurrently. If enabled the 6-axis quaternions can be pushed into the MPL library and the MPL will handle the compass integration for 9-axis.

Sorry about the quotes inside of quotes... Sending from cell phone :slight_smile:

Z

Please tell which I2Cdev library you use, with a link to it. There are a number of copies with changes with old and new bugs.
Which Arduino board do you use ?

The MPU6050::getFIFOBytes() calls I2Cdev::readBytes().
The I2Cdev::readBytes() is full of bugs, making is slower that it should be.
But even without the bugs, the 2.4 ms will perhaps be 2.2 ms, but not much lower.

If the FastWire mode is turned on, the I2Cdev::readBytes() calls Fastwire::readBuf().

I can't find the source code of the FastWire library that is used by I2Cdev. The FastWire seems to directly control the TWI registers and using polling mode. It does not have those bugs, but it is not compatible with newer Arduino boards.

I think that the FastWire library is not needed. Using the normal Arduino Wire library without using it in the wrong way is almost as fast.

You could upgrade to a Arduino board with a ARM M0+ processor, and use a MPU-9250 in SPI mode.

Koepel:
Please tell which I2Cdev library you use, with a link to it. There are a number of copies with changes with old and new bugs.
Which Arduino board do you use ?

The MPU6050::getFIFOBytes() calls I2Cdev::readBytes().
The I2Cdev::readBytes() is full of bugs, making is slower that it should be.
But even without the bugs, the 2.4 ms will perhaps be 2.2 ms, but not much lower.

If the FastWire mode is turned on, the I2Cdev::readBytes() calls Fastwire::readBuf().

I can't find the source code of the FastWire library that is used by I2Cdev. The FastWire seems to directly control the TWI registers and using polling mode. It does not have those bugs, but it is not compatible with newer Arduino boards.

I think that the FastWire library is not needed. Using the normal Arduino Wire library without using it in the wrong way is almost as fast.

You could upgrade to a Arduino board with a ARM M0+ processor, and use a MPU-9250 in SPI mode.

I am understanding your request better now

This only checks how much data is in the FIFO buffer

mpu.getFIFOBytes(fifoBuffer, packetSize);

then we test to see if the data is at the correct length

if ((!fifoCount) || (fifoCount % packetSize))

then we retrieve the data

       while (fifoCount  >= packetSize) {
      mpu.getFIFOBytes(fifoBuffer, packetSize);//2400us!!!!!!!!!!
      fifoCount -= packetSize;
    }

This retrieves the block of data:

/* ================================================================================================ *
 | Default MotionApps v2.0 42-byte FIFO packet structure:                                           |
 |                                                                                                  |
 | [QUAT W][      ][QUAT X][      ][QUAT Y][      ][QUAT Z][      ][GYRO X][      ][GYRO Y][      ] |
 |   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  |
 |                                                                                                  |
 | [GYRO Z][      ][ACC X ][      ][ACC Y ][      ][ACC Z ][      ][      ]                         |
 |  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41                          |
 * ================================================================================================ */

// this block of memory gets written to the MPU on start-up, and it seems
// to be volatile memory, so it has to be done each time (it only takes ~1
// second though)

It should be possible to turn off unused data shrinking the size of the packet.
streamlining the process is also an interest of mine too :slight_smile:
Z

P.S.
You are using the modified code I designed the streamlining to this point. It was done with help from friends on this forum. Let's make it even better

mpu.getFIFOBytes(fifoBuffer, packetSize);

in MPU6050.cpp
Your code calls:

void MPU6050::getFIFOBytes(uint8_t *data, uint8_t length) {
   if(length > 0){
       I2Cdev::readBytes(devAddr, MPU6050_RA_FIFO_R_W, length, data);
   } else {
   	*data = 0;
   }
}

in I2Cdev.h
getFIFOBytes Calls: ( Shortened version for ease of reading removed code for older versions of arduino and fastwire ) 
 
Line 6 of your code:
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE

only keeping code for I2CDEV_ARDUINO_WIRE

/** Read multiple bytes from an 8-bit device register. * @param devAddr I2C slave device address * @param regAddr First register regAddr to read from * @param length Number of bytes to read * @param data Buffer to store read data in * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Number of bytes read (-1 indicates failure) */ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) { int8_t count = 0; uint32_t t1 = millis(); 
// Arduino v1.0.1+, Wire library // Adds official support for repeated start condition, yay! // I2C/TWI subsystem uses internal buffer that breaks with large data requests // so if user requests more than BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once for (uint8_t k = 0; k < length; k += min(length, BUFFER_LENGTH)) { Wire.beginTransmission(devAddr); Wire.write(regAddr); Wire.endTransmission(); Wire.beginTransmission(devAddr); Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { data[count] = Wire.read(); } } // check for timeout if (timeout > 0 && millis() - t1 >= timeout && count < length) count = -1; // timeout return count; }

in Wire.cpp
readBytes calls:
int TwoWire::read(void) { int value = -1; if(rxIndex < rxLength) { value = rxBuffer[rxIndex]; ++rxIndex; } return value; }

That's all the code in the entire read process of the FIFO buffer
any thoughts?
Z

I use the I2Cdev library by Jeff Rowberg and running it on an Arduino Micro (ATMega32u4): I2Cdev Library

I do not know if this is using FastWire or not. Unfortunately I do not have much experience coding, and do not think I would be much help improving the getFIFOBytes command.

Aha!! Made a breakthrough. So trying what Koepel said, I went into the I2Cdev library and enabled FastWire. That cut the line time from 2400us to 1200us. The whole loop now takes about 3500us.

Then doing what zhomeslice said, I changed the FIFO output frequency from 100Hz to 200Hz. Now I am able to get around 250 data sets a second with no FIFO reset! This is about twice the amount of data per second I was getting before.

So is it possible to go even faster? Will the MPU refresh any faster than 200Hz? Can the loop time be taken down any more?

The get DMP function take around 1600us to complete, but with this already great preformance I understand if we are at the limit of what a 16Mhz processor can do.

  // display Euler angles in degrees
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  yawX = ypr[0] * 180 / M_PI;
  roll = ypr[1] * 180 / M_PI;
  pitch = ypr[2] * 180 / M_PI;

 ///////////////////////MPU Acclermeter//////////////
  mpu.dmpGetAccel(&aa, fifoBuffer);
  mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
  mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

That is a lot faster, I was not expecting such a big difference :o

The floating point library for the AVR family of microcontrollers is extremely fast and optimized. However, a division with 'long' or with 'float' takes a lot longer than other operations, maybe 3 to 10 times longer.
I assume that this "180 / M_PI" will be solved by the compiler. That will probably not be calculated runtime.

The floating point library is very strict according to the IEEE754 standard. If you let go the standard, the compiler can optimize it better. There is a compiler option for that, called -ffast-math. It is possible to put a #pragma in the sketch, but I don't know if only the *.ino will get that or the libraries as well. Perhaps you have to put that #pragma in the top of every file. Perhaps the #pragma only needs to be in the sketch and in the I2Cdev.h.

The Arduino sets the -Os flag for the compiler to optimize for size. You could try to override that and optimize for speed. For example -O3. I'm sure that will help, but perhaps it requires too must SRAM or Flash memory.

#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-O3")

As @zhomeslice already wrote, if you only read the quaternations or only the x,y,z values, then you don't need all the time with the I2C transfer. I think that the 'dmp' firmware puts that in the FIFO and I don't know how to change that.

Some have made non-blocking I2C functions.

Do you know that the MPU-6050 is outdated and noisy ? More samples means more noise. All this effort is the same as putting spoilers and racing stripes on a Flintstone car.

Experimentation time :slight_smile:

As @zhomeslice already wrote, if you only read the quaternations or only the x,y,z values, then you don't need all the time with the I2C transfer. I think that the 'dmp' firmware puts that in the FIFO and I don't know how to change that.

I have never attempted to alter this line. What I believe this does is set the rate at which the MPU is actually sampled by the pre-compiled DMP program we load into the MPU6050. looks to me that we are dividing 1khz by 5 (1+4) to get the max 200hz now will this affect the rate stored at line 305 (inv_set_fifo_rate) I don't know.
My guess is that they are related. Will this speed up your code probably not but it could give you more samples to work with or it could provide cleaner data by getting more samples from the gyro and accelerometer rate values for the DMP to use in its calculations.

//Line 400 of MPU6050_6Axis_MotionApps20.h
            //DEBUG_PRINTLN(F("Setting sample rate to 200Hz..."));
            setRate(4); // 1khz / (1 + 4) = 200 Hz

Aha!! Made a breakthrough. So trying what Koepel said, I went into the I2Cdev library and enabled FastWire. That cut the line time from 2400us to 1200us. The whole loop now takes about 3500us.

Then doing what zhomeslice said, I changed the FIFO output frequency from 100Hz to 200Hz. Now I am able to get around 250 data sets a second with no FIFO reset! This is about twice the amount of data per second I was getting before.

So is it possible to go even faster? Will the MPU refresh any faster than 200Hz? Can the loop time be taken down any more?

The get DMP function take around 1600us to complete, but with this already great preformance I understand if we are at the limit of what a 16Mhz processor can do.

This is great I never realized how much performance I was giving up by not using the FastWire library

You may want to register as a developer with InvenSense and check out the latest library for the mpu6050 we are using something like 2.x while Version 6.x is out now! I spent several days attempting to get the new code to fit into the mpu6050 without luck. you will probably need to store the MPU DMP precompiled code in an external flash memory chip to be retrieved and loaded at startup.

Z

The Invesense link has some errors
This should works
https://www.invensense.com/developers/login/?redirect_to=developers
You're talking about Embedded MotionDriver 6.12?

zoomx:
The Invesense link has some errors
This should works
InvenSense Developers
You're talking about Embedded MotionDriver 6.12?

Thanks, and yes that's the one.
You can follow how he transferred the functions into his class most are exactly the same.
Z

Thank you for sharing this!