jrowberg / i2cdevlib

I2C device library collection for AVR/Arduino or other C++-based MCUs
http://www.i2cdevlib.com
3.91k stars 7.52k forks source link

Confusing line in MPU6050_DMP6 example #479

Open paynterf opened 4 years ago

paynterf commented 4 years ago

I'm trying to understand the following code fragment in the MPU6050_DMP6 example

    // check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024)
{
    // reset so we can continue cleanly
    mySerial.printf("FIFO overflow with FIFO count = %d\n", mpu.getFIFOCount());
    mpu.resetFIFO();

In particular the if() statement. It appears to be contradictory (or redundant) in the sense that if the MPU6050 FIFO interrupt overflow bit is set, doesn't that imply that the FIFO count is (or maybe, was) >= 1024?

I've run into some instances where this if() statement executes (the condition is TRUE) but the FIFO count reported by the mySerial.printf() statement reports that the FIFO count is much less than 1024 (like 28 instead). Obviously this means that the overflow bit is SET, but there is no overflow - what gives?

The only thing I can think of is that mpu.resetFIFO() clears the FIFO but doesn't reset the overflow bit in the interrupt status register. Could this be true?

TIA,

Frank

ZHomeSlice commented 4 years ago

It works but, I agree. The testing for Packet fill is inefficient and cumbersome. But this is an example I would do it like this:

    fifoCount = mpu.getFIFOCount();
    if ((fifo_count < packet_length) || (fifo_count % packetSize)) {
        mpu.resetFIFO();
        return 0; // Fifo is corrupted and must be reset
    }
// Continue with code because the remaining packets are good!

The % divides by packet size and returns a remainder which if it is NOT Zero there is a problem overflowed or corrupted in some way! done! we need the packet size to get the number of packets available so why make other requests for additional data. Everything you need to know can be determined with this one line.

paynterf commented 4 years ago

Homer,

Interesting that you used the modulus operator; I have done this before in some of my other robot code, but I was (and am still) a bit mystified by the IMU's treatment of the FIFO. For instance, does a non-modulo FIFO count always signify a corrupted FIFO? If so, how can this be? It doesn't seem possible that the FIFO is always loaded instantaneously with 'packetsize' bytes. What happens if the FIFO count is interrogated in the middle of a packet load operation? Does the mpu/dmp ignore mpu.getFIFOCount() calls until an entire packet load of bytes has been sequenced into the FIFO?

Is the FIFO load/unload process always reliable/predictable/atomic?

TIA,

Frank

On Fri, Oct 11, 2019 at 9:28 PM Homer Creutz notifications@github.com wrote:

It works but, I agree. The testing for Packet fill is inefficient and cumbersome. But this is an example I would do it like this:

fifoCount = mpu.getFIFOCount(); if ((fifo_count < packet_length) || (fifo_count % packetSize)) { mpu.resetFIFO(); return 0; // Fifo is corrupted and must be reset } // Continue with code because the remaining packets are good!

The % divides by packet size and returns a remainder which if it is NOT Zero there is a problem overflowed or corrupted in some way! done! we need the packet size to get the number of packets available so why make other requests for additional data. Everything you need to know can be determined with this one line.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T324VJM2QDHTWOCJ46BTQOER3NA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBBRZWI#issuecomment-541269209, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323TQTGSV3B2KGXAK6LQOER3NANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, As I have tested and I believe there is documentation to support this but I can't remember where to exactly look. https://www.invensense.com/developers/login/ the DMP 6.12 example is here but the V5.xx has better documentation that can be found around the web. (Note: The difference is that the DMP 6.12 version has a proprietary 9 degree of freedom library that can be used if we can find a way to compile it with the Arduino line. ) Back to the overall answer. The FIFO buffer depending on the version of DMP has a fixed size. if the buffer is empty it always inserts a packet of a fixed size defined in the DMP Source. when you have an overflow and the packet size is not an exact division of the FIFO buffer size a portion of the packet will be shoved from the beginning of the FIFO buffer and now all the data is deemed corrupted. Thinking about it you could use the modulus operator now knowing the remainder to easily recover from the overflow. just strip the partial packet off the buffer before passing it onto the normal routine. (possible code below)

So for your question about the FIFO buffer loading. I have never acquired a packet that was partial when the buffer has not overflowed. so their source code must fill the buffer before releasing the data When the MPU6050 uses an external clock it runs at 19.2MHz well beyond i2c bus speeds. I'm sure that the buffer could be filled with data before the i2c request must be fulfilled. If corrupted data is generated in another way then it is a flaw of the MPU source or the communication issue. and now out of my control. So only 2 conditions should consider failure in retrieving good data. Buffer is zero no data, or there is a remainder when dividing the FIFO count and the packet size.

Pondering a possible auto overflow correction routine: Just now Created this! It may have errors. (I won't be able to get to test this for a couple of weeks any volunteers?)


    fifoCount = mpu.getFIFOCount();
    if (fifo_count == 0) {
              return 0; // no data
        }
        if (fifo_count % packetSize) {  // fifo_count will ALWAYS be a multiple of packetSize unless it has overflowed!
              uint8_t fifoTrash[packetSize]; // Trash bin
              mpu.getFIFOBytes(fifoTrash, (fifo_count % packetSize) + packetSize ); // Remove the partial packet in the full overflown buffer and just to be safe remove one complete packet to make room for a new packet if it is generated while we are catching up.
/* 
My thought process. And possibly a future update after testing. 
### (Think of a world without overflow errors)
How can this be true? **Always** the last byte in the buffer is **always** the last bye of a good packet. So shifting off the bytes from the beginning of the buffer until you only have a buffer with the correct number of bytes = cleaned!
*/
              fifo_count -= ((fifo_count % packetSize) + packetSize); //Corrected buffer size without requesting over i2c saves clock ticks.

//TEST
fifoCount = mpu.getFIFOCount(); // lets see what we did
if ((fifo_count % packetSize) == 0) { 
 Serial.println("Success");
}
if (fifo_count % packetSize) { 
 Serial.print("Failure\n we are still off by:");
 Serial.println(fifo_count % packetSize);
// The error should only be +- 1 but I think this should work Just corret the math above and get an extra byte from the buffer.
}
//END TEST
    }
        // Now the buffer should be fixed so get the data

Frank, Thanks for the post I haven't thought about fixing the buffer overflow this way before.

Homer

paynterf commented 4 years ago

Homer,

This is very interesting, and I will try to test it here, maybe by introducing enough delay to ensure FIFO overflows.

One concern I have with all of this though is that while we think of 'mpu.getFIFOCount()' and 'mpu.getFIFOBytes()' as instantaneous, they are in fact quite slow with respect to the IMU/DMP. So, what does the result of one of these calls mean? From the IMU/DMP's perspective, it might mean "oh yeah, that was the count last year some time, so what?" or "You read 14 bytes, but while you were doing it I overflowed the FIFO".

Another issue I have is this: If the FIFO overflows, and the IMU/DMP starts overwriting the data, why doesn't this happen in packet_size byte increments so we never see corrupted data? IOW, why would a FIFO overflow be a problem at all? A 1024-byte buffer can hold 24 42-bit packets + 16 bytes. Since the IMU/DMP knows when the FIFO overflows, why wouldn't it simply skip the broken packet and start overwriting the start of the FIFO with a brand-new packet?

Arggh, I have a headache! ;-)

Frank

On Sat, Oct 12, 2019 at 11:09 AM Homer Creutz notifications@github.com wrote:

Frank, As I have tested and I believe there is documentation to support this but I can't remember where to exactly look. https://www.invensense.com/developers/login/ the DMP 6.12 example is here but the V5.xx has better documentation that can be found around the web. (Note: The difference is that the DMP 6.12 version has a proprietary 9 degree of freedom library that can be used if we can find a way to compile it with the Arduino line. ) Back to the overall answer. The FIFO buffer depending on the version of DMP has a fixed size. if the buffer is empty it always inserts a packet of a fixed size defined in the DMP Source. when you have an overflow and the packet size is not an exact division of the FIFO buffer size a portion of the packet will be shoved from the beginning of the FIFO buffer and now all the data is deemed corrupted. Thinking about it you could use the modulus operator now knowing the remainder to easily recover from the overflow. just strip the partial packet off the buffer before passing it onto the normal routine. (possible code below)

So for your question about the FIFO buffer loading. I have never acquired a packet that was partial when the buffer has not overflowed. so their source code must fill the buffer before releasing the data When the MPU6050 uses an external clock it runs at 19.2MHz well beyond i2c bus speeds. I'm sure that the buffer could be filled with data before the i2c request must be fulfilled. If corrupted data is generated in another way then it is a flaw of the MPU source or the communication issue. and now out of my control. So only 2 conditions should consider failure in retrieving good data. Buffer is zero no data, or there is a remainder when dividing the FIFO count and the packet size.

Pondering a possible auto overflow correction routine: Just now Created this! It may have errors. (I won't be able to get to test this for a couple of weeks any volunteers?)

fifoCount = mpu.getFIFOCount(); if (fifo_count == 0) { return 0; // no data } if (fifo_count % packetSize) { // fifo_count will ALWAYS be a multiple of packetSize unless it has overflowed! uint8_t fifoTrash[packetSize]; // Trash bin mpu.getFIFOBytes(fifoTrash, (fifo_count % packetSize) + packetSize ); // Remove the partial packet in the full overflown buffer and just to be safe remove one complete packet to make room for a new packet if it is generated while we are catching up. /* My thought process. And possibly a future update after testing.

(Think of a world without overflow errors)

How can this be true? Always the last byte in the buffer is always the last bye of a good packet. So shifting off the bytes from the beginning of the buffer until you only have a buffer with the correct number of bytes = cleaned! */ fifo_count -= ((fifo_count % packetSize) + packetSize); //Corrected buffer size without requesting over i2c saves clock ticks.

//TEST fifoCount = mpu.getFIFOCount(); // lets see what we did if ((fifo_count % packetSize) == 0) { Serial.println("Success"); } if (fifo_count % packetSize) { Serial.print("Failure\n we are still off by:"); Serial.println(fifo_count % packetSize); // The error should only be +- 1 but I think this should work Just corret the math above and get an extra byte from the buffer. } //END TEST } // Now the buffer should be fixed so get the data

Frank, Thanks for the post I haven't thought about fixing the buffer overflow this way before.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T3225D6Z2LUJPGNWEMCDQOHSCDA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBCBOEA#issuecomment-541333264, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T32ZWC6FPHBRH5BU5X2DQOHSCDANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, I could imagine that there might be a case where the 10ms time is up and we randomly started the request FIFO buffer request just before the time is up and the buffer overflows and now we read assuming that all is well... but that is difficult MPU6050 has a buffer size of 1024 bytes and Default MotionApps v2.0 has 42-byte FIFO packet structure. so the FIFO would overflow exactly at 250 milliseconds. My version 6.12 I shared has a smaller packet size of only 28 bytes. So it would overflow at 370 Milliseconds.

Fifo data is stacked first in first out so if the rule is the last bit in the FIFO buffer is always the last bit in a valid packet then you overflowed the first packet retrieved would be a partial packet as the newest packet would overweight part of the data and push the Front marker over. If front an back markers are the same then the buffer is considered empty. if you take a full packet size out, you automatically chop into the next packet. so this caries on leaving every packet split up between two reads. To correct this you need to clean out the damaged packet and give room for another packet to be stored. I prefer catching up to the moment by reading all the packets in the buffer and only keeping the last one which is the most recent reading.

The mpu 6050 doesn't know how much data a packet contains form the DMP firmware it just stores the data for us to grab and keeps a counter the first in first out doesn't shift the data as we read it just rotates the data around a fixed buffer. so if you overflow you push the start reading here marker over by on from the last writing spot. this video might help explain what is happening https://youtu.be/0KC69GcltI0?t=256 The only difference from this video and what happens in the mpu6050 is that when the array is full new values will be written shoving front marker one ahead for each value written keeping the array in a full state, overwriting the oldest data and throwing an overflow flag. Confusing right.

Homer

paynterf commented 4 years ago

Homer,

I did watch the video, and it helped (some, anyway) - thanks. So, If the FIFO is arranged as a wrap-around buffer, why wouldn't the normal front/back marker management algorithm take care of 'overflows'? IOW, why would we care where the 'start reading here' marker is, since reads should wrap right around with the writes. Is there something fundamental I'm missing here?

But, since the empirical evidence clearly indicates that we do have to care about overflows, isn't the implication then that the FIFO isn't arranged as a wrap-around buffer with appropriate front/back marker management?

Confusing - YES! ;-)

BTW, on a separate but related subject: The documentation associated with Jeff's MPU6050_6Axis_MotionApps_V6_12.h implies that there is currently no way to adjust the IMU's FIFO load rate - we're stuck with the MPU6050_DMP_FIFO_RATE_DIVISOR 0x01 default. Do you happen to know if this is really the case? The reason I ask is my applications are for wheeled robots - relatively high mass/low angular velocity, so I normally throttle the 'fusion rate' to 20Hz using MPU6050_DMP_FIFO_RATE_DIVISOR 0x09.

I'm setting up a test program using Jeff's MPU6050_DMP6_using_DMP_V6.12 example, modified by placing an interrupts counter in the ISR, and a 100 mSec delay at the start of the loop() function. This resulted in the following partial printout.

......>......

// X Accel Y Accel Z Accel X Gyro Y Gyro Z Gyro //OFFSETS -3228, 2452, 866, 144, -20, 71 Enabling DMP... Enabling interrupt detection (Arduino external interrupt 0)... DMP ready! Waiting for first interrupt... Msect Yaw NumInt fifoCount 7919 -0.01 1 280 8023 -0.01 0 560 8125 -0.01 1 812 FIFO overflow! 8329 -0.05 1 252 8432 -0.05 0 532 8535 -0.04 1 784 FIFO overflow! 8738 0.18 1 252 8841 0.10 0 532 8944 -0.02 1 784 FIFO overflow! 9148 -5.39 1 252 9250 -5.60 0 532 9354 -5.84 1 784 FIFO overflow! 9558 -23.23 0 252 9660 -23.64 0 532 9763 -24.07 1 784 FIFO overflow! 9966 -39.12 0 252 10070 -39.48 0 532 10173 -39.83 1 784 FIFO overflow! 10376 -55.19 0 252 10479 -55.65 0 532 10583 -56.15 1 784 FIFO overflow! 10786 -57.84 1 252 10889 -57.22 0 532 10992 -56.68 1 784 FIFO overflow! 11196 -25.62 1 252 11298 -24.61 0 532 11402 -23.61 1 784 FIFO overflow! 11606 5.91 1 252 11708 6.31 0 532 11811 6.73 1 784 FIFO overflow! 12015 25.60 1 252 12118 26.09 0 532 12221 26.62 1 784 FIFO overflow! 12425 46.35 1 252 12527 46.74 0 532 12631 47.15 1 784 FIFO overflow! 12834 41.65 1 252 12937 40.78 0 532 13040 39.91 1 784 FIFO overflow! 13244 12.71 1 252 13346 12.09 0 532 13450 11.46 0 784 FIFO overflow! 13654 -15.69 1 252 13757 -16.51 0 532 13859 -17.34 0 784 FIFO overflow! 14063 -46.85 1 252 14167 -47.43 0 532 14269 -48.01 0 784 FIFO overflow! 14473 -70.45 1 252 14576 -71.07 0 532 14679 -71.61 0 784 FIFO overflow! 14882 -52.87 1 252 14986 -52.08 0 532 15088 -51.30 0 784 FIFO overflow! 15292 -6.81 1 252 15395 -5.98 0 532 15499 -5.13 0 784 FIFO overflow! 15702 28.21 1 252 15805 28.98 0 532 15908 29.73 0 784 FIFO overflow! 16112 46.72 1 280 16215 46.64 0 532 16318 46.56 0 784 FIFO overflow! 16522 40.81 1 280 16624 40.80 0 532 16728 40.80 0 784 FIFO overflow! 16931 40.77 1 280 17034 40.77 0 532 17137 40.77 0 784 FIFO overflow! 17341 40.72 0 280 17443 40.72 1 532 17547 40.72 0 784 FIFO overflow! 17751 40.68 0 280 17853 40.68 1 532 17956 40.68 0 784

As you can see from the above, the fifo count increments about 252 bytes (6 packets) per 100 mSec (2.52 bytes/mSec or about 2.5KBS), way faster than I need, but...

Also, the current overflow handling algorithm in the MPU6050_DMP6_using_DMP_V6.12 example handles the overflow condition at least reasonably, as I was able to get good yaw data even in the presence of multiple FIFO overflow events, as shown in the accompanying Excel plot.

[image: 191012_OverflowTest1.jpg]

Next I'll modify the program to use your overflow handling algorithm and see what happens ;-)

Frank

On Sat, Oct 12, 2019 at 5:51 PM Homer Creutz notifications@github.com wrote:

Frank, I could imagine that there might be a case where the 10ms time is up and we randomly started the request FIFO buffer request just before the time is up and the buffer overflows and now we read assuming that all is well... but that is difficult MPU6050 has a buffer size of 1024 bytes and Default MotionApps v2.0 has 42-byte FIFO packet structure. so the FIFO would overflow exactly at 250 milliseconds. My version 6.12 I shared has a smaller packet size of only 28 bytes. So it would overflow at 370 Milliseconds.

Fifo data is stacked first in first out so if the rule is the last bit in the FIFO buffer is always the last bit in a valid packet then you overflowed the first packet retrieved would be a partial packet as the newest packet would overweight part of the data and push the Front marker over. If front an back markers are the same then the buffer is considered empty. if you take a full packet size out, you automatically chop into the next packet. so this caries on leaving every packet split up between two reads. To correct this you need to clean out the damaged packet and give room for another packet to be stored. I prefer catching up to the moment by reading all the packets in the buffer and only keeping the last one which is the most recent reading.

The mpu 6050 doesn't know how much data a packet contains form the DMP firmware it just stores the data for us to grab and keeps a counter the first in first out doesn't shift the data as we read it just rotates the data around a fixed buffer. so if you overflow you push the start reading here marker over by on from the last writing spot. this video might help explain what is happening https://youtu.be/0KC69GcltI0?t=256 The only difference from this video and what happens in the mpu6050 is that when the array is full new values will be written shoving front one ahead for each value written keeping the array full overwriting the oldest data and throwing an overflow flag. Confusing right.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T325U5A52HOXXLX23O5TQOJBFDA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBCJAMQ#issuecomment-541364274, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T322SVQJSF3S3YIZ2NULQOJBFDANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, Some answers to your questions:

Why would we care where the 'start reading here' marker is, since reads should wrap right around with the writes? Is there something fundamental I'm missing here?

The problem is the buffer size doesn't evenly match the packet length so some fraction of the oldest packet gets partially overwritten with the newest packet shifting the first pointer into the middle of the oldest packet. so only a partial packet remains Buffer Size:

111112222233333444445555566666777 overflows 2 77


771112222233333444445555566666777
    ^
So packet (1) only has a portion of  its packet left and the pointer for the next read event points at the first #1 
So if we read the (5 byte) packet we would get 11122 and the pointer would be at the next 2 corrupted packet

> implies that there is currently no way to adjust the IMU's FIFO load rate - we're stuck with the MPU6050_DMP_FIFO_RATE_DIVISOR 0x01 default.  Do you happen to know if this is really the case?

Ther is no function specifically designed to do it directly but you can adjust this.

```
#define DMP_SAMPLE_RATE     (200)
#define D_0_22                  (22+512) // Memory location for DMP V6.12 Fifo Rate 
/**
 *  @brief      Set DMP output rate.
 *  Only used when DMP is on.
 *  @param[in]  rate    Desired fifo rate (Hz).
 *  @return     0 if successful.
 */
void dmp_set_fifo_rate(unsigned short rate)
{
    unsigned short div;
    unsigned char tmp[8];

    if (rate > DMP_SAMPLE_RATE)
        return ;
    div = DMP_SAMPLE_RATE / rate - 1;
    tmp[0] = (unsigned char)((div >> 8) & 0xFF);
    tmp[1] = (unsigned char)(div & 0xFF);
   // mpu_write_mem(D_0_22, 2, tmp)  // from the Invensence Example code line 684 in file inv_mpu_dmp_motion_driver.c
Converted to this librarys code
   I2Cdev::writeByte(mpu.devAddr, MPU6050_RA_MEM_START_ADDR, D_0_22); // Sets where int  the DMP the rate chang value is to be written
   I2Cdev::writeBytes(mpu.devAddr, MPU6050_RA_MEM_R_W, 2, tmp); // Sets the Rate
}
```

I Slapped that together from the invensense example code... It should work.

> Next I'll modify the program to use your overflow handling algorithm and see what happens ;-)

Good Luck on the mod. It should work

Homer
paynterf commented 4 years ago

Homer,

Aha! I finally get it - thanks for the graphic (literally) explanation! ;-)

I'll give the V6.12 rate change function a whirl and let you know how it goes.

Frank

On Sat, Oct 12, 2019 at 8:38 PM Homer Creutz notifications@github.com wrote:

Frank, Some answers to your questions:

Why would we care where the 'start reading here' marker is, since reads should wrap right around with the writes? Is there something fundamental I'm missing here?

The problem is the buffer size doesn't evenly match the packet length so some fraction of the oldest packet gets partially overwritten with the newest packet shifting the first pointer into the middle of the oldest packet. so only a partial packet remains Buffer Size:

111112222233333444445555566666777 overflows 2 77

771112222233333444445555566666777 ^ So packet (1) only has a portion of its packet left and the pointer for the next read event points at the first #1 So if we read the (5 byte) packet we would get 11122 and the pointer would be at the next 2 corrupted packet

implies that there is currently no way to adjust the IMU's FIFO load rate - we're stuck with the MPU6050_DMP_FIFO_RATE_DIVISOR 0x01 default. Do you happen to know if this is really the case?

Ther is no function specifically designed to do it directly but you can adjust this.

#define DMP_SAMPLE_RATE     (200)
#define D_0_22                  (22+512) // Memory location for DMP V6.12 Fifo Rate
/**
 *  @brief      Set DMP output rate.
 *  Only used when DMP is on.
 *  @param[in]  rate    Desired fifo rate (Hz).
 *  @return     0 if successful.
 */
void dmp_set_fifo_rate(unsigned short rate)
{
    unsigned short div;
    unsigned char tmp[8];

    if (rate > DMP_SAMPLE_RATE)
        return ;
    div = DMP_SAMPLE_RATE / rate - 1;
    tmp[0] = (unsigned char)((div >> 8) & 0xFF);
    tmp[1] = (unsigned char)(div & 0xFF);
   // mpu_write_mem(D_0_22, 2, tmp)  // from the Invensence Example code line 684 in file inv_mpu_dmp_motion_driver.c
Converted to this librarys code
   I2Cdev::writeByte(mpu.devAddr, MPU6050_RA_MEM_START_ADDR, D_0_22); // Sets where int  the DMP the rate chang value is to be written
   I2Cdev::writeBytes(mpu.devAddr, MPU6050_RA_MEM_R_W, 2, tmp); // Sets the Rate
}

I Slapped that together from the invensense example code... It should work.

Next I'll modify the program to use your overflow handling algorithm and see what happens ;-)

Good Luck on the mod. It should work

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T326JJ5HN2IOIDMBTGBTQOJUXBA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBCLK3Q#issuecomment-541373806, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327VUC6VFKHIMPDZK23QOJUXBANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, tomorrow I'll be traveling Keep us informed I may be slow to respond. Homer

paynterf commented 4 years ago

Homer,

I have been playing with your algorithms, and have some promising results (although with at least one minor 'fly in the ointment' - see the post). I took the liberty of documenting all the work so far in a post on my 'Paynter's Palace' blog site. I wanted to just share the draft post with you rather than publish it publicly, but apparently the 'Share Draft Post' Wordpress plugin has some problems with my 'Classic Editor' configuration so I was unable to do that. So, I published the post so you can see it. Please feel free to comment and/or suggest changes, which I will be more than happy to implement. I'm also quite happy to UNpublish it if you are in any way uncomfortable with it; I do these posts just as much for my own documentation as for anyone else's edification, so regardless of its published/draft status, I'll still have it available to me ;-). Here's the post URL:

https://www.fpaynter.com/2019/10/mpu6050-fifo-buffer-management-study/

I understand you might not be able to respond for a while, and that's fine. In the meantime I may be able to make some more progress, and maybe even figure out why the reported FIFO byte count is only half what it should be!

Regards,

Frank

On Sat, Oct 12, 2019 at 11:50 PM Homer Creutz notifications@github.com wrote:

Frank, tomorrow I'll be traveling Keep us informed I may be slow to respond. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T327DGBH33MC6WIYYIHLQOKLHVA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBCNWTI#issuecomment-541383501, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T3277ZKI7PKAKDX4DP23QOKLHVANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, This is a very nice article. I'm fine with it and I'm glad I can help.

You mention: What are the differences between the versions?

The best part about V6.12 is that it has an auto calibration for the gyro built into the dmp firmware. I've enabled it for my donation to Jeff's code. All you have to do is have the MPU set still for 8 seconds and it will further calibrate itself.

The best part about V2 is that it's smaller.than v V6.12.

About the dmp firmware and what I did to improve Jeff's code The DMP firmware has a series of memory locations that can be changed to add and remove features. These features basically add data to the FIFO buffer. It is almost impossible to follow. So I made all the changes using invensence cumbersome example code verified it worked then I added a capture routine and retrieved the modified firmware before the mpu6050 started running the dmp firmware. This pre-configured firmware contained all the modifications for a specific purpose. While additional changes can be made, most Arduino programmers can't figure it out. And keep the defaults I've set. It took me months of trial and error to get to this point and I'm still trying to get the 9 degree our freedom code to comply under an Arduino ide. This library is another black box that has been turned into a library file that is just supposed to work lol. This library must run on the Arduino and not the mpu9150. The MPU9150 and MPU9250 are basically an MPU6050 with a magnetometer included.

My version of the mpu6050 code can be found here https://github.com/ZHomeSlice/Simple_MPU6050

It uses Jeff's i2c library by extending it. I also treat things differently I use allot of macros rather than functions to set up the mpu6050 this allows me to condensed the code size to something easily viewed while providing an easy way to look up what each macro does. Every possible register is represented in my macros

I also have an overflow routine I created that will certainly change with what we have just found. Although you might be interested in seeing my early attempts that are defiantly not as simple as our new way you've just successfully tested. Thank you,.

I also created the calibration routines using a simple pid routine.

It's late here and I'll look for more tomorrow. My cell phone likes to incorrectly correct the words I try to swipe in so forgive any spelling and punctuation errors.

Homer

paynterf commented 4 years ago

Homer,

Thanks for the information about the firmware and your library. I'll give your library a whirl!

Any ideas about mpu.getFIFOCount() reporting only half the expected value based on num_interrupts X 28?

Wow! if you typed your entire reply on a cell phone, that's impressive; I'm lucky to type two or three words for a text message! ;-)

Frank

On Mon, Oct 14, 2019 at 2:39 AM Homer Creutz notifications@github.com wrote:

Frank, This is a very nice article. I'm fine with it and I'm glad I can help.

You mention: What are the differences between the versions?

The best part about V6.12 is that it has an auto calibration for the gyro built into the dmp firmware. I've enabled it for my donation to Jeff's code. All you have to do is have the MPU set still for 8 seconds and it will further calibrate itself.

The best part about V2 is that it's smaller.than v V6.12.

About the dmp firmware and what I did to improve Jeff's code The DMP firmware has a series of memory locations that can be changed to add and remove features. These features basically add data to the FIFO buffer. It is almost impossible to follow. So I made all the changes using invensence cumbersome example code verified it worked then I added a capture routine and retrieved the modified firmware before the mpu6050 started running the dmp firmware. This pre-configured firmware contained all the modifications for a specific purpose. While additional changes can be made, most Arduino programmers can't figure it out. And keep the defaults I've set. It took me months of trial and error to get to this point and I'm still trying to get the 9 degree our freedom code to comply under an Arduino ide. This library is another black box that has been turned into a library file that is just supposed to work lol. This library must run on the Arduino and not the mpu9150. The MPU9150 and MPU9250 are basically an MPU6050 with a magnetometer included.

My version of the mpu6050 code can be found here https://github.com/ZHomeSlice/Simple_MPU6050

It uses Jeff's i2c library by extending it. I also treat things differently I use allot of macros rather than functions to set up the mpu6050 this allows me to condensed the code size to something easily viewed while providing an easy way to look up what each macro does. Every possible register is represented in my macros

I also have an overflow routine I created that will certainly change with what we have just found. Although you might be interested in seeing my early attempts that are defiantly not as simple as our new way you've just successfully tested. Thank you,.

I also created the calibration routines using a simple pid routine.

It's late here and I'll look for more tomorrow. My cell phone likes to incorrectly correct the words I try to swipe in so forgive any spelling and punctuation errors.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T327UHQDJP4RGT2COUGLQOQHZLA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBDPBYI#issuecomment-541520097, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T324C2D4CUAX6VPFWC3LQOQHZLANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

paynterf commented 4 years ago

Homer,

You might want to take a look at my update of just a few minutes ago. I'm beginning to think the MPU6050 is smarter (or dumber) than both of us!

I have gone through my code a number of times now, looking for a way to explain the anomalous results I'm getting, but haven't found a 'smoking gun'. I'm using a Chinese knockoff GY-521 rather than a 'name brand' device, so I guess it's conceivable I'm seeing some sort of hardware quality control issue. I'll try a different board and see if that helps.

Regards,

Frank

On Mon, Oct 14, 2019 at 8:44 AM Frank Paynter paynterf@gmail.com wrote:

Homer,

Thanks for the information about the firmware and your library. I'll give your library a whirl!

Any ideas about mpu.getFIFOCount() reporting only half the expected value based on num_interrupts X 28?

Wow! if you typed your entire reply on a cell phone, that's impressive; I'm lucky to type two or three words for a text message! ;-)

Frank

On Mon, Oct 14, 2019 at 2:39 AM Homer Creutz notifications@github.com wrote:

Frank, This is a very nice article. I'm fine with it and I'm glad I can help.

You mention: What are the differences between the versions?

The best part about V6.12 is that it has an auto calibration for the gyro built into the dmp firmware. I've enabled it for my donation to Jeff's code. All you have to do is have the MPU set still for 8 seconds and it will further calibrate itself.

The best part about V2 is that it's smaller.than v V6.12.

About the dmp firmware and what I did to improve Jeff's code The DMP firmware has a series of memory locations that can be changed to add and remove features. These features basically add data to the FIFO buffer. It is almost impossible to follow. So I made all the changes using invensence cumbersome example code verified it worked then I added a capture routine and retrieved the modified firmware before the mpu6050 started running the dmp firmware. This pre-configured firmware contained all the modifications for a specific purpose. While additional changes can be made, most Arduino programmers can't figure it out. And keep the defaults I've set. It took me months of trial and error to get to this point and I'm still trying to get the 9 degree our freedom code to comply under an Arduino ide. This library is another black box that has been turned into a library file that is just supposed to work lol. This library must run on the Arduino and not the mpu9150. The MPU9150 and MPU9250 are basically an MPU6050 with a magnetometer included.

My version of the mpu6050 code can be found here https://github.com/ZHomeSlice/Simple_MPU6050

It uses Jeff's i2c library by extending it. I also treat things differently I use allot of macros rather than functions to set up the mpu6050 this allows me to condensed the code size to something easily viewed while providing an easy way to look up what each macro does. Every possible register is represented in my macros

I also have an overflow routine I created that will certainly change with what we have just found. Although you might be interested in seeing my early attempts that are defiantly not as simple as our new way you've just successfully tested. Thank you,.

I also created the calibration routines using a simple pid routine.

It's late here and I'll look for more tomorrow. My cell phone likes to incorrectly correct the words I try to swipe in so forgive any spelling and punctuation errors.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T327UHQDJP4RGT2COUGLQOQHZLA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBDPBYI#issuecomment-541520097, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T324C2D4CUAX6VPFWC3LQOQHZLANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, So this may affect the V6.12 code where it only has a buffer of half of the expected 1024 bytes is available. My version of the code uses a smaller than expected buffer.

My SimpleMPU6050 only has an assumed 512 buffer size for all versions of the MPU6050 to accommodate this discrepancy I discovered with the MPU9250. It makes more sense that all MPU versions would be affected and not just the MPU9250 as every version uses the same MPU6050 or MPU6000 _maxPackets = floor(512 / packet_length); // MPU 9250 can only handle 512 bytes of data in the FIFO Because the DMP V6.12 requires more space than the V2 code I believe that the 1024 value is incorrect. I now believe that all versions of the MPU only get a buffer of 512 when using the newer V6.12 code.

you mentioned that anomalous results are present. Does this match what you are finding.

Homer

paynterf commented 4 years ago

Homer,

Interesting. Based on my results so far, a FIFO length of 512 by itself does not explain the anamalous results I've been getting. In my initial experiment with a100 mSec loop() delay, the FIFO count has been 308 with an interrupt count of 22, without any errors. But, on occasion, the FIFO count jumps to 316 (non-modular). Your algorithm catches this and (over two loop() cycles) corrects it, but your assumption was that a non-modular count could never happen unless the FIFO overflowed. So, we have a paradox; a FIFO count that is less than the max FIFO length (even 512) can occasionally result in a non-modular value.

A possible factor in all this is the apparent 2x error in the reported FIFO count when compared to the interrupt count. The reported number of interrupts between loop() iterations is typically 22, but the reported FIFO count is typically 308. But 308 x the packet length of 28 is 616, not 308! If in fact the count is 616 and not 308, AND the max buffer length was 512 not 1024, then the buffer should overflow. In this case I'm not sure why it didn't overflow every time, but...

Regards,

Frank

On Tue, Oct 15, 2019 at 1:56 AM Homer Creutz notifications@github.com wrote:

Frank, So this may affect the V6.12 code where it only has a buffer of half of the expected 1024 bytes is available. My version of the code uses a smaller than expected buffer.

My SimpleMPU6050 only has an assumed 512 buffer size for all versions of the MPU6050 to accommodate this discrepancy I discovered with the MPU9250. It makes more sense that all MPU versions would be affected and not just the MPU9250 as every version uses the same MPU6050 or MPU6000 _maxPackets = floor(512 / packet_length); // MPU 9250 can only handle 512 bytes of data in the FIFO Because the DMP V6.12 requires more space than the V2 code I believe that the 1024 value is incorrect. I now believe that all versions of the MPU only get a buffer of 512 when using the newer V6.12 code.

you mentioned that anomalous results are present. Does this match what you are finding.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T326IEXM7GYEFNDO4DFLQOVLSHA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBHQM5A#issuecomment-542049908, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327KJ4LGK5UH6WL63VTQOVLSHANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

paynterf commented 4 years ago

Homer,

I made a math error in my previous email. I meant to say the reported number of interrupts (22) times the assumed packet length of 28 is 616 not

  1. Oops! ;-)

Frank

On Tue, Oct 15, 2019 at 8:36 AM Frank Paynter paynterf@gmail.com wrote:

Homer,

Interesting. Based on my results so far, a FIFO length of 512 by itself does not explain the anamalous results I've been getting. In my initial experiment with a100 mSec loop() delay, the FIFO count has been 308 with an interrupt count of 22, without any errors. But, on occasion, the FIFO count jumps to 316 (non-modular). Your algorithm catches this and (over two loop() cycles) corrects it, but your assumption was that a non-modular count could never happen unless the FIFO overflowed. So, we have a paradox; a FIFO count that is less than the max FIFO length (even 512) can occasionally result in a non-modular value.

A possible factor in all this is the apparent 2x error in the reported FIFO count when compared to the interrupt count. The reported number of interrupts between loop() iterations is typically 22, but the reported FIFO count is typically 308. But 308 x the packet length of 28 is 616, not 308! If in fact the count is 616 and not 308, AND the max buffer length was 512 not 1024, then the buffer should overflow. In this case I'm not sure why it didn't overflow every time, but...

Regards,

Frank

On Tue, Oct 15, 2019 at 1:56 AM Homer Creutz notifications@github.com wrote:

Frank, So this may affect the V6.12 code where it only has a buffer of half of the expected 1024 bytes is available. My version of the code uses a smaller than expected buffer.

My SimpleMPU6050 only has an assumed 512 buffer size for all versions of the MPU6050 to accommodate this discrepancy I discovered with the MPU9250. It makes more sense that all MPU versions would be affected and not just the MPU9250 as every version uses the same MPU6050 or MPU6000 _maxPackets = floor(512 / packet_length); // MPU 9250 can only handle 512 bytes of data in the FIFO Because the DMP V6.12 requires more space than the V2 code I believe that the 1024 value is incorrect. I now believe that all versions of the MPU only get a buffer of 512 when using the newer V6.12 code.

you mentioned that anomalous results are present. Does this match what you are finding.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T326IEXM7GYEFNDO4DFLQOVLSHA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBHQM5A#issuecomment-542049908, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327KJ4LGK5UH6WL63VTQOVLSHANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, Let's perform a second fifoCount = mpu.getFIFOCount(); When we discover the error. This way we can determine if there is truly an error, Or we gust read during the FIFO fill process. My assumption that it is instantaneous could be wrong especially if you don't read out shortly after the interrupt occurs. Before we would scrap scrap everything and wait 10 MS for the new packet to be created. Now with the fix-it code in place this type of error should be handled. But instead we are catching partially filed packets at random.

So... Let's see if we are becoming lucky and catching a partial packet as it is written. You may try to read getFIFOCount several times rapidly after discovering the error to see how long it takes to compete the packet. Homer

paynterf commented 4 years ago

Homer,

Check the update for the latest data. I ran tests at 100 & 200 mSec loop() iteration delay with and without the added mpu.getFIFOCount(). Still getting non-modular counts.

Then at your suggestion, I modified your code to rapidly call mpu.getFIFOCount() as soon as possible after a non-modular count detection, and the count changed! I think you may have found the smoking gun!

Frank

On Tue, Oct 15, 2019 at 10:41 AM Homer Creutz notifications@github.com wrote:

Frank, Let's perform a second fifoCount = mpu.getFIFOCount(); When we discover the error. This way we can determine if there is truly an error, Or we gust read during the FIFO full process. My assumption that it is instantaneous could be wrong especially if you don't read out shortly after the interrupt occurs. Before we would scrap scrap everything and wait 10 MS for the new packet to be created. Now with the fix-it code in place this type of error should be handled. But instead we are catching partially filed packets at random.

So... Let's see if we are becoming lucky and catching a partial packet as it is written. You may try to read getFIFOCount several times rapidly after discovering the error to see how long it takes to compete the packet. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T322L6J2TN4JBFPP7SLDQOXJAPA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBJAQEY#issuecomment-542246931, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T325SSFPLVIAAXH5SCNLQOXJAPANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, So now let's determine how much time is required for updates before scrapping the packet.

unsigned long ErrorStart;
unsigned long ErrorEnd;
int Flag = 0;
ErrorStart = micros();
while(mpu.getFIFOCount() %  packetSize){
  ErrorEnd = Micors;
 Flag = 1;
}
if(Flag){
 Serial.print("It took this many microseconds to clear the error:");
 Serial.print(ErrorEnd - ErrorStart);
}

place this with no other code and you should be able to determine the loading duration of each packet until the overflow occurs

I'm very interested in the results.

My thoughts are that if the buffer is not filled and we detect a discrepancy as long as we have at least 1 full packet in the buffer we can drain the buffer up to the point of the next packet being written. Otherwise, we are waiting for the first packet to be completed. if we have a full buffer we need to clear the error packet and 1 extra. then we must recheck the buffer unless we for some reason caught the packet being written and still have a corrupted buffer. if no buffer corruption then we can read until the last packet and all is good. The code shouldn't be hard to wright I will see how much time tomorrow brings. If you could provide me with a delay time for the packet wright above I will see if I can complete this process.

Homer

paynterf commented 4 years ago

Homer,

49164 20 0 49264 20 280 It took this many microseconds to clear the error: 172 49367 21 588 49467 20 868

I'm going to try and instrument the code a little bit better to see what is going on - this is the first result.

Frank

On Wed, Oct 16, 2019 at 12:41 AM Homer Creutz notifications@github.com wrote:

Frank, So now let's determine how much time is required for updates before scrapping the packet.

unsigned long ErrorStart; unsigned long ErrorEnd; int Flag = 0; ErrorStart = micros(); while(mpu.getFIFOCount() % packetSize){ ErrorEnd = Micors; Flag = 1; } if(Flag){ Serial.print("It took this many microseconds to clear the error:"); Serial.print(ErrorEnd - ErrorStart); }

place this with no other code and you should be able to determine the loading duration of each packet until the overflow occurs

I'm very interested in the results.

My thoughts are that if the buffer is not filled and we detect a discrepancy as long as we have at least 1 full packet in the buffer we can drain the buffer up to the point of the next packet being written. Otherwise, we are waiting for the first packet to be completed. if we have a full buffer we need to clear the error packet and 1 extra. then we must recheck the buffer unless we for some reason caught the packet being written and still have a corrupted buffer. if no buffer corruption then we can read until the last packet and all is good. The code shouldn't be hard to wright I will see how much time tomorrow brings. If you could provide me with a delay time for the packet wright above I will see if I can complete this process.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T32ZSWEG7NAK236USK3LQO2LOTA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBLA4BA#issuecomment-542510596, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323T7Y7U5N7GZOJOWD3QO2LOTANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

paynterf commented 4 years ago

Homer,

Here's another run, instrumented to show the fifo count that caused the error:

Msec NumInt fifoCount 16523 20 280 16624 20 560 Error with fifo count = 863. It took 172 microseconds to clear the error 16727 21 868 16828 20 0 16928 20 280 17030 21 560 17131 20 840

And here's the code:

//Homer Creutz's suggested FIFO handling code unsigned long ErrorStart; unsigned long ErrorEnd; int Flag = 0; fifoCount = mpu.getFIFOCount(); int errorcount = fifoCount; ErrorStart = micros(); while (fifoCount % packetSize && fifoCount < MAX_FIFO_BYTES) { fifoCount = mpu.getFIFOCount(); ErrorEnd = micros(); Flag = 1; } if (Flag) { mySerial.printf("Error with fifo count = %d. It took %lu microseconds to clear the error\n", errorcount,(ErrorEnd-ErrorStart)); }

if (fifoCount == MAX_FIFO_BYTES) { mpu.resetFIFO(); }

Frank

On Wed, Oct 16, 2019 at 12:40 PM Frank Paynter paynterf@gmail.com wrote:

Homer,

49164 20 0 49264 20 280 It took this many microseconds to clear the error: 172 49367 21 588 49467 20 868

I'm going to try and instrument the code a little bit better to see what is going on - this is the first result.

Frank

On Wed, Oct 16, 2019 at 12:41 AM Homer Creutz notifications@github.com wrote:

Frank, So now let's determine how much time is required for updates before scrapping the packet.

unsigned long ErrorStart; unsigned long ErrorEnd; int Flag = 0; ErrorStart = micros(); while(mpu.getFIFOCount() % packetSize){ ErrorEnd = Micors; Flag = 1; } if(Flag){ Serial.print("It took this many microseconds to clear the error:"); Serial.print(ErrorEnd - ErrorStart); }

place this with no other code and you should be able to determine the loading duration of each packet until the overflow occurs

I'm very interested in the results.

My thoughts are that if the buffer is not filled and we detect a discrepancy as long as we have at least 1 full packet in the buffer we can drain the buffer up to the point of the next packet being written. Otherwise, we are waiting for the first packet to be completed. if we have a full buffer we need to clear the error packet and 1 extra. then we must recheck the buffer unless we for some reason caught the packet being written and still have a corrupted buffer. if no buffer corruption then we can read until the last packet and all is good. The code shouldn't be hard to wright I will see how much time tomorrow brings. If you could provide me with a delay time for the packet wright above I will see if I can complete this process.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T32ZSWEG7NAK236USK3LQO2LOTA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBLA4BA#issuecomment-542510596, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323T7Y7U5N7GZOJOWD3QO2LOTANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, This is interesting it takes less than .2 milliseconds to complete the buffer fill. So let us see if we can create some code to resolve this glitch... Here we go:

        int more;   
        int ctr;
        static int MaxPackets = MAX_FIFO_BYTES/packetSize;
        static int MaxPacketByets = MaxPackets * packetSize; 
    fifoCount = mpu.getFIFOCount();
    if (fifoCount < packetSize )
    {
        return 0; // Not Enough data FIFO Buffer is still considered empty
    }
       if (fifoCount > MaxPacketByets ) // We definitely have or will shortly have an overflow problem and need to remove the bytes from the buffer
       {
            uint8_t fifoTrash[2 * PACKET_SIZE]; // Trash bin (bit bucket) - just a place to put the removed bytes. Can't be just PACKET_SIZE!

        // option 1
         if(mpu.getFIFOCount()< MAX_FIFO_BYTES){
              mpu.getFIFOBytes(fifoTrash, packetSize); // remove a full packet  then waight to be sure that the packet is written
            delayMicroseconds(200);
            fifoCount = mpu.getFIFOCount();
            ctr++;
         }
// option 2
/*
           while(mpu.getFIFOCount()< MAX_FIFO_BYTES) //We need to make sure the buffer finishes filling which will take less than .2 milliseconds if this is even an issue.
           {
              ctr++; 
// this may not be enough to resolve the error... Option 1 has a delay but we already waited this long what's another 200 microseconds
           }
*/
           if(ctr) Serial.print("We actually detected the very last packet being written into the FIFO Buffer Before it overflowed!";
//once we are sure the buffer is full we can correctly remove the damaged packet.
            mpu.getFIFOBytes(fifoTrash, (fifoCount % packetSize) + packetSize);
        //fifoCount -= ((fifoCount % packetSize) + packetSize); //Correcting buffer content length without requesting over i2c saves clock ticks.
// or
        fifoCount = mpu.getFIFOCount();
       }
      more = (fifoCount / packetSize);// because the division is cast to int the remainder is removed even if the packet is being written to right now the last partial packet will be ignored.

      while (more--)// Get each packet until no complete packets remain. A partial packet could still exist.
      {
             mpu.getFIFOBytes(fifoBuffer, packetSize);
             fifoCount -= packetSize;
      }
Serial.println(fifoCount ); // this should be zero unless a partial packet existed at the time we attempted to read the FIFO.
return 1; // We have some data for you

So this is my thoughts on how to handle the overflow. If this succeeds then we could use this code without interrupts. it would return true if data is captured. and only return false if you were too early for the next request. This means no more overflow corruption for waiting too long!

Thanks for testing these and correcting my errors It is harder to code directly into this forum and not create any. Homer

paynterf commented 4 years ago

Homer,

I'm dealing with some disk & hardware issues at the moment, but I'll run this test as soon as I can

Frank

On Thu, Oct 17, 2019 at 4:52 AM Homer Creutz notifications@github.com wrote:

Frank, This is interesting it takes less than .2 milliseconds to complete the buffer fill. So let us see if we can create some code to resolve this glitch... Here we go:

    int more; 
    int ctr;
    static int MaxPackets = MAX_FIFO_BYTES/packetSize;
    static int MaxPacketByets = MaxPackets * packetSize;

fifoCount = mpu.getFIFOCount(); if (fifoCount < packetSize ) { return 0; // Not Enough data FIFO Buffer is still considered empty } if (fifoCount > MaxPacketByets ) // We definitely have or will shortly have an overflow problem and need to remove the bytes from the buffer { uint8_t fifoTrash[2 * PACKET_SIZE]; // Trash bin (bit bucket) - just a place to put the removed bytes. Can't be just PACKET_SIZE!

    // option 1
     if(mpu.getFIFOCount()< MAX_FIFO_BYTES){
          mpu.getFIFOBytes(fifoTrash, packetSize); // remove a full packet  then waight to be sure that the packet is written
        delayMicroseconds(200);
        fifoCount = mpu.getFIFOCount();
        ctr++;
     }

// option 2 / while(mpu.getFIFOCount()< MAX_FIFO_BYTES) //We need to make sure the buffer finishes filling which will take less than .2 milliseconds if this is even an issue. { ctr++; // this may not be enough to resolve the error... Option 1 has a delay but we already waited this long what's another 200 microseconds } / if(ctr) Serial.print("We actually detected the very last packet being written into the FIFO Buffer Before it overflowed!"; //once we are sure the buffer is full we can correctly remove the damaged packet. mpu.getFIFOBytes(fifoTrash, (fifoCount % packetSize) + packetSize); //fifoCount -= ((fifoCount % packetSize) + packetSize); //Correcting buffer content length without requesting over i2c saves clock ticks. // or fifoCount = mpu.getFIFOCount(); } more = (fifoCount / packetSize);// because the division is cast to int the remainder is removed even if the packet is being written to right now the last partial packet will be ignored.

  while (more--)// Get each packet until no complete packets remain. A partial packet could still exist.
  {
         mpu.getFIFOBytes(fifoBuffer, packetSize);
         fifoCount -= packetSize;
  }

Serial.println(fifoCount ); // this should be zero unless a partial packet existed at the time we attempted to read the FIFO. return 1; // We have some data for you

So this is my thoughts on how to handle the overflow. If this succeeds then we could use this code without interrupts. it would return true if data is captured. and only return false if you were too early for the next request. This means no more overflow corruption for waiting too long!

Thanks for testing these and correcting my errors It is harder to code directly into this forum and not create any. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T32YYSFLTH3UYZWO3OHTQPARWVA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBPKX2Q#issuecomment-543075306, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T32Z5HMSRYTI7GZPIIXTQPARWVANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, That will be great. I'm still 2-3 days away from directly treating this myself. I'm sure you'll be faster. Homer

paynterf commented 4 years ago

Homer,

I'm not quite sure I understand the intention here. If I understand the situation correctly,

If the above is a complete description of the situation, then I'm not sure why the following algorithm wouldn't work:

  1. call mpu.GetFIFOCount() repeatedly with a delay of 200 uSec between calls, until two subsequent calls get the same results
  2. If fifoCount < packetSize, do nothing
  3. if fifoCount % packetSize != 0 (non-modular) remove (fifoCount % packetSize) + packetSize bytes
  4. call mpu.GetFIFOCount() repeatedly with a delay of 200 uSec between calls, until two subsequent calls get the same results. This should always result in exactly two calls to mpu.getFIFOCount
  5. if fifoCount % packetSize == 0 (i.e. modular), remove all available packets and return. Note that while step 3 may or may not occur, step 5 will always occur whenever fifoCount >= packetSize, even if step 3 does occur and results in a fifoCount of zero.

What am I missing?

I implemented the above algorithm, and ran it for about 20 seconds with no problems. Interestingly, subsequent FIFO counts disagreed fairly often (50 times in 122 sec), as shown in the following plot (the yellow curve is either zero (subsequent FIFO counts agreed the first time) or 1 (it took one additional iteration to achieve agreement). The blue line is the yaw value, with some manual rotations thrown in to demonstrate validity. The FIFO count at the bottom of loop() is either 28 or zero, and the number of interrupts per loop() iteration is pretty steady at 21/22.

[image: 191017_OverflowTest3.jpg]

I've also attached the output log from the run, and the code itself. I'm pretty sure I'm missing something fundamental, but I don't know what it is ;-).

Regards,

Frank

On Thu, Oct 17, 2019 at 10:10 AM Homer Creutz notifications@github.com wrote:

Frank, That will be great. I'm still 2-3 days away from directly treating this myself. I'm sure you'll be faster. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T325RTVNM6GWAGHZEPT3QPBW4XA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBQHNMI#issuecomment-543192753, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323YIRKBVL2DE3SEMGDQPBW4XANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

void loop() { delay(LOOP_DELAY_MSEC); // if programming failed, don't try to do anything if (!dmpReady) return;

//// wait for MPU interrupt or extra packet(s) available
//while (!mpuInterrupt && fifoCount < packetSize) 
//{
//  if (mpuInterrupt && fifoCount < packetSize) 
//  {
//      // try to get out of the infinite loop 
//      fifoCount = mpu.getFIFOCount();
//  }
//  // other program behavior stuff here
//}

// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();

//10/17/19 Homer's new FIFO management code
int more;
int ctr;
static int MaxPackets = MAX_FIFO_BYTES / packetSize;
static int MaxPacketBytes = MaxPackets * packetSize;

//Step 1: call mpu.GetFIFOCount() repeatedly with a delay of 200 uSec between calls, until two subsequent calls get the same results
//Step 2: If fifoCount < packetSize, do nothing
//Step 3: if fifoCount % packetSize != 0 (non - modular) remove(fifoCount % packetSize) + packetSize bytes
//Step 4: call mpu.GetFIFOCount() repeatedly with a delay of 200 uSec between calls, until two subsequent calls get the same results (should always be exactly two calls).
//Step 5: if fifoCount % packetSize == 0 (i.e.modular), remove all available packets and return.
//Notes:
//  Note that while step 3 may or may not occur, step 5 will always occur whenever fifoCount >= packetSize, even if step 3 does occur and results in a fifoCount of zero.fifoCount = mpu.getFIFOCount();

//Step1: call mpu.GetFIFOCount() repeatedly with a delay of 200 uSec between calls, until two subsequent calls get the same results fifoCount = mpu.getFIFOCount(); delayMicroseconds(200); int fifoCount2 = mpu.getFIFOCount(); ctr = 0; while (fifoCount != fifoCount2) { fifoCount = mpu.getFIFOCount(); delayMicroseconds(200); fifoCount2 = mpu.getFIFOCount();

    ctr++;

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

//Step2: If fifoCount < packetSize, do nothing if (fifoCount < packetSize) { return; }

//Step3: if fifoCount % packetSize != 0 (non - modular) remove(fifoCount % packetSize) + packetSize bytes if (fifoCount % packetSize != 0) { uint8_t fifoTrash[2 * PACKET_SIZE]; // Trash bin (bit bucket) - just a place to put the removed bytes. Can't be just PACKET_SIZE!

}

if (fifoCount < packetSize)
{
    return; // Not Enough data FIFO Buffer is still considered empty
}

if (fifoCount >= MaxPacketBytes) // We definitely have or will shortly have an overflow problem and need to remove at least one packet from the buffer
{
    uint8_t fifoTrash[2 * PACKET_SIZE]; // Trash bin (bit bucket) - just a place to put the removed bytes. Can't be just PACKET_SIZE!
    mpu.getFIFOBytes(fifoTrash, (fifoCount % packetSize) + packetSize);
    fifoCount = mpu.getFIFOCount();
    delayMicroseconds(200);
    fifoCount = mpu.getFIFOCount();
}

//Step4: call mpu.GetFIFOCount() repeatedly with a delay of 200 uSec between calls, until two subsequent calls get the same results (should always be exactly two calls).

//Step5: if fifoCount % packetSize == 0 (i.e.modular), remove all available packets and return. more = (fifoCount / packetSize);

while (more--)// Get each packet until no complete packets remain. A partial packet could still exist.
{
    mpu.getFIFOBytes(fifoBuffer, packetSize);
    fifoCount -= packetSize;
}

// display Euler angles in degrees
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
float yaw = ypr[0] * 180 / M_PI;

mySerial.printf("%lu\t%3.2f\t%d\t%d\t%d\n", millis(), yaw, num_interrupts,mpu.getFIFOCount(), ctr);

num_interrupts = 0; //reset the interrupt counter (added for overflow testing)

//// blink LED to indicate activity
//blinkState = !blinkState;
//digitalWrite(LED_PIN, blinkState);

}

ZHomeSlice commented 4 years ago

Frank, My thoughts

a FIFO count == MAX_FIFO_BYTES is also a certain indicator of FIFO overflow

My thoughts for getting all Good Packets during non-overflow conditions:

//No Corruption has occurred at this time. or we have resolved any overflow conditions and are left with a good first packet. The last packet may or may not be complete and that is ok.
// How many full good packets do we have
      more = (int) (fifoCount / packetSize);// typecast to int to remove decimal rounding down
      more--;  // Added this as a thought on how to quickly get to the last packet
/**************     UPDATE     **************/
      for (uint8_t k = 0; k < more*packetSize ; k++) { 
          // MPU6050 has a getFIFOBytes function without any attributes We are using this to dump old packets. There is no advantage in creating a large holding buffer to store the data so I updated this routine.
           mpu.getFIFOBytes( ); // remove one byte at a time up to the last complete packet quickly 
      }
/************** END UPDATE **************/
      fifoCount = mpu.getFIFOCount(); //if we want to get the absolute last packet no matter what the next two lines are important.
      more = (int) (fifoCount / packetSize);// How many packets do we have now? We might as well test to see if we have finished another packet. typecast to int to remove decimal rounding down. If a new packet is just now being written we will ignore it.
      while (more--)// Get each packet until no complete packets remain.
      {
             mpu.getFIFOBytes(fifoBuffer, packetSize);
             fifoCount -= packetSize;
      }

// The Test
if(fifoCount > 0) Serial.print("We left a partial packet behind");

Out of time... I will try again later to create a routine that works with overflow.

Homer

ZHomeSlice commented 4 years ago

Good Morning Frank, This is a tough nut to crack. I keep on overthinking the overflow issue. First lets gathering more data as every MPU 6050, 9150, 6500, 9250 and V2 vs V6.12 can have different settings. In the V6.12 code, we have the definition of the Packet Size the commented portion is directly from the invensense example code. When you are using their code you can change the buffer size and restart the DMP at any time. but for us, we need the space so it is fixed to the following setup:

/*
    packetSize+= 16;//DMP_FEATURE_6X_LP_QUAT
    packetSize+= 6;//DMP_FEATURE_SEND_RAW_ACCEL
    packetSize+= 6;//DMP_FEATURE_SEND_RAW_GYRO
*/
    packetSize= 28;

in my version Simple_MPU6050 i define the MAX_FIFO_BYTES uaing a fixed value of 512

MAX_FIFO_BYTES = floor(512 / packetSize);

I do not see any location where I am sure this is the buffer size. my concern is that if we test this without checking the byte in the MPU6050 we may never know for sure and we could incorrectly trim the buffer creating corrupted data. What I do differently is that if there is a corrupted buffer I automatically scrap it so I don't care if it has overflowed. In your case, we are waiting for a long time for other code to complete with a high probability of an overflow each time. We need to know this value for sure but It may be different for each instance as it is a part of the MPU6050's buffer that the DMP source code is stored in. and each MPU6050, MPU9250, etc. may have a different buffer size.

My thoughts: As part of setup we need discover these values before moving forward:

MAX_PACKETS = floor(1024 / packet_length); //assumed default
mpu.resetFIFO();
  unsigned long Timer;
  Timer = millis();
  while ((millis() - Timer) >= ((MAX_PACKETS * 10) + 10)) { // minimum time needed to absolutly generate an overflow
//While we are waiting Lets detect the MAX duration of the FIFO buffer write:
       unsigned long ErrorStart;
       unsigned long ErrorEnd;
       int Flag = 0;
       int ctr = 0;
       if(ctr++ <= 10){ // 10 samples should be good without overflowing which would cause the results to become corrupted and lock us into an infinate loop.
          ErrorStart = micros();
         while(mpu.getFIFOCount() %  packetSize)
         {
              ErrorEnd = micros();
              Flag = 1;
         }
         if(Flag)
         {
               MAX_FIFO_WRITE_DURATION = max(ErrorEnd - ErrorStart);
               Flag = 0;
         }
      }
      else 
      {  // We have the data so lets bail as soon as we have an overflow
               mpuIntStatus = mpu.getIntStatus();
               if(mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) 
               {
                        break;
               }
      }
  }
mpuIntStatus = mpu.getIntStatus();
if(mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT))
{
   // We have Filled the FIFO buffer and overflowed so we can get the following values and know that we are good
  MAX_FIFO_BYTES  = mpu.getFIFOCount();
  MAX_PACKETS = floor(MAX_FIFO_BYTES  / packetSize);
  MAX_PACKET_BYTES = MAX_PACKETS * packetSize;
  OVERFLOWED_PARTIAL_PACKET_SIZE = MAX_FIFO_BYTES  - MAX_PACKET_BYTES;
}

Now is the fun part... I need to think about this more. To Be Continued :) Homer

ZHomeSlice commented 4 years ago

Frank, I'm back at my computer Take a peek at this code

  mpu.resetFIFO();
  int Flag = 0;
  int ctr = 0;
  int x,y;
  while (1) {
    x = mpu.getFIFOCount() %  packetSize;
    if (x) {
      y = mpu.getFIFOCount() %  packetSize;
      Serial.print(x);
      Serial.print(",");
      if (y) {
        mpuIntStatus = mpu.getIntStatus();
        if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) {
          Serial.print("Overflow");
          Serial.println(y);
            mpu.resetFIFO();
        } else if (y) { // the Packet is not complete after second test
          Serial.println("*** Error ***");
        }
      } Serial.println();

    }else Serial.print(".");
  }

it shows you when a packet is partially written and when overflow occurs when a packet is partially written we can see the byte count in the packet. not that checking the FIFO count immediately after detecting a partial packet, the packet will have been completed so there is no major delay. Homer

paynterf commented 4 years ago

Homer,

Here's an initial log from the run using your code. I'm going to edit the code a bit for a nicer output...

Frank

On Sun, Oct 20, 2019 at 7:14 PM Homer Creutz notifications@github.com wrote:

Frank, I'm back at my computer Take a peek at this code

mpu.resetFIFO(); int Flag = 0; int ctr = 0; int x,y; while (1) { x = mpu.getFIFOCount() % packetSize; if (x) { y = mpu.getFIFOCount() % packetSize; Serial.print(x); Serial.print(","); if (y) { mpuIntStatus = mpu.getIntStatus(); if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) { Serial.print("Overflow"); Serial.println(y); mpu.resetFIFO(); } else if (y) { // the Packet is not complete after second test Serial.println(" Error "); } } Serial.println();

}else Serial.print(".");

}

it shows you when a packet is partially written and when overflow occurs when a packet is partially written we can see the byte count in the packet. not that checking the FIFO count immediately after detecting a partial packet, the packet will have been completed so there is no major delay. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T3272736AVIUBLRKHCGLQPTQ4JA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBYWNOI#issuecomment-544302777, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327J7UTFXRU7RFSIPUDQPTQ4JANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

paynterf commented 4 years ago

Homer,

BTW, something you said earlier, about being able to modify the buffer length. If that's the case, why should we EVER have packet corruption due to buffer overflow - just make the buffer length an integral multiple of the packet length to start with, and the problem goes away entirely.

Am I missing something?

Frank

On Sun, Oct 20, 2019 at 8:26 PM Frank Paynter paynterf@gmail.com wrote:

Homer,

Here's an initial log from the run using your code. I'm going to edit the code a bit for a nicer output...

Frank

On Sun, Oct 20, 2019 at 7:14 PM Homer Creutz notifications@github.com wrote:

Frank, I'm back at my computer Take a peek at this code

mpu.resetFIFO(); int Flag = 0; int ctr = 0; int x,y; while (1) { x = mpu.getFIFOCount() % packetSize; if (x) { y = mpu.getFIFOCount() % packetSize; Serial.print(x); Serial.print(","); if (y) { mpuIntStatus = mpu.getIntStatus(); if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) { Serial.print("Overflow"); Serial.println(y); mpu.resetFIFO(); } else if (y) { // the Packet is not complete after second test Serial.println(" Error "); } } Serial.println();

}else Serial.print(".");

}

it shows you when a packet is partially written and when overflow occurs when a packet is partially written we can see the byte count in the packet. not that checking the FIFO count immediately after detecting a partial packet, the packet will have been completed so there is no major delay. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T3272736AVIUBLRKHCGLQPTQ4JA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBYWNOI#issuecomment-544302777, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327J7UTFXRU7RFSIPUDQPTQ4JANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

I wish it were that simple. I haven't figured out how to modify the FIFO buffer length. I believe it is hardcoded into the DMP and without better documentation... Well, I haven't seen any way :)

BUT with that said

Here you go an overflow proof function GetCurrentFIFOPacket() to get the latest packet no matter how long the delay.

// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================
// Returns 1) when nothing special was done 
//         2) when recovering from overflow 
//         0) when no valid data is available
// ================================================================
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
  uint8_t Error;
  int8_t more;
  uint8_t Flag = 0;
  uint8_t overflowed = 0;
  do {
    if (Error = (fifoCount = mpu.getFIFOCount()) %  length) {
      if (Error = (fifoCount = mpu.getFIFOCount()) %  length) {
        mpuIntStatus = mpu.getIntStatus();
        if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) {
          mpu.getFIFOBytes(fifoBuffer, Error); // lets remove the overflow portion
          mpu.getFIFOBytes(fifoBuffer, length);
          overflowed = 1;
          if (Error = (fifoCount = mpu.getFIFOCount()) %  length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space
            mpu.getFIFOBytes(fifoBuffer, Error); // lets remove the overflow portion again
            if ((fifoCount = mpu.getFIFOCount()) %  length) {
              mpu.resetFIFO();
              Serial.println("Failed to recover overflow error");
              return 0;
            }
          }
        }
      }
    }
    fifoCount = mpu.getFIFOCount();
    if (fifoCount >= packetSize) {
      mpu.getFIFOBytes(fifoBuffer, length);
      Flag = 1 + overflowed;
      fifoCount -= packetSize;
    }
  } while (fifoCount >= packetSize);
  return Flag;
}

I have results from a delay that places is right at the overflow point and I shift the delay() cycleing between 175 and 179 milliseconds for my test program. Here are the results: Note Flag and Status are the same. If Flag is 2 then we are recovering from the overflow event. else we bearly caught it before the overflow. This is where I discovered all the glitching and I had to do the do{...}while(); to retest for errors especially at the exact moment when we were approching the overflow. and I am sure it would happen at other times just as a packet was to be written.

178 Flag = 2 Status = 2ypr  -2.48   -0.16   -0.07
179 Flag = 1 Status = 1ypr  -2.48   -0.16   -0.07
175 Flag = 1 Status = 1ypr  -2.48   -0.14   -0.07
176 Flag = 1 Status = 1ypr  -2.49   -0.15   -0.06
177 Flag = 1 Status = 1ypr  -2.49   -0.14   -0.07
178 Flag = 2 Status = 2ypr  -2.50   -0.14   -0.07
179 Flag = 2 Status = 2ypr  -2.50   -0.14   -0.07
175 Flag = 1 Status = 1ypr  -2.50   -0.14   -0.07
176 Flag = 1 Status = 1ypr  -2.50   -0.14   -0.07
177 Flag = 1 Status = 1ypr  -2.50   -0.14   -0.07
178 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.06
179 Flag = 2 Status = 2ypr  -2.50   -0.14   -0.07
175 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.07
176 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.07
177 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.07
178 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.07
179 Flag = 2 Status = 2ypr  -2.50   -0.13   -0.07
175 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.07
176 Flag = 2 Status = 2ypr  -2.50   -0.13   -0.06
177 Flag = 2 Status = 2ypr  -2.50   -0.13   -0.07
178 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.08
179 Flag = 1 Status = 1ypr  -2.49   -0.13   -0.07
175 Flag = 1 Status = 1ypr  -2.50   -0.13   -0.08
176 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.08
177 Flag = 2 Status = 2ypr  -2.49   -0.13   -0.08
178 Flag = 2 Status = 2ypr  -2.48   -0.13   -0.08
179 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.08
175 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.08
176 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.08
177 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
178 Flag = 2 Status = 2ypr  -2.48   -0.13   -0.07
179 Flag = 1 Status = 1ypr  -2.48   -0.14   -0.07
175 Flag = 1 Status = 1ypr  -2.48   -0.14   -0.07
176 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
177 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
178 Flag = 2 Status = 2ypr  -2.47   -0.13   -0.07
179 Flag = 2 Status = 2ypr  -2.48   -0.14   -0.07
175 Flag = 1 Status = 1ypr  -2.48   -0.14   -0.07
176 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
177 Flag = 1 Status = 1ypr  -2.48   -0.14   -0.06
178 Flag = 1 Status = 1ypr  -2.48   -0.14   -0.06
179 Flag = 2 Status = 2ypr  -2.48   -0.14   -0.07
175 Flag = 1 Status = 1ypr  -2.47   -0.15   -0.06
176 Flag = 1 Status = 1ypr  -2.47   -0.15   -0.07
177 Flag = 1 Status = 1ypr  -2.47   -0.15   -0.06
178 Flag = 1 Status = 1ypr  -2.47   -0.15   -0.06
179 Flag = 2 Status = 2ypr  -2.48   -0.16   -0.06
175 Flag = 1 Status = 1ypr  -2.47   -0.16   -0.06
176 Flag = 2 Status = 2ypr  -2.47   -0.16   -0.06
177 Flag = 2 Status = 2ypr  -2.47   -0.16   -0.06
178 Flag = 1 Status = 1ypr  -2.47   -0.16   -0.06
179 Flag = 1 Status = 1ypr  -2.47   -0.16   -0.06
175 Flag = 1 Status = 1ypr  -2.47   -0.15   -0.06
176 Flag = 1 Status = 1ypr  -2.47   -0.15   -0.06
177 Flag = 2 Status = 2ypr  -2.47   -0.14   -0.05
178 Flag = 2 Status = 2ypr  -2.48   -0.13   -0.07
179 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
175 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
176 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
177 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
178 Flag = 2 Status = 2ypr  -2.48   -0.13   -0.07
179 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
175 Flag = 1 Status = 1ypr  -2.48   -0.13   -0.07
176 Flag = 1 Status = 1ypr  -2.49   -0.13   -0.07
177 Flag = 1 Status = 1ypr  -2.49   -0.13   -0.06

I appriciate your skills in testing this. Let me knowof your results and especially if you discover any glitches. Homer

paynterf commented 4 years ago

Oops - sorry - I guess I misinterpreted what you said ;-(. Your data looks good - I'll get back to you as I can. In the meantime, here are some results from your previous code

[image: 102019_MsecBetweenDet.jpg] [image: 102019_Non-modularCountsVsTime.jpg]

Interesting that '16' seems to be a very popular number when a non-modular count is detected. I'm sure there is some clever explanation for this, but I have no clue what it is. Maybe it is some sort of 'beat note' between the FIFO rate and the Arduino loop cycle time? Same thing with the time between directions (note that the 'zeros' in this plot are the result of the situation where the non-modular count persists after the second getFIFOCount() call).

Raw data attached.

Frank

On Sun, Oct 20, 2019 at 9:19 PM Homer Creutz notifications@github.com wrote:

I wish it were that simple. I haven't figured out how to modify the FIFO buffer length. I believe it is hardcoded into the DMP and without better documentation... Well, I haven't seen any way :)

BUT with that said

Here you go an overflow proof function GetCurrentFIFOPacket() to get the latest packet no matter how long the delay.

// ================================================================ // === INTERRUPT DETECTION ROUTINE === // ================================================================ // Returns 1) when nothing special was done // 2) when recovering from overflow // 0) when no valid data is available // ================================================================ uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint8_t Error; int8_t more; uint8_t Flag = 0; uint8_t overflowed = 0; do { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { mpuIntStatus = mpu.getIntStatus(); if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) { mpu.getFIFOBytes(fifoBuffer, Error); // lets remove the overflow portion mpu.getFIFOBytes(fifoBuffer, length); overflowed = 1; if (Error = (fifoCount = mpu.getFIFOCount()) % length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space mpu.getFIFOBytes(fifoBuffer, Error); // lets remove the overflow portion again if ((fifoCount = mpu.getFIFOCount()) % length) { mpu.resetFIFO(); Serial.println("Failed to recover overflow error"); return 0; } } } } } fifoCount = mpu.getFIFOCount(); if (fifoCount >= packetSize) { mpu.getFIFOBytes(fifoBuffer, length); Flag = 1 + overflowed; fifoCount -= packetSize; } } while (fifoCount >= packetSize); return Flag; }

I have results from a delay that places is right at the overflow point and I shift the delay() cycleing between 175 and 179 milliseconds for my test program. Here are the results: Note Flag and Status are the same. If Flag is 2 then we are recovering from the overflow event. else we bearly caught it before the overflow. This is where I discovered all the glitching and I had to do the do{...}while(); to retest for errors especially at the exact moment when we were approching the overflow. and I am sure it would happen at other times just as a packet was to be written.

178 Flag = 2 Status = 2ypr -2.48 -0.16 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.16 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.49 -0.15 -0.06 177 Flag = 1 Status = 1ypr -2.49 -0.14 -0.07 178 Flag = 2 Status = 2ypr -2.50 -0.14 -0.07 179 Flag = 2 Status = 2ypr -2.50 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.50 -0.14 -0.07 177 Flag = 1 Status = 1ypr -2.50 -0.14 -0.07 178 Flag = 1 Status = 1ypr -2.50 -0.13 -0.06 179 Flag = 2 Status = 2ypr -2.50 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 176 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 178 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 179 Flag = 2 Status = 2ypr -2.50 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 176 Flag = 2 Status = 2ypr -2.50 -0.13 -0.06 177 Flag = 2 Status = 2ypr -2.50 -0.13 -0.07 178 Flag = 1 Status = 1ypr -2.50 -0.13 -0.08 179 Flag = 1 Status = 1ypr -2.49 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.13 -0.08 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 177 Flag = 2 Status = 2ypr -2.49 -0.13 -0.08 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.08 179 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 175 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 177 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 178 Flag = 2 Status = 2ypr -2.47 -0.13 -0.07 179 Flag = 2 Status = 2ypr -2.48 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.48 -0.14 -0.06 178 Flag = 1 Status = 1ypr -2.48 -0.14 -0.06 179 Flag = 2 Status = 2ypr -2.48 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 176 Flag = 1 Status = 1ypr -2.47 -0.15 -0.07 177 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 178 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 179 Flag = 2 Status = 2ypr -2.48 -0.16 -0.06 175 Flag = 1 Status = 1ypr -2.47 -0.16 -0.06 176 Flag = 2 Status = 2ypr -2.47 -0.16 -0.06 177 Flag = 2 Status = 2ypr -2.47 -0.16 -0.06 178 Flag = 1 Status = 1ypr -2.47 -0.16 -0.06 179 Flag = 1 Status = 1ypr -2.47 -0.16 -0.06 175 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 176 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 177 Flag = 2 Status = 2ypr -2.47 -0.14 -0.05 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 176 Flag = 1 Status = 1ypr -2.49 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.49 -0.13 -0.06

I appriciate your skills in testing this. Let me knowof your results and especially if you discover any glitches. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T326E4RPVUFJLS3XIHLLQPT7TFA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBYZJNA#issuecomment-544314548, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T3253P4SJT7BB5WCZNDTQPT7TFANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

paynterf commented 4 years ago

Homer,

doesn't look like 'uint8_t data' is being used in the function. Is the 'fifoBuffer' variable defined as 'uint8_t ' external to this function, as we have been doing to date?

How 'bout an example calling snippet? ;-).

Frank

On Sun, Oct 20, 2019 at 9:45 PM Frank Paynter paynterf@gmail.com wrote:

Oops - sorry - I guess I misinterpreted what you said ;-(. Your data looks good - I'll get back to you as I can. In the meantime, here are some results from your previous code

[image: 102019_MsecBetweenDet.jpg] [image: 102019_Non-modularCountsVsTime.jpg]

Interesting that '16' seems to be a very popular number when a non-modular count is detected. I'm sure there is some clever explanation for this, but I have no clue what it is. Maybe it is some sort of 'beat note' between the FIFO rate and the Arduino loop cycle time? Same thing with the time between directions (note that the 'zeros' in this plot are the result of the situation where the non-modular count persists after the second getFIFOCount() call).

Raw data attached.

Frank

On Sun, Oct 20, 2019 at 9:19 PM Homer Creutz notifications@github.com wrote:

I wish it were that simple. I haven't figured out how to modify the FIFO buffer length. I believe it is hardcoded into the DMP and without better documentation... Well, I haven't seen any way :)

BUT with that said

Here you go an overflow proof function GetCurrentFIFOPacket() to get the latest packet no matter how long the delay.

// ================================================================ // === INTERRUPT DETECTION ROUTINE === // ================================================================ // Returns 1) when nothing special was done // 2) when recovering from overflow // 0) when no valid data is available // ================================================================ uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint8_t Error; int8_t more; uint8_t Flag = 0; uint8_t overflowed = 0; do { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { mpuIntStatus = mpu.getIntStatus(); if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) { mpu.getFIFOBytes(fifoBuffer, Error); // lets remove the overflow portion mpu.getFIFOBytes(fifoBuffer, length); overflowed = 1; if (Error = (fifoCount = mpu.getFIFOCount()) % length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space mpu.getFIFOBytes(fifoBuffer, Error); // lets remove the overflow portion again if ((fifoCount = mpu.getFIFOCount()) % length) { mpu.resetFIFO(); Serial.println("Failed to recover overflow error"); return 0; } } } } } fifoCount = mpu.getFIFOCount(); if (fifoCount >= packetSize) { mpu.getFIFOBytes(fifoBuffer, length); Flag = 1 + overflowed; fifoCount -= packetSize; } } while (fifoCount >= packetSize); return Flag; }

I have results from a delay that places is right at the overflow point and I shift the delay() cycleing between 175 and 179 milliseconds for my test program. Here are the results: Note Flag and Status are the same. If Flag is 2 then we are recovering from the overflow event. else we bearly caught it before the overflow. This is where I discovered all the glitching and I had to do the do{...}while(); to retest for errors especially at the exact moment when we were approching the overflow. and I am sure it would happen at other times just as a packet was to be written.

178 Flag = 2 Status = 2ypr -2.48 -0.16 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.16 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.49 -0.15 -0.06 177 Flag = 1 Status = 1ypr -2.49 -0.14 -0.07 178 Flag = 2 Status = 2ypr -2.50 -0.14 -0.07 179 Flag = 2 Status = 2ypr -2.50 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.50 -0.14 -0.07 177 Flag = 1 Status = 1ypr -2.50 -0.14 -0.07 178 Flag = 1 Status = 1ypr -2.50 -0.13 -0.06 179 Flag = 2 Status = 2ypr -2.50 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 176 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 178 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 179 Flag = 2 Status = 2ypr -2.50 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.13 -0.07 176 Flag = 2 Status = 2ypr -2.50 -0.13 -0.06 177 Flag = 2 Status = 2ypr -2.50 -0.13 -0.07 178 Flag = 1 Status = 1ypr -2.50 -0.13 -0.08 179 Flag = 1 Status = 1ypr -2.49 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.50 -0.13 -0.08 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 177 Flag = 2 Status = 2ypr -2.49 -0.13 -0.08 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.08 179 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 175 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.08 177 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 178 Flag = 2 Status = 2ypr -2.47 -0.13 -0.07 179 Flag = 2 Status = 2ypr -2.48 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.14 -0.07 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.48 -0.14 -0.06 178 Flag = 1 Status = 1ypr -2.48 -0.14 -0.06 179 Flag = 2 Status = 2ypr -2.48 -0.14 -0.07 175 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 176 Flag = 1 Status = 1ypr -2.47 -0.15 -0.07 177 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 178 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 179 Flag = 2 Status = 2ypr -2.48 -0.16 -0.06 175 Flag = 1 Status = 1ypr -2.47 -0.16 -0.06 176 Flag = 2 Status = 2ypr -2.47 -0.16 -0.06 177 Flag = 2 Status = 2ypr -2.47 -0.16 -0.06 178 Flag = 1 Status = 1ypr -2.47 -0.16 -0.06 179 Flag = 1 Status = 1ypr -2.47 -0.16 -0.06 175 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 176 Flag = 1 Status = 1ypr -2.47 -0.15 -0.06 177 Flag = 2 Status = 2ypr -2.47 -0.14 -0.05 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 176 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 178 Flag = 2 Status = 2ypr -2.48 -0.13 -0.07 179 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 175 Flag = 1 Status = 1ypr -2.48 -0.13 -0.07 176 Flag = 1 Status = 1ypr -2.49 -0.13 -0.07 177 Flag = 1 Status = 1ypr -2.49 -0.13 -0.06

I appriciate your skills in testing this. Let me knowof your results and especially if you discover any glitches. Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T326E4RPVUFJLS3XIHLLQPT7TFA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBYZJNA#issuecomment-544314548, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T3253P4SJT7BB5WCZNDTQPT7TFANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Oops, your right change fifoBuffer to data this will allow the function to not use globals. I just made it into a function so that I can shortly add it to the library and it is easier to share here.

paynterf commented 4 years ago

Homer,

I made the changes and made a few runs at different delays. I had to get my delay into the 350-370 mSec range to get anything but '1' returns from your function.

Here's the data and the .ino file that produced them.

Regards,

Frank

On Sun, Oct 20, 2019 at 11:14 PM Homer Creutz notifications@github.com wrote:

Oops, your right change fifoBuffer to data this will allow the function to not use globals. I just made it into a function so that I can shortly add it to the library and it is easier to share here.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T32ZXMNJPOAPKTKTFYH3QPUM7VA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEBY5T4Y#issuecomment-544332275, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323BEZ53VS6XPL5Q4ETQPUM7VANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, Here is an example

// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================
// Returns 1) when nothing special was done 
//         2) when recovering from overflow 
//         0) when no valid data is available
// ================================================================
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
  uint8_t Error;
  int8_t more;
  uint8_t Flag = 0;
  uint8_t overflowed = 0;
  do {
    if (Error = (fifoCount = mpu.getFIFOCount()) %  length) {
      if (Error = (fifoCount = mpu.getFIFOCount()) %  length) {
        mpuIntStatus = mpu.getIntStatus();
        if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) {
          mpu.getFIFOBytes(data, Error); // lets remove the overflow portion
          mpu.getFIFOBytes(data, length);
          overflowed = 1;
          if (Error = (fifoCount = mpu.getFIFOCount()) %  length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space
            mpu.getFIFOBytes(data, Error); // lets remove the overflow portion again
            if ((fifoCount = mpu.getFIFOCount()) %  length) {
              mpu.resetFIFO();
              Serial.println("Failed to recover overflow error");
              return 0;
            }
          }
        }
      }
    }
    fifoCount = mpu.getFIFOCount();
    if (fifoCount >= packetSize) {
      mpu.getFIFOBytes(data, length);
      Flag = 1 + overflowed;
      fifoCount -= packetSize;
    }
  } while (fifoCount >= packetSize);
    Serial.print(" Flag = ");
  Serial.print(Flag);
  return Flag;
}

// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================
int dx = 100 ;
int retval;
void loop() {
  delay(dx++); // I am using the delay to discover the exact moment we overflow and cycle around this point as this is where the errors I struggled with were generated
  Serial.print(dx);
  if (!(retval = GetCurrentFIFOPacket(fifoBuffer, packetSize))) return;
  /*
   * 0 = no data return
   * 1 = normal data no overflow recovery needed
   * 2 = normal data but overflow occured and we recovered
   * fifoBuffer contains the data
   */
  Serial.print(" Status = ");
  Serial.print(retval);
    Serial.print(" ");
  if(retval == 2) dx = dx - 2; 

  // display Euler angles in degrees
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  Serial.print("ypr\t");
  Serial.print(ypr[0] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[1] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[2] * 180 / M_PI);
  /*
    mpu.dmpGetAccel(&aa, fifoBuffer);
    Serial.print("\tRaw Accl XYZ\t");
    Serial.print(aa.x);
    Serial.print("\t");
    Serial.print(aa.y);
    Serial.print("\t");
    Serial.print(aa.z);
    mpu.dmpGetGyro(&gy, fifoBuffer);
    Serial.print("\tRaw Gyro XYZ\t");
    Serial.print(gy.x);
    Serial.print("\t");
    Serial.print(gy.y);
    Serial.print("\t");
    Serial.print(gy.z);
  */
  Serial.println();
  // blink LED to indicate activity
  blinkState = !blinkState;
  digitalWrite(LED_PIN, blinkState);

}

Hope this helps Homer

paynterf commented 4 years ago

Homer,

I think our emails crossed ;-)

Frank

On Mon, Oct 21, 2019 at 12:55 PM Homer Creutz notifications@github.com wrote:

Frank, Here is an example

// ================================================================ // === INTERRUPT DETECTION ROUTINE === // ================================================================ // Returns 1) when nothing special was done // 2) when recovering from overflow // 0) when no valid data is available // ================================================================ uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint8_t Error; int8_t more; uint8_t Flag = 0; uint8_t overflowed = 0; do { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { mpuIntStatus = mpu.getIntStatus(); if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) { mpu.getFIFOBytes(data, Error); // lets remove the overflow portion mpu.getFIFOBytes(data, length); overflowed = 1; if (Error = (fifoCount = mpu.getFIFOCount()) % length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space mpu.getFIFOBytes(data, Error); // lets remove the overflow portion again if ((fifoCount = mpu.getFIFOCount()) % length) { mpu.resetFIFO(); Serial.println("Failed to recover overflow error"); return 0; } } } } } fifoCount = mpu.getFIFOCount(); if (fifoCount >= packetSize) { mpu.getFIFOBytes(data, length); Flag = 1 + overflowed; fifoCount -= packetSize; } } while (fifoCount >= packetSize); Serial.print(" Flag = "); Serial.print(Flag); return Flag; }

// ================================================================ // === MAIN PROGRAM LOOP === // ================================================================ int dx = 100 ; int z; void loop() { delay(dx++); Serial.print(dx); if (!(z = GetCurrentFIFOPacket(fifoBuffer, packetSize))) return; /*

  • 0 = no data return
  • 1 = normal data no overflow recovery needed
  • 2 = normal data but overflow occured and we recovered
  • fifoBuffer contains the data */ Serial.print(" Status = "); Serial.print(z); Serial.print(" "); if(z == 2) dx = dx - 2;

    // display Euler angles in degrees mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); Serial.print("ypr\t"); Serial.print(ypr[0] 180 / M_PI); Serial.print("\t"); Serial.print(ypr[1] 180 / M_PI); Serial.print("\t"); Serial.print(ypr[2] 180 / M_PI); / mpu.dmpGetAccel(&aa, fifoBuffer); Serial.print("\tRaw Accl XYZ\t"); Serial.print(aa.x); Serial.print("\t"); Serial.print(aa.y); Serial.print("\t"); Serial.print(aa.z); mpu.dmpGetGyro(&gy, fifoBuffer); Serial.print("\tRaw Gyro XYZ\t"); Serial.print(gy.x); Serial.print("\t"); Serial.print(gy.y); Serial.print("\t"); Serial.print(gy.z); */ Serial.println(); // blink LED to indicate activity blinkState = !blinkState; digitalWrite(LED_PIN, blinkState);

}

Hope this helps Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T324VLK2KKQASXDHPQJDQPXNHPA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEB3AZUA#issuecomment-544607440, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323UKJKFDLJASYLTEYLQPXNHPANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

paynterf commented 4 years ago

Homer,

I think it might be useful at this point to try and summarize where I think we are at the moment

I have also updated my blog post with the above summary.

So, where do we go from here? I'm happy in that I am now very confident that I can use my MPU6050 installations in both my wall-following robots and expect to get valid results even with the 100-200 mSec total loop delay times used. However, I still don't quite understand why the 'just-overflowed' loop delay in my configuration seems to be twice yours, or where the factor of 2 comes in regarding the reported buffer length vs the interrupts x packet length calculation. Can you shed any light on those issues?

And, I have to say this has been a very enjoyable collaboration so far. If we ever meet up in RL, I'd like to buy you a beer!

Frank

On Mon, Oct 21, 2019 at 1:38 PM Frank Paynter paynterf@gmail.com wrote:

Homer,

I think our emails crossed ;-)

Frank

On Mon, Oct 21, 2019 at 12:55 PM Homer Creutz notifications@github.com wrote:

Frank, Here is an example

// ================================================================ // === INTERRUPT DETECTION ROUTINE === // ================================================================ // Returns 1) when nothing special was done // 2) when recovering from overflow // 0) when no valid data is available // ================================================================ uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint8_t Error; int8_t more; uint8_t Flag = 0; uint8_t overflowed = 0; do { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { if (Error = (fifoCount = mpu.getFIFOCount()) % length) { mpuIntStatus = mpu.getIntStatus(); if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) { mpu.getFIFOBytes(data, Error); // lets remove the overflow portion mpu.getFIFOBytes(data, length); overflowed = 1; if (Error = (fifoCount = mpu.getFIFOCount()) % length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space mpu.getFIFOBytes(data, Error); // lets remove the overflow portion again if ((fifoCount = mpu.getFIFOCount()) % length) { mpu.resetFIFO(); Serial.println("Failed to recover overflow error"); return 0; } } } } } fifoCount = mpu.getFIFOCount(); if (fifoCount >= packetSize) { mpu.getFIFOBytes(data, length); Flag = 1 + overflowed; fifoCount -= packetSize; } } while (fifoCount >= packetSize); Serial.print(" Flag = "); Serial.print(Flag); return Flag; }

// ================================================================ // === MAIN PROGRAM LOOP === // ================================================================ int dx = 100 ; int z; void loop() { delay(dx++); Serial.print(dx); if (!(z = GetCurrentFIFOPacket(fifoBuffer, packetSize))) return; /*

  • 0 = no data return
  • 1 = normal data no overflow recovery needed
  • 2 = normal data but overflow occured and we recovered
  • fifoBuffer contains the data */ Serial.print(" Status = "); Serial.print(z); Serial.print(" "); if(z == 2) dx = dx - 2;

    // display Euler angles in degrees mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); Serial.print("ypr\t"); Serial.print(ypr[0] 180 / M_PI); Serial.print("\t"); Serial.print(ypr[1] 180 / M_PI); Serial.print("\t"); Serial.print(ypr[2] 180 / M_PI); / mpu.dmpGetAccel(&aa, fifoBuffer); Serial.print("\tRaw Accl XYZ\t"); Serial.print(aa.x); Serial.print("\t"); Serial.print(aa.y); Serial.print("\t"); Serial.print(aa.z); mpu.dmpGetGyro(&gy, fifoBuffer); Serial.print("\tRaw Gyro XYZ\t"); Serial.print(gy.x); Serial.print("\t"); Serial.print(gy.y); Serial.print("\t"); Serial.print(gy.z); */ Serial.println(); // blink LED to indicate activity blinkState = !blinkState; digitalWrite(LED_PIN, blinkState);

}

Hope this helps Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T324VLK2KKQASXDHPQJDQPXNHPA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEB3AZUA#issuecomment-544607440, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323UKJKFDLJASYLTEYLQPXNHPANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank,

The loop delay required to just trigger FIFO overflows in my configuration is almost exactly twice the delay needed for yours

This is easy :) I'm using the MPU9250... might be an MPU9255 which looks to have a different FIFO buffer size. you are using an MPU6050 in assuming. The MPU9250 is based on the MPU6500 with a magnetometer integrated. 99% of the settings are the same just a few minor differences that I've had to fight. There is something somewhere I seen that the FIFO buffer is different. I would look if it were important any more, as of now with this code it doesn't matter.

Where to go? Well let's add this function to jeffs library and create a new example for everyone to use. I think that I might be able to streamline it a little bit more.

You can't imagine how many Arduino.cc forum posts this little function we developed will be instantly resolved. I was involved in a few of these a few years ago as I was attempting to master this little chip.

ZHomeSlice commented 4 years ago

Frank,

I've verified that the MPU9250 has a smaller buffer:

In:MPU-6000/MPU-6050 Product Specification Data Sheet

3.1 MPU-60X0 Overview ...An on-chip 1024 Byte FIFO buffer...

In: MPU-9250 Product Specification Data Sheet

4.17 FIFO The MPU-9250 contains a 512-byte FIFO register ...

Testing Code:

// ================================================================
// ===               INTERRUPT DETECTION ROUTINE                ===
// ================================================================
// Returns 1) when nothing special was done
//         2) when recovering from overflow
//         0) when no valid data is available
// ================================================================
#define EnableTimer //this enables the  auto tuning routine to discover the exact time the fifo buffer is filled
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
  uint8_t Error;
  int8_t more;
  uint8_t Flag = 0;
  uint8_t overflowed = 0;
  static unsigned long xTimer;
  static int t = 9700;
  static int x = 1;
#ifdef EnableTimer
  if (  micros() - xTimer < (t)) return 0;// This is an auto tuning routine to discover the exact time the fifo buffer is filled
#endif
  do {
    if (Error = (fifoCount = mpu.getFIFOCount()) %  length) {
      mpuIntStatus = mpu.getIntStatus();
      if (mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) {
        mpu.getFIFOBytes(data, Error); // lets remove the overflow portion
        mpu.getFIFOBytes(data, length);
        overflowed = 1;
        if (Error = (fifoCount = mpu.getFIFOCount()) %  length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space
          mpu.getFIFOBytes(data, Error); // lets remove the overflow portion again
          if ((fifoCount = mpu.getFIFOCount()) %  length) {
            mpu.resetFIFO();
            Serial.println(F("Failed to recover overflow error"));
            return 0;
          }
        }
      }
    }
    if (fifoCount >= packetSize) {
      mpu.getFIFOBytes(data, length);
      Flag = 1 + overflowed;
      fifoCount -= packetSize;
#ifdef EnableTimer
      xTimer = micros();
      t -= x;
      t = max(t,9700);
    } else {
      t += 1;
      x = 0;
#endif      
    }
  } while (fifoCount >= packetSize);
 // if (!Flag)x = 1;

  Serial.print(" t = ");
  Serial.print(t);
    Serial.print(" Flag = ");
  Serial.print(Flag);
  return Flag;
}

// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================
unsigned long int dx = 0; // test1
//unsigned long int dx = 176520; // MPU6500 or MPU9250 overflow time
//unsigned long int dx = 353040; // MPU6050 or MPU9150 overflow time

unsigned long Ctr;
int addDx = 10000;
void loop() {

int retval;
dx=dx + addDx;
delay(floor(dx/1000)); // I am using the delay to discover the exact moment we overflow and cycle around this point as this is where the errors I struggled with were generated
delayMicroseconds(dx%1000);
  Serial.print(dx);
  Serial.print(" ");
  Ctr++;
  if (!(retval = GetCurrentFIFOPacket(fifoBuffer, packetSize))) return;
  /*
     0 = no data return
     1 = normal data no overflow recovery needed
     2 = normal data but overflow occured and we recovered
  */
  Serial.print(" Ctr = ");
  Serial.print(Ctr);
  Serial.print(" ");
  Ctr = 0;
    if(retval == 2){
      dx = dx - (addDx*2); 
      addDx *= .5;
      addDx = max(1,addDx);
    }
  // display Euler angles in degrees
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  Serial.print("ypr\t");
  Serial.print(ypr[0] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[1] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[2] * 180 / M_PI);
  /*
    mpu.dmpGetAccel(&aa, fifoBuffer);
    Serial.print("\tRaw Accl XYZ\t");
    Serial.print(aa.x);
    Serial.print("\t");
    Serial.print(aa.y);
    Serial.print("\t");
    Serial.print(aa.z);
    mpu.dmpGetGyro(&gy, fifoBuffer);
    Serial.print("\tRaw Gyro XYZ\t");
    Serial.print(gy.x);
    Serial.print("\t");
    Serial.print(gy.y);
    Serial.print("\t");
    Serial.print(gy.z);
  */
  Serial.println();
  // blink LED to indicate activity
  blinkState = !blinkState;
  digitalWrite(LED_PIN, blinkState);

}

This code has a better performance than the last.

Homer

ZHomeSlice commented 4 years ago

Frank, I Believe I Have it

LCnt is how many times it loops before getting a reading

getFIFOCount every loop

 LCnt = 29 Normal   ypr -0.01   -0.06   0.57
 LCnt = 28 Normal   ypr -0.01   -0.07   0.56
 LCnt = 29 Normal   ypr -0.01   -0.07   0.55
 LCnt = 28 Normal   ypr -0.01   -0.07   0.55
 LCnt = 28 Normal   ypr -0.01   -0.07   0.55
 LCnt = 29 Normal   ypr -0.01   -0.07   0.54
 LCnt = 28 Normal   ypr -0.01   -0.07   0.53

Auto Tuning "Blink without delay" after tuning completed. this routine discovers the exact time the FIFO Buffer is filled!!!!

 LCnt = 816 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 816 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 816 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 816 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 815 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 815 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 816 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 816 Normal   ypr    -0.32   0.03    -0.10
 LCnt = 815 Normal   ypr    -0.32   0.03    -0.10

The Function has been moved into the MPU6050.cpp file so it won't work as a stand alone function in preperation to submit as a pull request

/** Get latest byte from FIFO buffer no matter how much time has passed.
 * ===                  GetCurrentFIFOPacket                    ===
 * ================================================================
 * Returns 1) when nothing special was done
 *         2) when recovering from overflow
 *         0) when no valid data is available
 * ================================================================ */
#define EnableTimer //this enables the  auto tuning routine to discover the exact time the fifo buffer is filled
uint8_t MPU6050::GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
#ifdef EnableTimer
    static unsigned long xTimer;
    static int t = 10000;
    static int x = 1;

    if (micros() - xTimer < (t)) return 0;// This is an auto tuning routine to discover the exact time the fifo buffer is filled
#endif
    uint16_t fifoC;
    uint8_t Error;
    uint8_t Flag = 0;
    uint8_t overflowed = 0;
    uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
    do {
        if (Error = (fifoC = getFIFOCount()) %  length) { 
            mpuIntStatus = getIntStatus();
            if ( mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) {
                getFIFOBytes(data, Error); // lets remove the overflow portion
                getFIFOBytes(data, length);
                overflowed = 1;
                if (Error = (fifoC = getFIFOCount()) %  length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space
                    getFIFOBytes(data, Error); // lets remove the overflow portion again
                    if ((fifoC = getFIFOCount()) %  length) {
                        resetFIFO();
                        Serial.println(F("Failed to recover overflow error"));
                        return 0;
                    }
                }
            }
        }
#ifdef EnableTimer
        if(fifoC == 0 && (fifoC = getFIFOCount())){ // no data was present above but now we have it Timing is perfect!!!
            x = 0;  // Lets stop moving around and changing the timing!
        }
#endif
        while(fifoC >(2*length)){
            getFIFOBytes(data, length);
            fifoC -= length;
#ifdef EnableTimer
            x = 1; // Something caused a delay and everything off again start searching for the sweet spot
#endif
        }
        if (fifoC >= length){
            getFIFOBytes(data, length);
            Flag = 1 + overflowed;
            fifoC -= length;
#ifdef EnableTimer
            xTimer = micros();
            t -= x;
            t = max(t,5000); // we have to limit this if there are external delays to deal with. 

        }else{
            t += x;
            fifoC = getFIFOCount(); // We didn't have data before but I bet we have it now!!! Lets check
#endif
        }
    } while (fifoC >= length);
    return Flag;
}

you will need to add this to the MPU6050.h file

uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length);

and the new loop() function:


// ================================================================
// ===                    MAIN PROGRAM LOOP                     ===
// ================================================================
unsigned long int dx = 0; // test1
//unsigned long int dx = 176520; // MPU6500 or MPU9250 overflow time
//unsigned long int dx = 353040; // MPU6050 or MPU9150 overflow time

unsigned long Ctr;
int addDx = 10000;
void loop() {

int retval;
/*
dx=dx + addDx;
delay(floor(dx/1000)); // I am using the delay to discover the exact moment we overflow and cycle around this point as this is where the errors I struggled with were generated
delayMicroseconds(dx%1000);
  Serial.print(dx);
  Serial.print(" ");
*/
  Ctr++;
  if (!(retval = mpu.GetCurrentFIFOPacket(fifoBuffer, packetSize))) return;
  /*
     0 = no data return
     1 = normal data no overflow recovery needed
     2 = normal data but overflow occured and we recovered
  */
  Serial.print(" LCnt = ");
  Serial.print(Ctr);
  Serial.print(" ");
  Ctr = 0;
  Serial.print((retval == 1)?"Normal   ":"Overflow ");

    if(retval == 2){
      dx = dx - (addDx*2); 
      addDx *= .5;
      addDx = max(1,addDx);
    }

  // display Euler angles in degrees
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  Serial.print("ypr\t");
  Serial.print(ypr[0] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[1] * 180 / M_PI);
  Serial.print("\t");
  Serial.print(ypr[2] * 180 / M_PI);
  /*
    mpu.dmpGetAccel(&aa, fifoBuffer);
    Serial.print("\tRaw Accl XYZ\t");
    Serial.print(aa.x);
    Serial.print("\t");
    Serial.print(aa.y);
    Serial.print("\t");
    Serial.print(aa.z);
    mpu.dmpGetGyro(&gy, fifoBuffer);
    Serial.print("\tRaw Gyro XYZ\t");
    Serial.print(gy.x);
    Serial.print("\t");
    Serial.print(gy.y);
    Serial.print("\t");
    Serial.print(gy.z);
  */
  Serial.println();
  // blink LED to indicate activity
  blinkState = !blinkState;
  digitalWrite(LED_PIN, blinkState);

}

Un-remark the delay portion of the code to see the exact time overflow occurs and see if it fails otherwise, this is looping as fast as possible to get the exact time when data becomes available.

I went through many iterations before I discovered this sweet spot! No int pin required!!!! I'll see about posting this for approval tomorrow. Jeff is usually fast on accepting my pull requests.

paynterf commented 4 years ago

Homer,

Here's the output from my run with your new routine:

Opening port Port open Initializing I2C devices... Testing device connections... MPU6050 connection successful Initializing DMP...

**......>......

// X Accel Y Accel Z Accel X Gyro Y Gyro Z Gyro //OFFSETS -3166, 2464, 876, 141, -24, 66 Enabling DMP... Enabling interrupt detection (Arduino external interrupt 0)... DMP ready! Waiting for first interrupt... FIFO packet size = 28 Loop Delay Duration = 360

Msec Yaw Flag 10000 LCnt = 1 Normal ypr -0.01 -0.06 0.61 20000 LCnt = 1 Normal ypr 0.00 -0.06 0.59 30000 LCnt = 1 Normal ypr 0.00 -0.06 0.57 40000 LCnt = 1 Normal ypr 0.00 -0.06 0.55 50000 LCnt = 1 Normal ypr 0.01 -0.06 0.51 60000 LCnt = 1 Normal ypr 0.01 -0.06 0.48 70000 LCnt = 1 Normal ypr 0.01 -0.05 0.43 80000 LCnt = 1 Normal ypr 0.02 -0.05 0.39 90000 LCnt = 1 Normal ypr 0.03 -0.04 0.34 100000 LCnt = 1 Normal ypr 0.03 -0.04 0.30 110000 LCnt = 1 Normal ypr 0.04 -0.04 0.25 120000 LCnt = 1 Normal ypr 0.04 -0.04 0.21 130000 LCnt = 1 Normal ypr 0.05 -0.03 0.17 140000 LCnt = 1 Normal ypr 0.06 -0.03 0.12 150000 LCnt = 1 Normal ypr 0.07 -0.03 0.08 160000 LCnt = 1 Normal ypr 0.08 -0.03 0.03 170000 LCnt = 1 Normal ypr 0.08 -0.02 -0.00 180000 LCnt = 1 Normal ypr 0.10 -0.02 -0.03 190000 LCnt = 1 Normal ypr 0.10 -0.02 -0.06 200000 LCnt = 1 Normal ypr 0.12 -0.01 -0.08 210000 LCnt = 1 Normal ypr 0.13 -0.01 -0.10 220000 LCnt = 1 Normal ypr 0.15 0.00 -0.11 230000 LCnt = 1 Normal ypr 0.16 0.00 -0.13 240000 LCnt = 1 Normal ypr 0.17 -0.01 -0.15 250000 LCnt = 1 Normal ypr 0.19 0.00 -0.17 260000 LCnt = 1 Normal ypr 0.20 0.01 -0.18 270000 LCnt = 1 Normal ypr 0.22 0.01 -0.20 280000 LCnt = 1 Normal ypr 0.24 0.00 -0.20 290000 LCnt = 1 Normal ypr 0.26 0.00 -0.20 300000 LCnt = 1 Normal ypr 0.27 0.01 -0.20 310000 LCnt = 1 Normal ypr 0.29 0.01 -0.21 320000 LCnt = 1 Normal ypr 0.31 0.00 -0.21 330000 LCnt = 1 Normal ypr 0.34 0.00 -0.22 340000 LCnt = 1 Normal ypr 0.33 -0.02 -0.20 350000 LCnt = 1 Normal ypr -9.88 -0.35 -0.97 360000 LCnt = 1 Normal ypr -21.67 -0.86 -1.70 370000 LCnt = 1 Overflow ypr -33.54 -1.31 -2.02 355000 LCnt = 1 Normal ypr -46.44 -1.76 -2.29 360000 LCnt = 1 Overflow ypr -58.08 -2.16 -2.49 352500 LCnt = 1 Normal ypr -65.56 -2.10 -2.51 355000 LCnt = 1 Normal ypr -52.53 -0.86 -1.58 357500 LCnt = 1 Overflow ypr -31.97 -0.16 -0.03 353750 LCnt = 1 Normal ypr -6.71 0.23 1.61 355000 LCnt = 1 Normal ypr 21.09 -0.47 3.12 356250 LCnt = 1 Normal ypr 37.15 -0.84 3.33 357500 LCnt = 1 Normal ypr 51.21 -1.04 3.44 358750 LCnt = 1 Normal ypr 36.39 -0.84 1.74 360000 LCnt = 1 Normal ypr 18.49 -1.01 0.31 361250 LCnt = 1 Overflow ypr 1.88 -1.22 -0.82 359375 LCnt = 1 Overflow ypr -18.59 -1.69 -1.52 358437 LCnt = 1 Overflow ypr -41.91 -2.86 -2.41 357969 LCnt = 1 Normal ypr -51.56 -2.86 -2.47 358125 LCnt = 1 Normal ypr -60.17 -2.69 -2.41 358281 LCnt = 1 Normal ypr -57.77 -1.84 -1.98 358437 LCnt = 1 Normal ypr -44.84 -0.79 -0.84 358593 LCnt = 1 Normal ypr -26.85 0.08 0.03 358749 LCnt = 1 Normal ypr 0.68 0.16 1.97 358905 LCnt = 1 Normal ypr 20.96 -0.17 2.91 359061 LCnt = 1 Normal ypr 30.93 -0.48 2.90 359217 LCnt = 1 Normal ypr 42.48 -0.53 2.92 359373 LCnt = 1 Normal ypr 22.37 -0.60 0.89 359529 LCnt = 1 Normal ypr -0.41 -1.09 -0.67 359685 LCnt = 1 Normal ypr -29.46 -2.29 -1.91 359841 LCnt = 1 Normal ypr -53.38 -3.22 -2.40 359997 LCnt = 1 Overflow ypr -69.44 -3.49 -2.42 359763 LCnt = 1 Overflow ypr -69.54 -2.53 -2.39 359646 LCnt = 1 Overflow ypr -45.64 -0.83 -0.90 359587 LCnt = 1 Overflow ypr -22.92 0.06 0.60 359558 LCnt = 1 Overflow ypr -11.27 -0.04 1.38 359544 LCnt = 1 Overflow ypr -11.25 -0.04 0.90 359538 LCnt = 1 Normal ypr -11.23 -0.05 0.57 359540 LCnt = 1 Overflow ypr -11.21 -0.04 0.32 359537 LCnt = 1 Normal ypr -11.19 -0.05 0.14 359538 LCnt = 1 Normal ypr -11.17 -0.05 -0.00 359539 LCnt = 1 Normal ypr -11.15 -0.05 -0.09 359540 LCnt = 1 Normal ypr -11.13 -0.05 -0.18 359541 LCnt = 1 Normal ypr -11.10 -0.05 -0.23 359542 LCnt = 1 Normal ypr -11.08 -0.06 -0.28 359543 LCnt = 1 Overflow ypr -11.06 -0.06 -0.32 359542 LCnt = 1 Overflow ypr -11.03 -0.07 -0.34 359541 LCnt = 1 Overflow ypr -11.01 -0.06 -0.36 359540 LCnt = 1 Overflow ypr -10.99 -0.06 -0.36 359539 LCnt = 1 Overflow ypr -10.97 -0.06 -0.37 359538 LCnt = 1 Overflow ypr -10.94 -0.06 -0.38 359537 LCnt = 1 Normal ypr -10.92 -0.06 -0.39 359538 LCnt = 1 Normal ypr -10.90 -0.06 -0.39 359539 LCnt = 1 Normal ypr -10.88 -0.06 -0.40 359540 LCnt = 1 Normal ypr -10.86 -0.06 -0.41 359541 LCnt = 1 Normal ypr -10.83 -0.05 -0.41 359542 LCnt = 1 Normal ypr -10.81 -0.05 -0.41 359543 LCnt = 1 Normal ypr -10.79 -0.06 -0.41 359544 LCnt = 1 Normal ypr -10.77 -0.06 -0.41 359545 LCnt = 1 Overflow ypr -10.75 -0.05 -0.41 359544 LCnt = 1 Overflow ypr -10.72 -0.05 -0.41 359543 LCnt = 1 Overflow ypr -10.75 -0.04 -0.37 359542 LCnt = 1 Overflow ypr -10.77 -0.03 -0.33 359541 LCnt = 1 Overflow ypr -10.81 -0.02 -0.31 359540 LCnt = 1 Overflow ypr -10.84 -0.01 -0.29 359539 LCnt = 1 Overflow ypr -10.86 -0.01 -0.27 359538 LCnt = 1 Normal ypr -10.88 -0.01 -0.26 359539 LCnt = 1 Normal ypr -10.91 -0.01 -0.26 359540 LCnt = 1 Normal ypr -10.94 -0.01 -0.26 359541 LCnt = 1 Normal ypr -10.96 -0.01 -0.26 359542 LCnt = 1 Normal ypr -10.99 -0.01 -0.27 359543 LCnt = 1 Normal ypr -11.02 -0.01 -0.27 359544 LCnt = 1 Normal ypr -11.05 -0.01 -0.26 359545 LCnt = 1 Normal ypr -11.07 -0.00 -0.26 359546 LCnt = 1 Overflow ypr -11.10 -0.01 -0.25 359545 LCnt = 1 Overflow ypr -11.13 -0.01 -0.25 359544 LCnt = 1 Overflow ypr -11.16 -0.01 -0.24 359543 LCnt = 1 Overflow ypr -11.19 -0.01 -0.24 359542 LCnt = 1 Overflow ypr -11.22 -0.01 -0.24 359541 LCnt = 1 Overflow ypr -11.24 -0.01 -0.24 359540 LCnt = 1 Normal ypr -11.27 -0.01 -0.24 359541 LCnt = 1 Normal ypr -11.28 -0.01 -0.23 359542 LCnt = 1 Normal ypr -11.27 -0.02 -0.22 359543 LCnt = 1 Normal ypr -11.27 -0.02 -0.23 359544 LCnt = 1 Normal ypr -11.27 -0.02 -0.24 359545 LCnt = 1 Normal ypr -11.27 -0.02 -0.23 359546 LCnt = 1 Normal ypr -11.27 -0.01 -0.22 359547 LCnt = 1 Normal ypr -11.28 -0.01 -0.22 359548 LCnt = 1 Normal ypr -11.27 -0.01 -0.23 359549 LCnt = 1 Overflow ypr -11.27 -0.02 -0.23 359548 LCnt = 1 Overflow ypr -11.28 -0.01 -0.23 359547 LCnt = 1 Overflow ypr -11.28 -0.01 -0.22 359546 LCnt = 1 Overflow ypr -11.28 -0.01 -0.22 359545 LCnt = 1 Overflow ypr -11.28 -0.00 -0.22 359544 LCnt = 1 Overflow ypr -11.27 0.01 -0.23 359543 LCnt = 1 Normal ypr -11.27 0.01 -0.23 359544 LCnt = 1 Normal ypr -11.28 -0.00 -0.23 359545 LCnt = 1 Normal ypr -11.27 0.01 -0.23 359546 LCnt = 1 Normal ypr -11.27 0.01 -0.23 359547 LCnt = 1 Normal ypr -11.28 -0.00 -0.24 359548 LCnt = 1 Normal ypr -11.28 0.01 -0.24 359549 LCnt = 1 Normal ypr -11.29 0.01 -0.24 359550 LCnt = 1 Normal ypr -11.29 0.00 -0.24 359551 LCnt = 1 Overflow ypr -11.29 -0.00 -0.24 359550 LCnt = 1 Overflow ypr -11.30 -0.00 -0.24 359549 LCnt = 1 Overflow ypr -11.30 -0.00 -0.23 359548 LCnt = 1 Overflow ypr -11.30 -0.00 -0.23 359547 LCnt = 1 Overflow ypr -11.31 -0.00 -0.24 359546 LCnt = 1 Overflow ypr -11.31 -0.02 -0.24 359545 LCnt = 1 Overflow ypr -11.31 -0.02 -0.24 359544 LCnt = 1 Normal ypr -11.31 -0.02 -0.24 359545 LCnt = 1 Normal ypr -11.31 -0.02 -0.25 359546 LCnt = 1 Normal ypr -11.31 -0.02 -0.25 359547 LCnt = 1 Normal ypr -11.32 -0.02 -0.24

Port closed

As you can see, the time required for overflow is very close to 360 mSec, which agrees well with the values I was seeing before, and (I think) agrees with a 1024 byte buffer vs 512. So, the MPU with the V6.12 firmware must be filling the FIFO at 2884.444 bytes/second (2884.444 bps * 0.36 sec = 1024), or about 101 packets/second (2844.444/28 = 101.587).

Do you have any theories about the issue I had with the number of interrupts x the number of bytes/packet being twice the value reported from the FIFO with mpu.getFIFOCount()? This may be a moot issue now that you have basically eliminated the need for the interrupt-driven arrangement, but it still bugs me ;-).

Frank

On Tue, Oct 22, 2019 at 2:50 AM Homer Creutz notifications@github.com wrote:

Frank, I Believe I Have it

LCnt is how many times it loops before getting a reading

getFIFOCount every loop

LCnt = 29 Normal ypr -0.01 -0.06 0.57 LCnt = 28 Normal ypr -0.01 -0.07 0.56 LCnt = 29 Normal ypr -0.01 -0.07 0.55 LCnt = 28 Normal ypr -0.01 -0.07 0.55 LCnt = 28 Normal ypr -0.01 -0.07 0.55 LCnt = 29 Normal ypr -0.01 -0.07 0.54 LCnt = 28 Normal ypr -0.01 -0.07 0.53

Auto Tuning "Blink without delay" after tuning completed. this routine discovers the exact time the FIFO Buffer is filled!!!!

LCnt = 816 Normal ypr -0.32 0.03 -0.10 LCnt = 816 Normal ypr -0.32 0.03 -0.10 LCnt = 816 Normal ypr -0.32 0.03 -0.10 LCnt = 816 Normal ypr -0.32 0.03 -0.10 LCnt = 815 Normal ypr -0.32 0.03 -0.10 LCnt = 815 Normal ypr -0.32 0.03 -0.10 LCnt = 816 Normal ypr -0.32 0.03 -0.10 LCnt = 816 Normal ypr -0.32 0.03 -0.10 LCnt = 815 Normal ypr -0.32 0.03 -0.10

The Function has been moved into the MPU6050.cpp file so it won't work as a stand alone function in preperation to submit as a pull request

/** Get latest byte from FIFO buffer no matter how much time has passed.

  • === GetCurrentFIFOPacket ===
  • ================================================================
  • Returns 1) when nothing special was done
  • 2) when recovering from overflow
  • 0) when no valid data is available
  • ================================================================ */

    define EnableTimer //this enables the auto tuning routine to discover the exact time the fifo buffer is filled

    uint8_t MPU6050::GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof

    ifdef EnableTimer

    static unsigned long xTimer; static int t = 10000; static int x = 1;

    if (micros() - xTimer < (t)) return 0;// This is an auto tuning routine to discover the exact time the fifo buffer is filled

    endif

    uint16_t fifoC; uint8_t Error; uint8_t Flag = 0; uint8_t overflowed = 0; uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU do { if (Error = (fifoC = getFIFOCount()) % length) { mpuIntStatus = getIntStatus(); if ( mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) { getFIFOBytes(data, Error); // lets remove the overflow portion getFIFOBytes(data, length); overflowed = 1; if (Error = (fifoC = getFIFOCount()) % length) { // there could be some remaining bytes to deal with that snuck in after we freed up some space getFIFOBytes(data, Error); // lets remove the overflow portion again if ((fifoC = getFIFOCount()) % length) { resetFIFO(); Serial.println(F("Failed to recover overflow error")); return 0; } } } }

    ifdef EnableTimer

    if(fifoC == 0 && (fifoC = getFIFOCount())){ // no data was present above but now we have it Timing is perfect!!! x = 0; // Lets stop moving around and changing the timing! }

    endif

    while(fifoC >(2*length)){ getFIFOBytes(data, length); fifoC -= length;

    ifdef EnableTimer

      x = 1; // Something caused a delay and everything off again start searching for the sweet spot

    endif

    } if (fifoC >= length){ getFIFOBytes(data, length); Flag = 1 + overflowed; fifoC -= length;

    ifdef EnableTimer

      xTimer = micros();
      t -= x;
      t = max(t,5000); // we have to limit this if there are external delays to deal with.

    }else{ t += x; fifoC = getFIFOCount(); // We didn't have data before but I bet we have it now!!! Lets check

    endif

    } } while (fifoC >= length); return Flag; }

you will need to add this to the MPU6050.h file

uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length);

and the new loop() function:

// ================================================================ // === MAIN PROGRAM LOOP === // ================================================================ unsigned long int dx = 0; // test1 //unsigned long int dx = 176520; // MPU6500 or MPU9250 overflow time //unsigned long int dx = 353040; // MPU6050 or MPU9150 overflow time

unsigned long Ctr; int addDx = 10000; void loop() {

int retval; / dx=dx + addDx; delay(floor(dx/1000)); // I am using the delay to discover the exact moment we overflow and cycle around this point as this is where the errors I struggled with were generated delayMicroseconds(dx%1000); Serial.print(dx); Serial.print(" "); / Ctr++; if (!(retval = mpu.GetCurrentFIFOPacket(fifoBuffer, packetSize))) return; / 0 = no data return 1 = normal data no overflow recovery needed 2 = normal data but overflow occured and we recovered / Serial.print(" LCnt = "); Serial.print(Ctr); Serial.print(" "); Ctr = 0; Serial.print((retval == 1)?"Normal ":"Overflow ");

if(retval == 2){
  dx = dx - (addDx*2);
  addDx *= .5;
  addDx = max(1,addDx);
}

// display Euler angles in degrees mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); Serial.print("ypr\t"); Serial.print(ypr[0] 180 / M_PI); Serial.print("\t"); Serial.print(ypr[1] 180 / M_PI); Serial.print("\t"); Serial.print(ypr[2] 180 / M_PI); / mpu.dmpGetAccel(&aa, fifoBuffer); Serial.print("\tRaw Accl XYZ\t"); Serial.print(aa.x); Serial.print("\t"); Serial.print(aa.y); Serial.print("\t"); Serial.print(aa.z); mpu.dmpGetGyro(&gy, fifoBuffer); Serial.print("\tRaw Gyro XYZ\t"); Serial.print(gy.x); Serial.print("\t"); Serial.print(gy.y); Serial.print("\t"); Serial.print(gy.z); */ Serial.println(); // blink LED to indicate activity blinkState = !blinkState; digitalWrite(LED_PIN, blinkState);

}

Un-remark the delay portion of the code to see the exact time overflow occurs and see if it fails otherwise, this is looping as fast as possible to get the exact time when data becomes available.

I went through many iterations before I discovered this sweet spot! No int pin required!!!! I'll see about posting this for approval tomorrow. Jeff is usually fast on accepting my pull requests.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T322DGS3ME4GSEOXMTFDQP2PDPA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEB4WYXQ#issuecomment-544828510, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T32564OK67PWNH6FMYH3QP2PDPANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Looks great! I'm excited to see this get out there in the wild! lol.

Do you have any theories about the issue I had with the number of interrupts x the number of bytes/packet being twice the value reported from the FIFO with mpu.getFIFOCount()?

This is interesting what I know is that with the current settings every 10 milliseconds the MPU DMP firmware... (The big blob of data we upload at the start. Note that there are 2 ways to fill the FIFO buffer. the default FIFO configuration and the DMP FIFO configuration with its bit banged configuration that generates the Quaternion values. Only one of the FIFO filling options can be used at a time. we are using the Fixed DMP version and not the other) ...This Firmware is programmed to stuff the FIFO buffer with new values The Size of the Packet is fixed, I created the V6.12 (and I shared it with Jeff) and purposefully left off much of the fluff that could be added as it didn't pertain to the 99% majority of Arduino users. the V2 was created by someone else and with no documentation that I can find exists that would allow me to mod the packet size. And so the packets are much larger, about twice the size. Because the Arduino and the MPU are never in perfect sync the Interrupt was the preferred choice to get the values. now we can randomly pick and choose when to get the latest readings, which I think for most new and even experienced Arduino programmers will simplify there code. As for your question, I can only assume there was an error in the math as I've not been able to recreate the root cause of the two times packets scenario.

Can you see anything in the routine that could be removed or isn't needed? I've only had the "Failed to recover overflow error" appear once and I'm assuming it was a fluke as I've not been able to recreate it since. With that, it seems the notice is mute and may never occur under 99.99% of creations this code is used in. And if it does then they will just have to be patient and wait 10ms for the next good packet. :)

If you didn't know, this is my youtube channel not that I post much but there are a few entertaining videos https://youtu.be/JI7Pp7kWgmg Homer

paynterf commented 4 years ago

I'm glad you shared the video - that's pretty spectacular!

So now that I know you are using the IMU in a motor-driven robot, can you tell me if you have had any problems with motor EMI/RFI screwing up IMU data packets? I have two wall-following robots (much less sophisticated than your balancing one) that use IMU yaw information for heading-based turns, but I am having a lot of trouble getting reliable yaw data when the motors are running; I did a study a while back (see https://www.fpaynter.com/2019/07/mpu6050-imu-motor-noise-troubleshooting/) and determined that most of the problem was due to the transients generated by the switching style of motor controllers, but not so much by the L298 linear types.

I'm not sure where math errors could possibly creep into my anomalous results regarding number of interrupts and the number of bytes in the FIFO. The number of interrupts comes from a counter in the ISR, incremented once per interrupt, and then reset in loop() at the same time as the mpu.getFIFOCount() call. AFAICT, there is no way the interrupt count can be off by a factor of 2 (especially since it would have to be half in order for the math to work out), and the number of bytes comes directly from the mpu.getFIFOCount() call. When I look back through my post on our previous work, I found this little snippet of an output run:

Enabling DMP... Enabling interrupt detection (Arduino external interrupt 0)... DMP ready! Waiting for first interrupt... Msec Yaw NumInt fifoCount 6342 -0.01 22 280 <<-- for a 28-byte packet, NumInt should be 10, not 20 6446 -0.01 20 532 <<-- the FIFO increased by 252, which is approximately 12.6 bytes/interrupt 6548 0.00 20 812 <<-- the FIFO increased by 280, which is exactly 14 bytes/interrupt

Do you actually have direct evidence that the MPU loads a full 28-byte packet into the FIFO each time it emits an interrupt? Is it possible it's actually loading only 1/2 packet (14 bytes vs 28 bytes) per interrupt?

Frank

On Tue, Oct 22, 2019 at 12:27 PM Homer Creutz notifications@github.com wrote:

Looks great! I'm excited to see this get out there in the wild! lol.

Do you have any theories about the issue I had with the number of interrupts x the number of bytes/packet being twice the value reported from the FIFO with mpu.getFIFOCount()?

This is interesting what I know is that with the current settings every 10 milliseconds the MPU DMP firmware... (The big blob of data we upload at the start. Note that there are 2 ways to fill the FIFO buffer. the default FIFO configuration and the DMP FIFO configuration with its bit banged configuration that generates the Quaternion values. Only one of the FIFO filling options can be used at a time. we are using the Fixed DMP version and not the other) ...This Firmware is programmed to stuff the FIFO buffer with new values The Size of the Packet is fixed, I created the V6.12 (and I shared it with Jeff) and purposefully left off much of the fluff that could be added as it didn't pertain to the 99% majority of Arduino users. the V2 was created by someone else and with no documentation that I can find exists that would allow me to mod the packet size. And so the packets are much larger, about twice the size. Because the Arduino and the MPU are never in perfect sync the Interrupt was the preferred choice to get the values. now we can randomly pick and choose when to get the latest readings, which I think for most new and even experienced Arduino programmers will simplify there code. As for your question, I can only assume there was an error in the math as I've not been able to recreate the root cause of the two times packets scenario.

Can you see anything in the routine that could be removed or isn't needed? I've only had the "Failed to recover overflow error" appear once and I'm assuming it was a fluke as I've not been able to recreate it since. With that, it seems the notice is mute and may never occur under 99.99% of creations this code is used in. And if it does then they will just have to be patient and wait 10ms for the next good packet. :)

If you didn't know, this is my youtube channel not that I post much but there are a few entertaining videos https://youtu.be/JI7Pp7kWgmg Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T327BPZPLMF4QS7OQDXTQP4SW5A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEB6LSPI#issuecomment-545044797, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327EXMHZNHKSFGCERALQP4SW5ANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank,

So now that I know you are using the IMU in a motor-driven robot, can you tell me if you have had any problems with motor EMI/RFI screwing up IMU

I am using a 12V Milwaukee battery with a Custom made Duel H-Bridge Arduino Uno at heart. The biggest difficulties are where the voltage of the battery is close to the minimum voltage my voltage regulator can properly handle. For Example, my H-bridge can handle as low as 5V but my onboard voltage regulator tries to output at 5V but now can't so I have to subsidize an alternate power source through the USB to keep my Uno going. at 7 Volts I can make this happen until I try to run the motors when the motor pulses from forward to reverse the current draw dips the 7 volts downward and causes my onboard atmega320p to lockup. so again I need to attach an alternate power supply. above 7 volts I rarely have any problems usually this occurs as the batteries degrade to a lower charge.

Do you have any Schematics I can look at? My Custom Made "Arc Controller" has the equivalent of (2) JZK BTS7960B 43A Brushed DC H-Bridge and an Arduino Uno all in one. I control the H-Bridge (if I were to use this board) feeding a PWM signal to both of the R_EN and L_EN pins at the same time then set either of the (Incorrectly Labeled) RPWM or LPWM pins high to set the motor direction. having both RPWM and LPWM High or low at the same time will allow for breaking when the PWM signal is applied.

I would consider powering the UNO with a separate 5V source I like using the cell phone charger battery packs and an old USB cable-laying around. This should isolate the interference enough to Eliminate the interference.

Msec Yaw NumInt fifoCount 6342 -0.01 22 280 <<-- for a 28-byte packet, NumInt should be 10, not 20 6446 -0.01 20 532 <<-- the FIFO increased by 252, which is approximately 12.6 bytes/interrupt

NumInt ? is this a function counting ints 16 bit or is reading the number of 8 bit Bytes?

252/8 = 9 you have 9 packets if you are using the V6.12 DMP uint8_t fifoBuffer[64]; // FIFO storage buffer uint8_t is a basically an unsigned integer or "char" with 8 bits int8_t is a signed integer with 8 bits uint16_t is an "unsigned int" that has 16 bits uint32_t is an "unsigned long" that has 32 bits the use of uint8_t here is more clear than the use of "int" which could represent 16 or 32 bits based on the destination CPU. I tend to use the uint##_t as I know exactly what I am getting rather than the byte, char, int, unsigned int, etc.

My guess is that you are asking how many "int's" 16 bit integers are in the buffer which would return half expected count.

Do you actually have direct evidence that the MPU loads a full 28-byte packet into the FIFO each time it emits an interrupt? Is it possible it's actually loading only 1/2 packet (14 (ints?) bytes vs 28 bytes) per interrupt?

in inv_mpu_dmp_motion_driver.cpp line 968

/**
 *  @brief      Enable DMP features.
 *  The following \#define's are used in the input mask:
 *  \n DMP_FEATURE_TAP
 *  \n DMP_FEATURE_ANDROID_ORIENT
 *  \n DMP_FEATURE_LP_QUAT
 *  \n DMP_FEATURE_6X_LP_QUAT
 *  \n DMP_FEATURE_GYRO_CAL
 *  \n DMP_FEATURE_SEND_RAW_ACCEL
 *  \n DMP_FEATURE_SEND_RAW_GYRO
 *  \n NOTE: DMP_FEATURE_LP_QUAT and DMP_FEATURE_6X_LP_QUAT are mutually
 *  exclusive.
 *  \n NOTE: DMP_FEATURE_SEND_RAW_GYRO and DMP_FEATURE_SEND_CAL_GYRO are also
 *  mutually exclusive.
 *  @param[in]  mask    Mask of features to enable.
 *  @return     0 if successful.
 */
int dmp_enable_feature(unsigned short mask)
{
    unsigned char tmp[10];

    /* TODO: All of these settings can probably be integrated into the default
     * DMP image.
     */
    /* Set integration scale factor. */
    tmp[0] = (unsigned char)((GYRO_SF >> 24) & 0xFF);
    tmp[1] = (unsigned char)((GYRO_SF >> 16) & 0xFF);
    tmp[2] = (unsigned char)((GYRO_SF >> 8) & 0xFF);
    tmp[3] = (unsigned char)(GYRO_SF & 0xFF);
    mpu_write_mem(D_0_104, 4, tmp);

    /* Send sensor data to the FIFO. */
    tmp[0] = 0xA3;
    if (mask & DMP_FEATURE_SEND_RAW_ACCEL) {
        tmp[1] = 0xC0;
        tmp[2] = 0xC8;
        tmp[3] = 0xC2;
    } else {
        tmp[1] = 0xA3;
        tmp[2] = 0xA3;
        tmp[3] = 0xA3;
    }
    if (mask & DMP_FEATURE_SEND_ANY_GYRO) {
        tmp[4] = 0xC4;
        tmp[5] = 0xCC;
        tmp[6] = 0xC6;
    } else {
        tmp[4] = 0xA3;
        tmp[5] = 0xA3;
        tmp[6] = 0xA3;
    }
    tmp[7] = 0xA3;
    tmp[8] = 0xA3;
    tmp[9] = 0xA3;
    mpu_write_mem(CFG_15,10,tmp);

    /* Send gesture data to the FIFO. */
    if (mask & (DMP_FEATURE_TAP | DMP_FEATURE_ANDROID_ORIENT))
        tmp[0] = DINA20;
    else
        tmp[0] = 0xD8;
    mpu_write_mem(CFG_27,1,tmp);

    if (mask & DMP_FEATURE_GYRO_CAL)
        dmp_enable_gyro_cal(1);
    else
        dmp_enable_gyro_cal(0);

    if (mask & DMP_FEATURE_SEND_ANY_GYRO) {
        if (mask & DMP_FEATURE_SEND_CAL_GYRO) {
            tmp[0] = 0xB2;
            tmp[1] = 0x8B;
            tmp[2] = 0xB6;
            tmp[3] = 0x9B;
        } else {
            tmp[0] = DINAC0;
            tmp[1] = DINA80;
            tmp[2] = DINAC2;
            tmp[3] = DINA90;
        }
        mpu_write_mem(CFG_GYRO_RAW_DATA, 4, tmp);
    }

    if (mask & DMP_FEATURE_TAP) {
        /* Enable tap. */
        tmp[0] = 0xF8;
        mpu_write_mem(CFG_20, 1, tmp);
        dmp_set_tap_thresh(TAP_XYZ, 250);
        dmp_set_tap_axes(TAP_XYZ);
        dmp_set_tap_count(1);
        dmp_set_tap_time(100);
        dmp_set_tap_time_multi(500);

        dmp_set_shake_reject_thresh(GYRO_SF, 200);
        dmp_set_shake_reject_time(40);
        dmp_set_shake_reject_timeout(10);
    } else {
        tmp[0] = 0xD8;
        mpu_write_mem(CFG_20, 1, tmp);
    }

    if (mask & DMP_FEATURE_ANDROID_ORIENT) {
        tmp[0] = 0xD9;
    } else
        tmp[0] = 0xD8;
    mpu_write_mem(CFG_ANDROID_ORIENT_INT, 1, tmp);

    if (mask & DMP_FEATURE_LP_QUAT)
        dmp_enable_lp_quat(1);
    else
        dmp_enable_lp_quat(0);

    if (mask & DMP_FEATURE_6X_LP_QUAT)
        dmp_enable_6x_lp_quat(1);
    else
        dmp_enable_6x_lp_quat(0);

    /* Pedometer is always enabled. */
    dmp.feature_mask = mask | DMP_FEATURE_PEDOMETER;
    mpu_reset_fifo();

    dmp.packet_length = 0;
    if (mask & DMP_FEATURE_SEND_RAW_ACCEL)
        dmp.packet_length += 6;
    if (mask & DMP_FEATURE_SEND_ANY_GYRO)
        dmp.packet_length += 6;
    if (mask & (DMP_FEATURE_LP_QUAT | DMP_FEATURE_6X_LP_QUAT))
        dmp.packet_length += 16;
    if (mask & (DMP_FEATURE_TAP | DMP_FEATURE_ANDROID_ORIENT))
        dmp.packet_length += 4;

    return 0;
}

Whew, lots of settings to configure to get what you want here. so what are we looking at each of the DMP_FEATURE_SEND_RAW_ACCEL DMP_FEATURE_SEND_ANY_GYRO DMP_FEATURE_6X_LP_QUAT DMP_FEATURE_TAP DMP_FEATURE_ANDROID_ORIENT represent bits that are matched to the mask variable int dmp_enable_feature(unsigned short mask) passed to the function. unsigned short = unsigned 8-bit integer so sending something like 11011010B to the dmp_enable_feature would match up to each bit and enable that feature

So once we have set all the features of the DMP (changing the DMP image) all at once we can now calculate how big the DMP generated FIFO packet will be.

For my V6.12 setup I only enabled: DMP_FEATURE_SEND_RAW_ACCEL DMP_FEATURE_SEND_ANY_GYRO DMP_FEATURE_6X_LP_QUAT

The last part of the function sets the new packet size:

    dmp.packet_length = 0;
    if (mask & DMP_FEATURE_SEND_RAW_ACCEL)
        dmp.packet_length += 6;
    if (mask & DMP_FEATURE_SEND_ANY_GYRO)
        dmp.packet_length += 6;
    if (mask & (DMP_FEATURE_LP_QUAT | DMP_FEATURE_6X_LP_QUAT))
        dmp.packet_length += 16;
    if (mask & (DMP_FEATURE_TAP | DMP_FEATURE_ANDROID_ORIENT))
        dmp.packet_length += 4;

These are FIXED values for each feature that can't be changed Also, this is the order in which they will appear int the FIFO buffer. DMP_FEATURE_SEND_RAW_ACCEL = 6 bytes, DMP_FEATURE_SEND_ANY_GYRO = 6 bytes, DMP_FEATURE_6X_LP_QUAT = 16 bytes,

6+6+16 = 28

I created a program that placed this configuration into the DMP image while it was on the MPU6050 and just before running the program I retrieved the modified DMP image by dumping the Hex values of each byte to the serial buffer.

Homer

paynterf commented 4 years ago

Homer,

Not sure what's going on, but I'm pretty confident that the number returned from getFIFOCount() is the actual number of bytes currently available in the FIFO The function returns a 'uint_16t' object which is saved in fifoCount, also a 'uint_16t' object. Unless the 'printf()' function is somehow dividing the value by 2 during the print operation, I just don't see how that number can be wrong. I went back and re-ran my original experiment, and got the same results, as shown below:

Enabling interrupt detection (Arduino external interrupt 0)... DMP ready! Waiting for first interrupt... FIFO packet size = 28 Loop Delay Duration = 100

Msec Yaw NumInt fifoCount 5949 22 336 -0.01 28 0 6061 20 308 -0.01 28 0 6171 20 308 -0.01 28 0 6282 20 308 -0.01 28 0 6392 20 308 -0.01 28 0 6503 20 308 -0.01 28 0 6614 20 308 -0.02 28 0

So there is definitely something I don't understand. I have updated my blog post to include the above results, along with the complete program that created them. Maybe you could try running the program on your MPU9250-based setup and see if you get different results?

Regards,

Frank

On Tue, Oct 22, 2019 at 10:38 PM Homer Creutz notifications@github.com wrote:

Frank,

So now that I know you are using the IMU in a motor-driven robot, can you tell me if you have had any problems with motor EMI/RFI screwing up IMU

I am using a 12V Milwaukee battery with a Custom made Duel H-Bridge Arduino Uno at heart. The biggest difficulties are where the voltage of the battery is close to the minimum voltage my voltage regulator can properly handle. For Example, my H-bridge can handle as low as 5V but my onboard voltage regulator tries to output at 5V but now can't so I have to subsidize an alternate power source through the USB to keep my Uno going. at 7 Volts I can make this happen until I try to run the motors when the motor pulses from forward to reverse the current draw dips the 7 volts downward and causes my onboard atmega320p to lockup. so again I need to attach an alternate power supply. above 7 volts I rarely have any problems usually this occurs as the batteries degrade to a lower charge.

Do you have any Schematics I can look at? My Custom Made "Arc Controller" has the equivalent of (2) JZK BTS7960B 43A Brushed DC H-Bridge and an Arduino Uno all in one. I control the H-Bridge (if I were to use this board) feeding a PWM signal to both of the R_EN and L_EN pins at the same time then set either of the (Incorrectly Labeled) RPWM or LPWM pins high to set the motor direction. having both RPWM and LPWM High or low at the same time will allow for breaking when the PWM signal is applied.

I would consider powering the UNO with a separate 5V source I like using the cell phone charger battery packs and an old USB cable-laying around. This should isolate the interference enough to Eliminate the interference.

Msec Yaw NumInt fifoCount 6342 -0.01 22 280 <<-- for a 28-byte packet, NumInt should be 10, not 20 6446 -0.01 20 532 <<-- the FIFO increased by 252, which is approximately 12.6 bytes/interrupt

NumInt ? is this a function counting ints 16 bit or is reading the number of 8 bit Bytes?

252/8 = 9 you have 9 packets if you are using the V6.12 DMP uint8_t fifoBuffer[64]; // FIFO storage buffer uint8_t is a basically an unsigned integer or "char" with 8 bits int8_t is a signed integer with 8 bits uint16_t is an "unsigned int" that has 16 bits uint32_t is an "unsigned long" that has 32 bits the use of uint8_t here is more clear than the use of "int" which could represent 16 or 32 bits based on the destination CPU. I tend to use the uint##_t as I know exactly what I am getting rather than the byte, char, int, unsigned int, etc.

My guess is that you are asking how many "int's" 16 bit integers are in the buffer which would return half expected count.

Do you actually have direct evidence that the MPU loads a full 28-byte packet into the FIFO each time it emits an interrupt? Is it possible it's actually loading only 1/2 packet (14 (ints?) bytes vs 28 bytes) per interrupt?

in inv_mpu_dmp_motion_driver.cpp line 968

/**

  • @brief Enable DMP features.
  • The following #define's are used in the input mask:
  • \n DMP_FEATURE_TAP
  • \n DMP_FEATURE_ANDROID_ORIENT
  • \n DMP_FEATURE_LP_QUAT
  • \n DMP_FEATURE_6X_LP_QUAT
  • \n DMP_FEATURE_GYRO_CAL
  • \n DMP_FEATURE_SEND_RAW_ACCEL
  • \n DMP_FEATURE_SEND_RAW_GYRO
  • \n NOTE: DMP_FEATURE_LP_QUAT and DMP_FEATURE_6X_LP_QUAT are mutually
  • exclusive.
  • \n NOTE: DMP_FEATURE_SEND_RAW_GYRO and DMP_FEATURE_SEND_CAL_GYRO are also
  • mutually exclusive.
  • @param[in] mask Mask of features to enable.
  • @return 0 if successful. */ int dmp_enable_feature(unsigned short mask) { unsigned char tmp[10];

    /* TODO: All of these settings can probably be integrated into the default

    • DMP image. / / Set integration scale factor. */ tmp[0] = (unsigned char)((GYRO_SF >> 24) & 0xFF); tmp[1] = (unsigned char)((GYRO_SF >> 16) & 0xFF); tmp[2] = (unsigned char)((GYRO_SF >> 8) & 0xFF); tmp[3] = (unsigned char)(GYRO_SF & 0xFF); mpu_write_mem(D_0_104, 4, tmp);

    / Send sensor data to the FIFO. / tmp[0] = 0xA3; if (mask & DMP_FEATURE_SEND_RAW_ACCEL) { tmp[1] = 0xC0; tmp[2] = 0xC8; tmp[3] = 0xC2; } else { tmp[1] = 0xA3; tmp[2] = 0xA3; tmp[3] = 0xA3; } if (mask & DMP_FEATURE_SEND_ANY_GYRO) { tmp[4] = 0xC4; tmp[5] = 0xCC; tmp[6] = 0xC6; } else { tmp[4] = 0xA3; tmp[5] = 0xA3; tmp[6] = 0xA3; } tmp[7] = 0xA3; tmp[8] = 0xA3; tmp[9] = 0xA3; mpu_write_mem(CFG_15,10,tmp);

    / Send gesture data to the FIFO. / if (mask & (DMP_FEATURE_TAP | DMP_FEATURE_ANDROID_ORIENT)) tmp[0] = DINA20; else tmp[0] = 0xD8; mpu_write_mem(CFG_27,1,tmp);

    if (mask & DMP_FEATURE_GYRO_CAL) dmp_enable_gyro_cal(1); else dmp_enable_gyro_cal(0);

    if (mask & DMP_FEATURE_SEND_ANY_GYRO) { if (mask & DMP_FEATURE_SEND_CAL_GYRO) { tmp[0] = 0xB2; tmp[1] = 0x8B; tmp[2] = 0xB6; tmp[3] = 0x9B; } else { tmp[0] = DINAC0; tmp[1] = DINA80; tmp[2] = DINAC2; tmp[3] = DINA90; } mpu_write_mem(CFG_GYRO_RAW_DATA, 4, tmp); }

    if (mask & DMP_FEATURE_TAP) { / Enable tap. / tmp[0] = 0xF8; mpu_write_mem(CFG_20, 1, tmp); dmp_set_tap_thresh(TAP_XYZ, 250); dmp_set_tap_axes(TAP_XYZ); dmp_set_tap_count(1); dmp_set_tap_time(100); dmp_set_tap_time_multi(500);

    dmp_set_shake_reject_thresh(GYRO_SF, 200);
    dmp_set_shake_reject_time(40);
    dmp_set_shake_reject_timeout(10);

    } else { tmp[0] = 0xD8; mpu_write_mem(CFG_20, 1, tmp); }

    if (mask & DMP_FEATURE_ANDROID_ORIENT) { tmp[0] = 0xD9; } else tmp[0] = 0xD8; mpu_write_mem(CFG_ANDROID_ORIENT_INT, 1, tmp);

    if (mask & DMP_FEATURE_LP_QUAT) dmp_enable_lp_quat(1); else dmp_enable_lp_quat(0);

    if (mask & DMP_FEATURE_6X_LP_QUAT) dmp_enable_6x_lp_quat(1); else dmp_enable_6x_lp_quat(0);

    / Pedometer is always enabled. / dmp.feature_mask = mask | DMP_FEATURE_PEDOMETER; mpu_reset_fifo();

    dmp.packet_length = 0; if (mask & DMP_FEATURE_SEND_RAW_ACCEL) dmp.packet_length += 6; if (mask & DMP_FEATURE_SEND_ANY_GYRO) dmp.packet_length += 6; if (mask & (DMP_FEATURE_LP_QUAT | DMP_FEATURE_6X_LP_QUAT)) dmp.packet_length += 16; if (mask & (DMP_FEATURE_TAP | DMP_FEATURE_ANDROID_ORIENT)) dmp.packet_length += 4;

    return 0; }

Whew, lots of settings to configure to get what you want here. so what are we looking at each of the DMP_FEATURE_SEND_RAW_ACCEL DMP_FEATURE_SEND_ANY_GYRO DMP_FEATURE_6X_LP_QUAT DMP_FEATURE_TAP DMP_FEATURE_ANDROID_ORIENT represent bits that are matched to the mask variable int dmp_enable_feature(unsigned short mask) passed to the function. unsigned short = unsigned 8-bit integer so sending something like 11011010B to the dmp_enable_feature would match up to each bit and enable that feature

So once we have set all the features of the DMP (changing the DMP image) all at once we can now calculate how big the DMP generated FIFO packet will be.

For my V6.12 setup I only enabled: DMP_FEATURE_SEND_RAW_ACCEL DMP_FEATURE_SEND_ANY_GYRO DMP_FEATURE_6X_LP_QUAT

The last part of the function sets the new packet size:

dmp.packet_length = 0;
if (mask & DMP_FEATURE_SEND_RAW_ACCEL)
    dmp.packet_length += 6;
if (mask & DMP_FEATURE_SEND_ANY_GYRO)
    dmp.packet_length += 6;
if (mask & (DMP_FEATURE_LP_QUAT | DMP_FEATURE_6X_LP_QUAT))
    dmp.packet_length += 16;
if (mask & (DMP_FEATURE_TAP | DMP_FEATURE_ANDROID_ORIENT))
    dmp.packet_length += 4;

These are FIXED values for each feature that can't be changed Also, this is the order in which they will appear int the FIFO buffer. DMP_FEATURE_SEND_RAW_ACCEL = 6 bytes, DMP_FEATURE_SEND_ANY_GYRO = 6 bytes, DMP_FEATURE_6X_LP_QUAT = 16 bytes,

6+6+16 = 28

I created a program that placed this configuration into the DMP image while it was on the MPU6050 and just before running the program I retrieved the modified DMP image by dumping the Hex values of each byte to the serial buffer.

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T326EG3GR67QPUE32YSLQP62IXA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEB72XNI#issuecomment-545237941, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T322AFGOBOW7PTDEH35TQP62IXANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, I didn't understand what NumInt was I thought it pertained to an Integer but instead it a counter that watches the Int Pin on the MPU6050 :) I know what is happening.

Msec Yaw NumInt fifoCount
5949 22 336 -0.01 28 0
6061 20 308 -0.01 28 0
6171 20 308 -0.01 28 0
6282 20 308 -0.01 28 0
6392 20 308 -0.01 28 0
6503 20 308 -0.01 28 0
6614 20 308 -0.02 28 0

The time difference is about 110 to 111 ms so only 10 to 11 interrupts should be present but we show 20 twice the interrupts. Well, interrupts are not exclusive to the DMP FIFO packet ready flag and so we see an additional interrupt occurring.

Here are some of the interrupts that can be enabled"

In register 0x38 the following bits represent what interrupts are enabled any of these interrupts will cause the INT pin to change triggering the interrupt

INT_ENABLE_READ_FF_EN Bit 7  1 =  Enable interrupt for
INT_ENABLE_READ_WOM_EN Bit 6  1 =  Enable interrupt for wake on motion to propagate to interrupt pin. 0   function is disabled.
INT_ENABLE_READ_ZMOT_OFLOW_EN Bit 5  1 =  Enable interrupt for
INT_ENABLE_READ_FIFO_OFLOW_EN Bit 4   1 =  Enable interrupt for FIFO overflow to propagate to interrupt pin. 0   function is disabled.
INT_ENABLE_READ_FSYNC_INT_EN Bit  3  1 =  Enable (I2C_MST_INT_BIT) Fsync interrupt to propagate to interrupt pin. 0   function is disabled.
INT_ENABLE_READ_RAW_PLL_RDY_INT_EN Bit 2  1 = Enable
INT_ENABLE_READ_RAW_DMP_INT_EN Bit 1  1 =  Enable
INT_ENABLE_READ_RAW_RDY_EN Bit 0   1 =  Enable Raw Sensor Data Ready interrupt to propagate to interrupt pin.  0   function is disabled.

with only 1 bit enables you would think only 1 interrupt could occur. I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x02)); // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on

but when you watch the interrupts you will see that an additional interrupt occurs each cycle

Let's add this line into your code

uint8_t buffer;
I2Cdev::readByte(devAddr, MPU6050_RA_DMP_INT_STATUS,  buffer);
Serial.print(buffer,BIN);

This will give you what interrupts are triggering [BIT] NAME - FUNCTION [7] Reserved [6] WOM_INT 1 – Wake on motion interrupt occurred. [5] Reserved [4] FIFO_OVERFLOW_INT 1 – Fifo Overflow interrupt occurred. Note that the oldest data is has been dropped from the fifo. [3] FSYNC_INT 1 – Fsync interrupt occurred. [2] Reserved [1] Reserved [0] RAW_DATA_RDY_INT 1 – Sensor Register Raw Data sensors are updated and Ready to be read. The timing of the interrupt can vary depending on the setting in register 36 I2C_MST_CTRL, bit [6] WAIT_FOR_ES.

Note that the "Reserved" Interrupt Bits can be changed by the DMP Firmware and DMP Packet ready is one of the Reserved bits I can't remember which off the top of my head.

So while not a big deal we are getting 2 interrupts per cycle instead of one and we just have to deal with it... I have not found a way to just get the DMP packet ready interrupt

Homer

paynterf commented 4 years ago

Homer,

When I ran the code to look at at the actual interrupt register, all I got was '1's and '0's, as shown below:

Msec NumInt IntReg 5967 2 1 5968 2 0 5969 2 0 5969 2 0 5970 2 0 5971 3 1 5972 3 0 5972 3 0 5974 3 0 5975 3 0 5975 3 0 5976 3 0 5977 4 1 5978 4 0 5978 4 0 5979 4 0 5980 4 0 5981 4 0 5981 5 1 5982 5 0 5983 5 0 5984 5 0 5984 5 0 5985 5 0 5986 5 0 5987 6 1 5987 6 0 5988 6 0 5989 6 0 5990 6 0 5990 6 0 5991 7 1 5992 7 0 5993 7 0 5993 7 0 5994 7 0 5995 7 0 5996 7 0 5996 8 1 5997 8 0 5998 8 0 5999 8 0 5999 8 0 6000 8 0 6001 9 1 6002 9 0 6002 9 0 6003 9 0 6004 9 0 6005 9 0 6005 9 0 6006 10 1

It looks like interrupts are occurring every 5 mSec or so (as I had previously determined looking at the interrupts with an O'Scope), but the interrupt register never shows any values but '0' and '1'. Doesn't this indicate that there is only one interrupt source?

Regards,

Frank

On Thu, Oct 24, 2019 at 2:11 AM Homer Creutz notifications@github.com wrote:

Frank, I didn't understand what NumInt was I thought it pertained to an Integer but instead it a counter that watches the Int Pin on the MPU6050 :) I know what is happening.

Msec Yaw NumInt fifoCount

5949 22 336 -0.01 28 0

6061 20 308 -0.01 28 0

6171 20 308 -0.01 28 0

6282 20 308 -0.01 28 0

6392 20 308 -0.01 28 0

6503 20 308 -0.01 28 0

6614 20 308 -0.02 28 0

The time difference is about 110 to 111 ms so only 10 to 11 interrupts should be present but we show 20 twice the interrupts. Well, interrupts are not exclusive to the DMP FIFO packet ready flag and so we see an additional interrupt occurring.

Here are some of the interrupts that can be enabled"

In register 0x38 the following bits represent what interrupts are enabled any of these interrupts will cause the INT pin to change triggering the interrupt

INT_ENABLE_READ_FF_EN Bit 7 1 = Enable interrupt for

INT_ENABLE_READ_WOM_EN Bit 6 1 = Enable interrupt for wake on motion to propagate to interrupt pin. 0 function is disabled.

INT_ENABLE_READ_ZMOT_OFLOW_EN Bit 5 1 = Enable interrupt for

INT_ENABLE_READ_FIFO_OFLOW_EN Bit 4 1 = Enable interrupt for FIFO overflow to propagate to interrupt pin. 0 function is disabled.

INT_ENABLE_READ_FSYNC_INT_EN Bit 3 1 = Enable (I2C_MST_INT_BIT) Fsync interrupt to propagate to interrupt pin. 0 function is disabled.

INT_ENABLE_READ_RAW_PLL_RDY_INT_EN Bit 2 1 = Enable

INT_ENABLE_READ_RAW_DMP_INT_EN Bit 1 1 = Enable

INT_ENABLE_READ_RAW_RDY_EN Bit 0 1 = Enable Raw Sensor Data Ready interrupt to propagate to interrupt pin. 0 function is disabled.

with only 1 bit enables you would think only 1 interrupt could occur. I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x02)); // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on

but when you watch the interrupts you will see that an additional interrupt occurs each cycle

Let's add this line into your code

uint8_t buffer;

I2Cdev::readByte(devAddr, MPU6050_RA_DMP_INT_STATUS, buffer);

Serial.print(buffer,BIN);

This will give you what interrupts are triggering [BIT] NAME - FUNCTION [7] Reserved [6] WOM_INT 1 – Wake on motion interrupt occurred. [5] Reserved [4] FIFO_OVERFLOW_INT 1 – Fifo Overflow interrupt occurred. Note that the oldest data is has been dropped from the fifo. [3] FSYNC_INT 1 – Fsync interrupt occurred. [2] Reserved [1] Reserved [0] RAW_DATA_RDY_INT 1 – Sensor Register Raw Data sensors are updated and Ready to be read. The timing of the interrupt can vary depending on the setting in register 36 I2C_MST_CTRL, bit [6] WAIT_FOR_ES.

Note that the "Reserved" Interrupt Bits can be changed by the DMP Firmware and DMP Packet ready is one of the Reserved bits I can't remember which off the top of my head.

So while not a big deal we are getting 2 interrupts per cycle instead of one and we just have to deal with it... I have not found a way to just get the DMP packet ready interrupt

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T324XG3L6CUEXRTWB2ZDQQE4BVA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECD2P6Q#issuecomment-545761274, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T322NR33KBRGQARWDNHLQQE4BVANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)

ZHomeSlice commented 4 years ago

Frank, let's try an experiment

define DMP_INT_CONTINUOUS (0x02) // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on

It looks like the only interrupt indicator that appears is the [0] RAW_DATA_RDY_INT 1 when bit 0 is true we get only the 00000001B Instead of another Binary number. let's assume that 2 interrupts are occurring one for a DMP timer and another for the actual DMP "raw" data becoming ready.

Theory basis for the timer in document eMDv5.11 APIs Specification (embedded Motion Driver) (Same DMP Code as 6.11)

we find the following statement for int dmp_set_interrupt_mode (unsigned char mode)

A DMP interrupt can be configured to trigger on either of the two conditions below: a. One FIFO period has elapsed (set by mpu_set_sample_rate). <<< its a timer? b. is irrelevant as it pertains to taps

let's assume that this is just a timer and the real raw data interrupt and it was misplaced on this bit Zero. I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x02)); // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on change to I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x00)); // 0000 0000 no interrupt enable bit then change to I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x01)); // 0000 0001 INT_ENABLE: RAW_DATA_READY_INT_EN on

Let's use your code above to prove this theory

    // load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();
//<<< Place it here <<<
I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x00)); // 0000 0000 no interrupt enable bit 
// or 
// I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x01)); // 0000 0001 INT_ENABLE: 

Whats the results for each? Can we just get 1 interrupt every 10 MS ?

Homer

paynterf commented 4 years ago

Homer,

OK, I made this change in MPU6060_6Axis_MotionApps_V6_12.

//I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x02)); // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x00)); // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on //gfp 10/24/19 chg to 0x00

And with this code:

// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();

uint8_t val;
I2Cdev::writeBytes(devAddr, 0x38, 1, &(val = 0x01)); // 0000 0001

INT_ENABLE: RAW_DATA_READY_INT_EN on

I get

Msec NumInt IntReg

5945 0 1 5946 0 1 5947 0 0 5947 0 0 5948 0 0 5949 0 0 5950 0 0 5950 0 0 5951 0 1 5952 0 0 5953 0 0 5953 0 0 5954 0 0 5955 0 0 5956 0 0 5956 0 1 5957 0 0 5958 0 0 5959 0 0 5959 0 0 5960 0 0 5961 0 1 5962 0 0 5962 0 0 5963 0 0 5964 0 0 5965 0 0 5965 0 0 5966 0 1 5967 0 0 5968 0 0 5968 0 0 5969 0 0 5970 0 0 5971 0 1 5971 0 0 5972 0 0 5974 0 0 5975 0 0 5975 0 0 5976 0 0 5977 0 1

i.e. one non-zero result every 5 mSec

With this code:

I2Cdev::writeBytes(devAddr, 0x38, 1, &(val = 0x00)); // 0000 0000 no interrupt enable bit

I get:

Msec NumInt IntReg

5799 0 1 5800 0 0 5801 0 1 5801 0 0 5803 0 0 5804 0 0 5805 0 0 5805 0 0 5806 0 0 5807 0 1 5808 0 0 5808 0 0 5809 0 0 5810 0 0 5811 0 0 5811 0 1 5812 0 0 5813 0 0 5814 0 0 5814 0 0 5815 0 0 5816 0 0 5817 0 1 5817 0 0 5818 0 0 5819 0 0 5820 0 0 5820 0 0 5821 0 1

i.e. one non-zero result every 5 mSec

However, the number of interrupts never increments! I also checked with my O'Scope, and don't see any activity on my interrupt monitoring line. So, I undid the changes in MPU6060_6Axis_MotionApps_V6_12.h and re-ran the program using

this code:

I2Cdev::writeBytes(devAddr, 0x38, 1, &(val = 0x00)); // 0000 0000 no interrupt enable bit

I get:

Msec NumInt IntReg

5943 2 1 5944 2 0 5944 2 0 5945 2 0 5946 2 0 5947 3 1 5947 3 0 5948 3 0 5949 3 0 5950 3 0 5950 3 0 5951 4 1 5952 4 0 5952 4 0 5953 4 0 5954 4 0 5955 4 0 5955 4 0 5956 5 1 5957 5 0 5958 5 0 5958 5 0 5959 5 0 5960 5 0 5961 6 1 5961 6 0 5962 6 0 5963 6 0 5964 6 0 5964 6 0 5965 6 0 5966 7 1 5967 7 0 5967 7 0 5968 7 0 5969 7 0 5970 7 0 5970 8 1 5971 8 0

So, still getting about one non-zero result ever 5 mSec, but now the interrupt monitoring line shows a pulse every 5 mSec

So, no idea what is happening, but it's clear that the MPU insists on producing at least one non-zero result every 5 mSec, whether or not interrupts are enabled. However, in the first two cases above, those non-zero results are just as clearly NOT interrupts!

Sounds like we're on the track of something, but I don't have a clue what it is! ;-).

Frank

On Thu, Oct 24, 2019 at 11:29 AM Homer Creutz notifications@github.com wrote:

Frank, let's try an experiment

define DMP_INT_CONTINUOUS (0x02)

It looks like the only interrupt indicator that appears is the [0] RAW_DATA_RDY_INT 1 when bit 0 is true we get only the 00000001B Instead of another Binary number. let's assume that 2 interrupts are occurring one for a DMP timer and another for the actual DMP "raw" data becoming ready.

Theory basis for the timer in document eMDv5.11 APIs Specification (embedded Motion Driver) (Same DMP Code as 6.11)

we find the following statement for int dmp_set_interrupt_mode (unsigned char mode)

A DMP interrupt can be configured to trigger on either of the two conditions below: a. One FIFO period has elapsed (set by mpu_set_sample_rate). <<< its a timer? b. is irrelevant as it pertains to taps

let's assume that this is just a timer and the real raw data interrupt and it was misplaced on this bit Zero. I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x02)); // 0000 0010 INT_ENABLE: RAW_DMP_INT_EN on change to I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x00)); // 0000 0000 no interrupt enable bit then change to I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x01)); // 0000 0001 INT_ENABLE: RAW_DATA_READY_INT_EN on

Let's use your code above to prove this theory

// load and configure the DMP Serial.println(F("Initializing DMP...")); devStatus = mpu.dmpInitialize(); //<<< Place it here <<< I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x00)); // 0000 0000 no interrupt enable bit // or // I2Cdev::writeBytes(devAddr,0x38, 1, &(val = 0x01)); // 0000 0001 INT_ENABLE:

Whats the results for each? Can we just get 1 interrupt every 10 MS ?

Homer

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T324YPYNKXHN2RFUOA73QQG5MBA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECFOBBQ#issuecomment-545972358, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T32Y4JI3Q2ZIIZ4ME6DLQQG5MBANCNFSM4I6XC3RA .

-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)