Confusing line in MPU6050_DMP6 example
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
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.
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 [email protected] 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)
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
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 [email protected] 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)
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
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 [email protected] 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)
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
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 [email protected] 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)
Frank, tomorrow I'll be traveling Keep us informed I may be slow to respond. Homer
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 [email protected] 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)
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
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 [email protected] 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)
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 [email protected] 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 [email protected] 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)
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
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 [email protected] 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)
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 308. Oops! ;-)
Frank
On Tue, Oct 15, 2019 at 8:36 AM Frank Paynter [email protected] 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 [email protected] 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)
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
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 [email protected] 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)
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
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 [email protected] 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)
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 [email protected] 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 [email protected] 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)
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
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 [email protected] 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)
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
Homer,
I'm not quite sure I understand the intention here. If I understand the situation correctly,
- Corrupted packets cannot exist unless the FIFO has overflowed at least once since last reset (or cleared via your procedure)
- A non-modular FIFO count could be caused by calling mpu.getFifoCount() before the MPU has finished writing the packet. Reading the FIFO count again after a 200 uSec delay will confirm the issue one way or the other. A non-modular FIFO count after confirming with a second, delayed call to mpu.getFIFOCount() is a certain indicator of FIFO overflow.
- a FIFO count == MAX_FIFO_BYTES is also a certain indicator of FIFO overflow
- Once a non-modular count condition is confirmed, there are only two
ways to continue extracting valid MPU data:
- Reset the FIFO entirely with mpu.ResetFIFO()
- Remove (fifoCount % packSize) + packetSize bytes from the buffer, thus resynching the FIFO 'start' pointer with the start of the first valid packet, and then extract all the remaining packets resulting in a FIFO count of zero, with the last packet read representing the most recent IMU results.
If the above is a complete description of the situation, then I'm not sure why the following algorithm wouldn't work:
- call mpu.GetFIFOCount() repeatedly with a delay of 200 uSec between calls, until two subsequent calls get the same results
- If fifoCount < packetSize, do nothing
- if fifoCount % packetSize != 0 (non-modular) remove (fifoCount % packetSize) + packetSize bytes
- 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
- 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 [email protected] 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);
}
Frank, My thoughts
a FIFO count == MAX_FIFO_BYTES is also a certain indicator of FIFO overflow
-
a FIFO count == MAX_FIFO_BYTES is the only certain indicator of FIFO overflow. We should carefully check after removing extra (old) packets and corrupted packets that the buffer isn't being written to during our retrieval of data. (Thoughts might be a before check of the FIFO count then again an after as there is a chance that the FIFO Buffer size changes during our attempt to catch up)
-
When the buffer isn't full but it is to the point that the next packet will corrupt the FIFO Buffer we need to be extra cautious. The packets are still good but we could face a problem before we clear enough space for the next packet.
-
If we are between Max Packets and MAX_FIFO_BYTES we are at a fail point and must take action after the packet is written. reading the buffer and not taking any action we could be left with corrupted data.
-
all other times the data isn't corrupted even during the time a new packet is being written.
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
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
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
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 [email protected] 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)
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 [email protected] 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 [email protected] 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)
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
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 [email protected] 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)
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 [email protected] 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 [email protected] 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)
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.
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 [email protected] 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)
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
Homer,
I think our emails crossed ;-)
Frank
On Mon, Oct 21, 2019 at 12:55 PM Homer Creutz [email protected] 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)
Homer,
I think it might be useful at this point to try and summarize where I think we are at the moment
- You have clearly created an effective algorithm for detecting and recovering from FIFO overflow events, and the subroutine that implements your algorithm can be used in an interrupt-driven or polling configuration. I personally like the polling arrangement because it requires one less connecting wire, and removes the need for an ISR.
- I believe we have both demonstrated that the algorithm works as designed, but the loop delay required to just trigger FIFO overflows in my configuration is almost exactly twice the delay needed for yours. This needs to be explained.
- There is still the problem of a factor of 2 error between the expected return from mpu.getFIFOCount() and the number calculated by multiplying the number of interrupts times the expected packet length. This also needs to be explained.
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 [email protected] wrote:
Homer,
I think our emails crossed ;-)
Frank
On Mon, Oct 21, 2019 at 12:55 PM Homer Creutz [email protected] 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)
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.
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 ...
-
I've performed more accurate testing microsecond
-
I've added an auto-tuning for an accurate replacement to the interrupt routine without polling the MPU over i2c constantly and a way to remove it if it is not desired or needed sample time > 10ms
-
I've removed extra calls to the MPU as either they were redundant or a non-issue as even if the remainder was there it didn't matter because the complete packets were not corrupted.
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
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.
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 [email protected] 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 overflow0) 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)
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
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 [email protected] 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)
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
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 [email protected] 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)
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
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 [email protected] 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)
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
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 [email protected] 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)
Frank, This is where it should be controlled as far as I can tell everything points to here. Thanks for running these tests. I believe I got similar results. I remember trying things like this as I created the SimpleMPU6050 library, but I still can't figure out why the second interrupt occurs... I believe that the best option would be to Check after any interrupt for fifo count and bail if nothings there. I'm at a loss as to how to crack this one. :) Homer
Homer,
When I was a research scientist at The Ohio State University ElectroScience Lab (an antennas & radar research lab), we lived for experiments that returned anomalous results; that often meant some discovery was in the works. In this case we have experimental results that neither of us can explain, which means that we are about to discover something new about the MPU6050 chip, assuming we care enough to run it down and form a testable theory about the unexplained behavior.
I'm not sure I care enough to run it down, as I mainly wanted to achieve reliable non-interrupt (polling) based operation for my application. However, I will leave you with this interesting observation: It appeared to me that the MPU6050 does something approximately every 5 mSec that causes a non-zero result in the interrupt register (I think that was the one you had me checking), whether or not the DMP interrupt function was enabled.
I believe that something is to load data into the FIFO. If the DMP interrupt is enabled, then those interrupts occur every 5 mSec, at exactly the same rate as the activity that occurs without the interrupt enabled. In other words, the interrupt emitted by the DMP says "hey, I just loaded some more data into the FIFO". I think we have all been assuming all this time that 'some more' meant 'one entire packet', but I, for one, no longer believe that. I believe that the DMP loads only 14 bytes (1/2 packet) into the FIFO every 5 mSec, averaging about 100 packets/sec.
Anyway, it's been fun so far, and I do hope someone eventually clears up the mystery. Now I have to get back to 'real life' - getting my MPU6050 to co-exist peacefully with my robot's wheel motors and motor driver ;-).
Regards,
Frank
On Fri, Oct 25, 2019 at 12:54 AM Homer Creutz [email protected] wrote:
Frank, This is where it should be controlled as far as I can tell everything points to here. Thanks for running these tests. I believe I got similar results. I remember trying things like this as I created the SimpleMPU6050 library, but I still can't figure out why the second interrupt occurs... I believe that the best option would be to Check after any interrupt for fifo count and bail if nothings there. I'm at a loss as to how to crack this one. :) 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=AA6T323OPSDLVNRXP4RJOL3QQJ3XPA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECHFUAQ#issuecomment-546200066, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T32ZZOKYKC6O3Z7XHZ5LQQJ3XPANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank,
It appeared to me that the MPU6050 does something approximately every 5 mSec that causes a non-zero result in the interrupt register (I think that was the one you had me checking), whether or not the DMP interrupt function was enabled.
This is the ultimate mystery. I feel that I discovered at one point in time what the extra interrupt was indicating. I believe that if we were to remove the DMP code and just run the MPU6050 with stock features that an interrupt will still occur. I ran across this before and dug into it to the point I shifted gears as it has another purpose and I just had to ignore the extra interrupt.
I believe that the DMP loads only 14 bytes (1/2 packet) into the FIFO every 5 mSec, averaging about 100 packets/sec.
With this, I have proof to the contrary. The trick I use in the code to detect the exact moment the buffer is full uses 2 calls to getFIFOCount and it only takes a few microseconds to fill but it can be detected. I'm intentionally looking for the fill point adjusting the timers to discover it.
uint8_t MPU6050::GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
.... startup code here
do {
if (Error = (fifoC = getFIFOCount()) % length) { //Something has appeared but its not complete
... overflow code here which we do a slow i2c call for overflow bit giving the buffer time to fill
... overflow at this time is irrelevant as the buffer just got its first bit of data it's just not a complete packet.
}
if(fifoC == 0 && (fifoC = getFIFOCount())){ // During the first test only a partial packet of data was present above but now that we have the full packet we have the Timing is perfect!!!
... all the rest
}
This is during my fast loop no delay testing where we were looping through this function about 700 times every 10 ms with the timer present without the timer we only get about 30 tests every 10 milliseconds
I'm planning on adding 2 functions to the MPU6050 library both are overflow proof one adds additional tests to provide additional delay code using what I mentioned above to allow the i2c bus to be silent and also precisely request at the moment of Packet completion the fifo data. this using a blink without delay timer instead of physical interrupts. The timing function will call the second general overflow function. to keep duplicate code to a minimum.
Homer
Homer,
OK, so you are convinced the DMP loads full 28-byte packets - then what explains the disparity between the interrupt counts and FIFO counts I was getting? Either the interrupt count is wrong by a factor of two, or the FIFO count is wrong by a factor of two; which is it?
Inquiring minds want to know! ;-)
Frank
On Sat, Oct 26, 2019 at 2:14 PM Homer Creutz [email protected] wrote:
Frank,
It appeared to me that the MPU6050 does something approximately every 5 mSec that causes a non-zero result in the interrupt register (I think that was the one you had me checking), whether or not the DMP interrupt function was enabled.
This is the ultimate mystery. I feel that I discovered at one point in time what the extra interrupt was indicating. I believe that if we were to remove the DMP code and just run the MPU6050 with stock features that an interrupt will still occur. I ran across this before and dug into it to the point I shifted gears as it has another purpose and I just had to ignore the extra interrupt.
I believe that the DMP loads only 14 bytes (1/2 packet) into the FIFO every 5 mSec, averaging about 100 packets/sec.
With this, I have proof to the contrary. The trick I use in the code to detect the exact moment the buffer is full uses 2 calls to getFIFOCount and it only takes a few microseconds to fill but it can be detected. I'm intentionally looking for the fill point adjusting the timers to discover it.
uint8_t MPU6050::GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof .... startup code here do { if (Error = (fifoC = getFIFOCount()) % length) { //Something has appeared but its not complete ... overflow code here which we do a slow i2c call for overflow bit giving the buffer time to fill ... overflow at this time is irrelevant as the buffer just got its first bit of data it's just not a complete packet. } if(fifoC == 0 && (fifoC = getFIFOCount())){ // During the first test only a partial packet of data was present above but now that we have the full packet we have the Timing is perfect!!! ... all the rest }
This is during my fast loop no delay testing where we were looping through this function about 700 times every 10 ms with the timer present without the timer we only get about 30 tests every 10 milliseconds
I'm planning on adding 2 functions to the MPU6050 library both are overflow proof one adds additional tests to provide additional delay code using what I mentioned above to allow the i2c bus to be silent and also precisely request at the moment of Packet completion the fifo data. this using a blink without delay timer instead of physical interrupts. The timing function will call the second general overflow function. to keep duplicate code to a minimum.
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=AA6T32YDWKSPYALSXWOXUC3QQSCIDA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECKN2GI#issuecomment-546626841, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T326IDKI4HFNNQHAIHGTQQSCIDANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank,
Either the interrupt count is wrong by a factor of two, or the FIFO count is wrong by a factor of two; which is it?
Interrupt triggers a second time for some unknown reason. I'm ignoring the interrupts completely with our code as it is not needed.
I'm creating 2 examples that will be added to the library shortly. I've also decided to create 2 complete separate functions 1 for projects like yours that only need the data once in a while and the second function uses a blink without delay timer that fine-tunes itself to match the 10ms interrupt trigger without even looking at the interrupt trigger. I use the FIFO count to find the sweet spot. the second function has some overhead to accomplish this but it is still fast. faster than polling the MPU6050 over i2c. It may even be faster than using interrupts although that hasn't been tested. I will need to make a 3rd function with overflow protection for use with interrupts before all is done. All I can say is wow this is coming together quite nicely. Thank you for your help.
Homer
UPDATE Submitted pull request: Overflow protection & no interrupts code with examples
Homer,
I'm really glad that I could help, but I was just the lab tech in this project. You were the guy making the magic happen ;-).
I agree on the idea of ignoring interrupts - polling is now just as reliable, thanks to you, and requires one less pin and no ISR.
However, your idea of 'a second interrupt occurs for some unknown reason, doesn't hold water. O'Scope monitoring of the interrupt line shows an interrupt occurring every 5 m Sec, which (with a 100 mSec loop delay time) should produce about 20-22 interrupts per printout. This agrees very closely with the actual measured value of 21-22. The FIFO count is the number returned from the 'getFIFOCount()' function.
I guess this will remain a mystery ;-).
Frank
On Sat, Oct 26, 2019 at 11:13 PM Homer Creutz [email protected] wrote:
Frank,
Either the interrupt count is wrong by a factor of two, or the FIFO count is wrong by a factor of two; which is it?
Interrupt triggers a second time for some unknown reason. I'm ignoring the interrupts completely with our code as it is not needed.
I'm creating 2 examples that will be added to the library shortly. I've also decided to create 2 complete separate functions 1 for projects like yours that only need the data once in a while and the second function uses a blink without delay timer that fine-tunes itself to match the 10ms interrupt trigger without even looking at the interrupt trigger. I use the FIFO count to find the sweet spot. the second function has some overhead to accomplish this but it is still fast. faster than polling the MPU6050 over i2c. It may even be faster than using interrupts although that hasn't been tested. I will need to make a 3rd function with overflow protection for use with interrupts before all is done. All I can say is wow this is comming together quite nicely. Thank you for your help.
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=AA6T32ZGO2BC7KDXAUA2LWLQQUBM3A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECKVLGY#issuecomment-546657691, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327CPGCKVYWKB7HOBUTQQUBM3ANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank, I have another overflow proof sequence that is simpler and faster!
/** Get latest byte from FIFO buffer no matter how much time has passed.
* === GetCurrentFIFOPacket ===
* ================================================================
* Returns 1) when data was received
* 0) when no valid data is available
* ================================================================ */
// put your main code here, to run repeatedly:
uint8_t MPU6050::GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
uint16_t fifoC;
uint8_t Error;
uint8_t Flag = 0;
uint8_t overflowed = 0;
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
if ((fifoC = getFIFOCount()) > length) {
while (fifoC > length) { // Shrink down to 1 packet
getFIFOBytes(data, length);
fifoC--;
}
if ((fifoC = getFIFOCount()) > length) {
while (fifoC > length) { // We got more data while we were shrinking
getFIFOBytes(data, length);
fifoC--;
}
if ((fifoC = getFIFOCount()) > length) {
while (fifoC > length) {// we need to be sure, but this shouldn't happen... Shrink some more
getFIFOBytes(data, length);
fifoC--;
}
}
}
}
while (fifoC && (fifoC < length)) fifoC = getFIFOCount(); //Finish loading the packet!
//we have only 1 packet!
if (fifoC == length) {
getFIFOBytes(data, length);
return 1;
}
return 0;
}
Try it out and let me know what you think Homer
Homer,
It works ok up until the loop delay gets past 350 mSec, and then the packets become corrupted, as shown in the following plot:
[image: 191029_YawVsTimeVsLoopDelay.jpg]
Here's the code that I used for this:
void setup() { // initialize serial communication Serial.begin(115200); while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device Serial.println(F("Initializing I2C devices...")); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT);
// verify connection Serial.println(F("Testing device connections...")); Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
//// wait for ready //Serial.println(F("\nSend any character to begin DMP programming and demo: ")); //while (Serial.available() && Serial.read()); // empty buffer //while (!Serial.available()); // wait for data //while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP Serial.println(F("Initializing DMP...")); devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity mpu.setXGyroOffset(51); mpu.setYGyroOffset(8); mpu.setZGyroOffset(21); mpu.setXAccelOffset(1150); mpu.setYAccelOffset(-50); mpu.setZAccelOffset(1060);
// make sure it worked (returns 0 if so) if (devStatus == 0) { // Calibration Time: generate offsets and calibrate our MPU6050 mpu.CalibrateAccel(6); mpu.CalibrateGyro(6); Serial.println(); mpu.PrintActiveOffsets(); // turn on the DMP, now that it's ready Serial.println(F("Enabling DMP...")); mpu.setDMPEnabled(true);
// get expected DMP packet size for later comparison packetSize = mpu.dmpGetFIFOPacketSize(); mySerial.printf("FIFO packet size = %d\n", packetSize); mySerial.printf("Loop Delay Duration = %d\n", MAX_LOOP_DELAY_MSEC); } else { // ERROR! // 1 = initial memory load failed // 2 = DMP configuration updates failed // (if it's going to break, usually the code will be 1) Serial.print(F("DMP Initialization failed (code ")); Serial.print(devStatus); Serial.println(F(")")); }
// configure pins for output pinMode(LED_PIN, OUTPUT); pinMode(INT_MONITOR_PIN, OUTPUT);
//mySerial.printf("\nMsec\tCnt\tX\tY\n"); mySerial.printf("\nMsec\tYaw\tFlag\n"); startMsec = millis(); MsecSinceLastYawCheck = 0;
for (int loopDelayMsec = 0; loopDelayMsec < MAX_LOOP_DELAY_MSEC; loopDelayMsec = loopDelayMsec + 50) { delay(loopDelayMsec); //mySerial.printf("Loop Delay = %d\n", loopDelayMsec); for (size_t i = 0; i < 10; i++) { int retval = GetCurrentFIFOPacket(fifoBuffer, packetSize);
// display Euler angles in degrees mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); float yawval = ypr[0] * 180 / M_PI;
mySerial.printf("%d\t%lu\t%3.2f\t%d\n", loopDelayMsec, millis(), yawval, retval); } }
mySerial.printf("Stopping...\n"); while (1) {
} }
By the way, I figured out at least part of the 'off by a factor 2' mystery. I set up the program to call mpu.GetFIFOCount() as rapidly as possible and saved the results in an array for later printout. The results show that the FIFO count does indeed change in whole packet increments, but it only changes every 10 mSec (I think you actually mentioned this way back at the start of this thread). However, the interrupt line emits interrupt pulses every 5 mSec, and that is the reason for the discrepancy - the MPU6050 only loads a packet into the FIFO every other interrupt for some unknown reason. So, I've solved one mystery, but all it did was uncover another one! ;-)
Plot and the relevant code are shown below:
[image: 191029_FIFOCountChangeIntervalVsTime.jpg]
void loop() { while (loopCount < MAX_LOOP_COUNT) { uint16_t mSec = millis(); mSecArray[loopCount] = mSec; fifoCount = mpu.getFIFOCount(); countArray[loopCount] = fifoCount; loopCount++; digitalWrite(LED_PIN, !digitalRead(LED_PIN)); }
for (size_t i = 0; i < loopCount; i++) { mySerial.printf("%d\t%d\t%d\n", i,mSecArray[i], countArray[i]); }
mySerial.printf("Stopping...\n"); while (1) {
}
}
Thoughts?
Regards,
Frank
PS: I put a lot of this up on my Wordpress site, but I changed it's status back to DRAFT to give you time to fix the problem, assuming it's your problem and not something I did.
On Mon, Oct 28, 2019 at 10:46 AM Homer Creutz [email protected] wrote:
Frank, I have another overflow proof sequence that is simpler and faster!
/** Get latest byte from FIFO buffer no matter how much time has passed.
- === GetCurrentFIFOPacket ===
- ================================================================
- Returns 1) when data was received
0) when no valid data is available- ================================================================ */ // put your main code here, to run repeatedly: uint8_t MPU6050::GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint16_t fifoC; uint8_t Error; uint8_t Flag = 0; uint8_t overflowed = 0; uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
if ((fifoC = getFIFOCount()) > length) { while (fifoC > length) { // Shrink down to 1 packet getFIFOBytes(data, length); fifoC--; fifoC = getFIFOCount(); } if ((fifoC = getFIFOCount()) > length) { while (fifoC > length) { // We got more data while we were shrinking getFIFOBytes(data, length); fifoC--; fifoC = getFIFOCount(); } if ((fifoC = getFIFOCount()) > length) { while (fifoC > length) {// we need to be sure, but this shouldn't happen... Shrink some more getFIFOBytes(data, length); fifoC--; fifoC = getFIFOCount(); } } } } while (fifoC && (fifoC < length)) fifoC = getFIFOCount(); //Finish loading the packet! //we have only 1 packet! if (fifoC == length) { getFIFOBytes(data, length); return 1; } return 0; }
Try it out and let me know what you think 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=AA6T326X5K2PTR564HPONILQQ33L7A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECNEBII#issuecomment-546980001, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T325HYGZN2TASPPSYZVTQQ33L7ANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank, Try this New and improved Version out: Why didn't I think of it this way in the first place :)
/** Get latest byte from FIFO buffer no matter how much time has passed.
* === GetCurrentFIFOPacket ===
* ================================================================
* Returns 1) when data was received
* 0) when no valid data is available
* ================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
uint16_t fifoC;
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) { // Shrink down to 1 packet
mpu.getFIFOBytes(data, length);
fifoC--;
}
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) { // We got more data while we were shrinking
mpu.getFIFOBytes(data, length);
fifoC--;
}
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) {// we need to be sure, but this shouldn't happen... Shrink some more
mpu.getFIFOBytes(data, length);
fifoC--;
}
}
}
}
while (fifoC && (fifoC < length)) fifoC = mpu.getFIFOCount(); //Finish loading the packet!
//we have only 1 packet!
if (fifoC == length) {
mpu.getFIFOBytes(data, length);
return 1;
}
return 0;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
while (Serial.available() && Serial.read()); // empty buffer
while (!Serial.available()); // wait for data
while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(51);
mpu.setYGyroOffset(8);
mpu.setZGyroOffset(21);
mpu.setXAccelOffset(1150);
mpu.setYAccelOffset(-50);
mpu.setZAccelOffset(1060);
if (devStatus == 0) {
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
Serial.println();
mpu.PrintActiveOffsets();
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
dmpReady = true;
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
uint32_t startMsec, MsecSinceLastYawCheck;
startMsec = millis();
MsecSinceLastYawCheck = 0;
for (int loopDelayMsec = 0; loopDelayMsec < 500; loopDelayMsec = loopDelayMsec + 1) {
delay(loopDelayMsec);
for (size_t i = 0; i < 10; i++) {
while (! GetCurrentFIFOPacket(fifoBuffer, packetSize));
Serial.print(loopDelayMsec);
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);
Serial.println();
}
}
while (1);
}
Homer
Homer,
Looks good to me. Here's a plot of the results. During the test, I was manually moving the sensor back and forth
[image: 191029_YawVsTimeVsLoopDelay2.jpg]
Also, just to confess my sins, I had an error in my first program - I didn't skip the iterations where your function returned zero. I went back and re-ran that test, with the following results (sensor motionless the entire time). It looks better, but still dies with a loop delay of 450 mSec or more. The reason there are so few values displayed for 450 & 500 mSec is because most calls to GetCurrentFIFOPacket() failed and got skipped (apparently all of the 400 mSec delay iterations were skipped). Here's the tail end of the data showing the failures.
350 8417 -0.13 1 350 8429 -0.13 1 350 8442 -0.13 1 350 8456 -0.13 1 350 8469 -0.13 1 350 8481 -0.13 1 350 8496 -0.13 1 350 8508 -0.13 1 350 8521 -0.13 1 350 8535 -0.13 1 350 8548 -0.13 1 350 8560 -0.13 1 350 8574 -0.13 1 350 8587 -0.13 1 350 8600 -0.14 1 350 8613 -0.14 1 350 8627 -0.14 1 450 10579 -179.56 1 450 10680 179.89 1 500 12208 -179.89 1 500 12447 179.68 1 Stopping...
Port closed
Anyway, your latest version appears to be a winner, especially for my application where a 200 mSec loop delay is fast! ;-).
Frank
On Tue, Oct 29, 2019 at 7:48 PM Homer Creutz [email protected] wrote:
Frank, Try this New and improved Version out: Why didn't I think of it this way in the first place :)
/** Get latest byte from FIFO buffer no matter how much time has passed.
- === GetCurrentFIFOPacket ===
- ================================================================
- Returns 1) when data was received
0) when no valid data is available- ================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint16_t fifoC; if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) { // Shrink down to 1 packet mpu.getFIFOBytes(data, length); fifoC--; } if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) { // We got more data while we were shrinking mpu.getFIFOBytes(data, length); fifoC--; } if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) {// we need to be sure, but this shouldn't happen... Shrink some more mpu.getFIFOBytes(data, length); fifoC--; } } } } while (fifoC && (fifoC < length)) fifoC = mpu.getFIFOCount(); //Finish loading the packet! //we have only 1 packet! if (fifoC == length) { mpu.getFIFOBytes(data, length); return 1; } return 0; }
// ================================================================ // === INITIAL SETUP === // ================================================================
void setup() { // join I2C bus (I2Cdev library doesn't do this automatically) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif Serial.begin(115200); while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device Serial.println(F("Initializing I2C devices...")); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT);
// verify connection Serial.println(F("Testing device connections...")); Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready Serial.println(F("\nSend any character to begin DMP programming and demo: ")); while (Serial.available() && Serial.read()); // empty buffer while (!Serial.available()); // wait for data while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP Serial.println(F("Initializing DMP...")); devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity mpu.setXGyroOffset(51); mpu.setYGyroOffset(8); mpu.setZGyroOffset(21); mpu.setXAccelOffset(1150); mpu.setYAccelOffset(-50); mpu.setZAccelOffset(1060); if (devStatus == 0) { mpu.CalibrateAccel(6); mpu.CalibrateGyro(6); Serial.println(); mpu.PrintActiveOffsets(); Serial.println(F("Enabling DMP...")); mpu.setDMPEnabled(true);
dmpReady = true; packetSize = mpu.dmpGetFIFOPacketSize();} else { Serial.print(F("DMP Initialization failed (code ")); Serial.print(devStatus); Serial.println(F(")")); }
// configure LED for output pinMode(LED_PIN, OUTPUT); uint32_t startMsec, MsecSinceLastYawCheck; startMsec = millis(); MsecSinceLastYawCheck = 0;
for (int loopDelayMsec = 0; loopDelayMsec < 500; loopDelayMsec = loopDelayMsec + 1) { delay(loopDelayMsec); for (size_t i = 0; i < 10; i++) { while (! GetCurrentFIFOPacket(fifoBuffer, packetSize)); Serial.print(loopDelayMsec); 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); Serial.println();
}} while (1); }
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=AA6T3225EAMK53XNWAKNQSTQRDDUTA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECSOO5Q#issuecomment-547678070, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T32YJ22FPIU6OC6WHNGLQRDDUTANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank,
(apparently all of the 400 mSec delay iterations were skipped).
This is interesting... using the mpu6050? email me your test code. Homer
Homer,
Here it is. It has both versions of your GetCurrentFIFOPacket() function, with the newest one commented out. The results with 400 mSec missing are with the currently uncommented version.
I ran it twice more just now, and one time there were 2 corrupted packet lines in the 400 mSec section, and the other there were no 400 mSec results again.
Regards,
Frank
On Wed, Oct 30, 2019 at 11:32 AM Homer Creutz [email protected] wrote:
Frank,
(apparently all of the 400 mSec delay iterations were skipped).
This is interesting... using the mpu6050? email me your test code. 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=AA6T323JXNPK5QTHBLUY3ITQRGSJLA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECUUP6I#issuecomment-547964921, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327JXXDRVJPVZ7WOSTDQRGSJLANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Homer,
I think you might have an error in your newest version of GetCurrentFIFOPacket():
In the section shown in magenta below, I believe the 'length' variable starts out as the packet size (28 in this case). The mpu.GetFIFOBytes(data,length) call will retrieve an entire 28 byte packet each time as long as there are at least 28 bytes in the FIFO, but you are apparently only decrementing fifoC by 1, not by length as I think you should.
If there were, for example, 280 bytes (10 packets) in the FIFO, you would get something like this:
fifoC FIFO length 280 280 279 252 278 224 277 196 .... 271 000 <<<< oops!
In other words, fifoC would never be less than 28, even after removing all the bytes from the FIFO. And, I think you have the same error in the other sections as well.
I Instrumented your code to printout the values of fifoC at the entrance to the first section, and then the decremented fifoC and the real count from the FIFO with mpu.GetFIFOCount(). The result for a small portion of the run is shown below:
fifoC = 56 fifoC-- = 55 FIFO Count = 28 fifoC-- = 54 FIFO Count = 0 fifoC-- = 53 FIFO Count = 0 fifoC-- = 52 FIFO Count = 0 fifoC-- = 51 FIFO Count = 0 fifoC-- = 50 FIFO Count = 0 fifoC-- = 49 FIFO Count = 0 fifoC-- = 48 FIFO Count = 0 fifoC-- = 47 FIFO Count = 0 fifoC-- = 46 FIFO Count = 0 fifoC-- = 45 FIFO Count = 0 fifoC-- = 44 FIFO Count = 0 fifoC-- = 43 FIFO Count = 0 fifoC-- = 42 FIFO Count = 0 fifoC-- = 41 FIFO Count = 0 fifoC-- = 40 FIFO Count = 0 fifoC-- = 39 FIFO Count = 0 fifoC-- = 38 FIFO Count = 0 fifoC-- = 37 FIFO Count = 0 fifoC-- = 36 FIFO Count = 0 fifoC-- = 35 FIFO Count = 0 fifoC-- = 34 FIFO Count = 0 fifoC-- = 33 FIFO Count = 0 fifoC-- = 32 FIFO Count = 0
Am I missing something?
Frank
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) { // Shrink down to 1 packet
mpu.getFIFOBytes(data, length);
fifoC--;
} if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) { // We got more data while we were shrinking mpu.getFIFOBytes(data, length); fifoC--; } if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) {// we need to be sure, but this shouldn't happen... Shrink some more mpu.getFIFOBytes(data, length); fifoC--;
} } } }
On Wed, Oct 30, 2019 at 12:45 PM Frank Paynter [email protected] wrote:
Homer,
Here it is. It has both versions of your GetCurrentFIFOPacket() function, with the newest one commented out. The results with 400 mSec missing are with the currently uncommented version.
I ran it twice more just now, and one time there were 2 corrupted packet lines in the 400 mSec section, and the other there were no 400 mSec results again.
Regards,
Frank
On Wed, Oct 30, 2019 at 11:32 AM Homer Creutz [email protected] wrote:
Frank,
(apparently all of the 400 mSec delay iterations were skipped).
This is interesting... using the mpu6050? email me your test code. 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=AA6T323JXNPK5QTHBLUY3ITQRGSJLA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECUUP6I#issuecomment-547964921, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327JXXDRVJPVZ7WOSTDQRGSJLANCNFSM4I6XC3RA .
-- 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)
Homer,
Hmm, it looks like there is still something funny going on with your code. When I changed 'fifoC--;' to 'fifoC-=length;' and ran the instrumented code again, I got
fifoC = 616 fifoC-- = 588 FIFO Count = 588 fifoC-- = 560 FIFO Count = 560 fifoC-- = 532 FIFO Count = 532 fifoC-- = 504 FIFO Count = 504 fifoC-- = 476 FIFO Count = 504 fifoC-- = 448 FIFO Count = 476 fifoC-- = 420 FIFO Count = 448 fifoC-- = 392 FIFO Count = 420 fifoC-- = 364 FIFO Count = 420 fifoC-- = 336 FIFO Count = 392 fifoC-- = 308 FIFO Count = 364 fifoC-- = 280 FIFO Count = 336 fifoC-- = 252 FIFO Count = 336 fifoC-- = 224 FIFO Count = 308 fifoC-- = 196 FIFO Count = 280 fifoC-- = 168 FIFO Count = 280 fifoC-- = 140 FIFO Count = 252 fifoC-- = 112 FIFO Count = 224 fifoC-- = 84 FIFO Count = 196 fifoC-- = 56 FIFO Count = 196 fifoC-- = 28 FIFO Count = 168
Now fifoC is decrementing correctly, but for some reason mpu.GetFIFOCount() is sometimes not correctly reporting the results of the previous call to mpu.GetFIFOBytes(data, length), or maybe mpu.GetFIFOBytes() doesn't block, and so mpu.GetFIFOCount() returns the same count because mpu.GetFIFOBytes(data, length) hasn't completed?
So, I put a 1 mSec delay in that section between the call to mpu.GetFIFOBytes() and a call to mpu.GetFIFOCount(), and got the following output: fifoC = 336 fifoC-- = 308 FIFO Count = 336 fifoC-- = 280 FIFO Count = 308 fifoC-- = 252 FIFO Count = 308 fifoC-- = 224 FIFO Count = 280 fifoC-- = 196 FIFO Count = 280 fifoC-- = 168 FIFO Count = 252 fifoC-- = 140 FIFO Count = 252 fifoC-- = 112 FIFO Count = 252 fifoC-- = 84 FIFO Count = 224 fifoC-- = 56 FIFO Count = 224 fifoC-- = 28 FIFO Count = 196
Now the problem has actually gotten worse - not better!
So, I think I understand what's going on. The MPU6050 adds a new packet to the FIFO every 10 mSec. So, if it takes longer than 10 mSec to remove a packet, you're always going to lose the race and overflow. When I added a delay, all I did was make extraction slower, so I lost the race faster.
So, I still think fifoC should be decremented by 'length' each time, not by
- However, I now realize that I can't really instrument the code with print statements, as that slows everything down and makes it harder to actually drain the FIFO down to < 1 packet.
Is there any way to temporarily stop the MPU6050 from continuing to add packets to the FIFO? If so, this problem would get *much *easier!
Regards,
Frank
On Wed, Oct 30, 2019 at 3:03 PM Frank Paynter [email protected] wrote:
Homer,
I think you might have an error in your newest version of GetCurrentFIFOPacket():
In the section shown in magenta below, I believe the 'length' variable starts out as the packet size (28 in this case). The mpu.GetFIFOBytes(data,length) call will retrieve an entire 28 byte packet each time as long as there are at least 28 bytes in the FIFO, but you are apparently only decrementing fifoC by 1, not by length as I think you should.
If there were, for example, 280 bytes (10 packets) in the FIFO, you would get something like this:
fifoC FIFO length 280 280 279 252 278 224 277 196 .... 271 000 <<<< oops!
In other words, fifoC would never be less than 28, even after removing all the bytes from the FIFO. And, I think you have the same error in the other sections as well.
I Instrumented your code to printout the values of fifoC at the entrance to the first section, and then the decremented fifoC and the real count from the FIFO with mpu.GetFIFOCount(). The result for a small portion of the run is shown below:
fifoC = 56 fifoC-- = 55 FIFO Count = 28 fifoC-- = 54 FIFO Count = 0 fifoC-- = 53 FIFO Count = 0 fifoC-- = 52 FIFO Count = 0 fifoC-- = 51 FIFO Count = 0 fifoC-- = 50 FIFO Count = 0 fifoC-- = 49 FIFO Count = 0 fifoC-- = 48 FIFO Count = 0 fifoC-- = 47 FIFO Count = 0 fifoC-- = 46 FIFO Count = 0 fifoC-- = 45 FIFO Count = 0 fifoC-- = 44 FIFO Count = 0 fifoC-- = 43 FIFO Count = 0 fifoC-- = 42 FIFO Count = 0 fifoC-- = 41 FIFO Count = 0 fifoC-- = 40 FIFO Count = 0 fifoC-- = 39 FIFO Count = 0 fifoC-- = 38 FIFO Count = 0 fifoC-- = 37 FIFO Count = 0 fifoC-- = 36 FIFO Count = 0 fifoC-- = 35 FIFO Count = 0 fifoC-- = 34 FIFO Count = 0 fifoC-- = 33 FIFO Count = 0 fifoC-- = 32 FIFO Count = 0
Am I missing something?
Frank
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) { // Shrink down to 1 packet
mpu.getFIFOBytes(data, length);
fifoC--;
} if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) { // We got more data while we were shrinking mpu.getFIFOBytes(data, length); fifoC--; } if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) {// we need to be sure, but this shouldn't happen... Shrink some more mpu.getFIFOBytes(data, length); fifoC--;
} } } }
On Wed, Oct 30, 2019 at 12:45 PM Frank Paynter [email protected] wrote:
Homer,
Here it is. It has both versions of your GetCurrentFIFOPacket() function, with the newest one commented out. The results with 400 mSec missing are with the currently uncommented version.
I ran it twice more just now, and one time there were 2 corrupted packet lines in the 400 mSec section, and the other there were no 400 mSec results again.
Regards,
Frank
On Wed, Oct 30, 2019 at 11:32 AM Homer Creutz [email protected] wrote:
Frank,
(apparently all of the 400 mSec delay iterations were skipped).
This is interesting... using the mpu6050? email me your test code. 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=AA6T323JXNPK5QTHBLUY3ITQRGSJLA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECUUP6I#issuecomment-547964921, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327JXXDRVJPVZ7WOSTDQRGSJLANCNFSM4I6XC3RA .
-- 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)
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Homer,
I think I might have figured it out. I modified your function to loop forever (well, up to 100 iterations) to drain the FIFO down to 1 packet. This works great, up until there is enough loop delay to allow the MPU6050 to completely fill the 1024 byte FIFO. At this point, the function can't properly drain down to 1 packet, because there will always be 16 bytes remaining that can't/won't be extracted (not quite sure why, but....).
Here's the modified function:
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint16_t fifoC; uint16_t FIFOCount; uint16_t MAX_TRIES = 100; //magic number for now uint16_t tries = 0; if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length && tries < MAX_TRIES) { // Shrink down to 1 packet mpu.getFIFOBytes(data, length); fifoC-= length; if (fifoC < length) { fifoC = mpu.getFIFOCount(); }
tries++; }
//at this point, either all packets but 1 have been removed, or MAX_TRIES has been exceeded if (tries >= MAX_TRIES) { mySerial.printf("oops! MAX_TRIES exceeded with FIFO count = %d\n", mpu.getFIFOCount()); return 0; } }
mySerial.printf("tries = %d\t FIFO count = %d\n", tries, mpu.getFIFOCount());
while (fifoC && (fifoC < length)) fifoC = mpu.getFIFOCount(); //Finish loading the packet! //we have only 1 packet! if (fifoC == length) { mpu.getFIFOBytes(data, length); return 1; } return 0; }
And here's a partial printout:
300 7763 -0.19 1 tries = 0 FIFO count = 28 300 7777 -0.19 1 tries = 1 FIFO count = 28 300 7791 -0.19 1 tries = 0 FIFO count = 28 300 7804 -0.19 1 tries = 0 FIFO count = 28 300 7818 -0.19 1 tries = 39 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 tries = 2 FIFO count = 16 350 8697 179.73 1 tries = 1 FIFO count = 16
Starting at about 300 mSec loop delay, the code loses the race with the MPU6050, and the FIFO overflows. Now the drain function drains down to less than 28, but there are still 16 bytes remaining, and the mpu.ReadBytes() function starts failing. From then on, the function always fails to produce good packets.
I believe the solution is to check for 0 < fifoC < length, and if so, remove just fifoC bytes from the buffer, leaving exactly zero remaining. When I added this to your function as shown below
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint16_t fifoC; uint16_t FIFOCount; uint16_t MAX_TRIES = 100; //magic number for now uint16_t tries = 0; if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length && tries < MAX_TRIES) { // Shrink down to 1 packet mpu.getFIFOBytes(data, length); fifoC-= length; if (fifoC < length) { fifoC = mpu.getFIFOCount(); if (fifoC > 0 && fifoC < length) { mpu.getFIFOBytes(data, fifoC); } }
tries++; }
//at this point, either all packets but 1 have been removed, or MAX_TRIES has been exceeded if (tries >= MAX_TRIES) { mySerial.printf("oops! MAX_TRIES exceeded with FIFO count = %d\n", mpu.getFIFOCount()); return 0; } }
//mySerial.printf("tries = %d\t FIFO count = %d\n", tries, mpu.getFIFOCount());
while (fifoC && (fifoC < length)) fifoC = mpu.getFIFOCount(); //Finish loading the packet! //we have only 1 packet! if (fifoC == length) { mpu.getFIFOBytes(data, length); return 1; } return 0; }
I get reliable results all the way out to 550 mSec loop delay, as shown in the attached log file.
Thoughts?
Frank
On Wed, Oct 30, 2019 at 3:52 PM Frank Paynter [email protected] wrote:
Homer,
Hmm, it looks like there is still something funny going on with your code. When I changed 'fifoC--;' to 'fifoC-=length;' and ran the instrumented code again, I got
fifoC = 616 fifoC-- = 588 FIFO Count = 588 fifoC-- = 560 FIFO Count = 560 fifoC-- = 532 FIFO Count = 532 fifoC-- = 504 FIFO Count = 504 fifoC-- = 476 FIFO Count = 504 fifoC-- = 448 FIFO Count = 476 fifoC-- = 420 FIFO Count = 448 fifoC-- = 392 FIFO Count = 420 fifoC-- = 364 FIFO Count = 420 fifoC-- = 336 FIFO Count = 392 fifoC-- = 308 FIFO Count = 364 fifoC-- = 280 FIFO Count = 336 fifoC-- = 252 FIFO Count = 336 fifoC-- = 224 FIFO Count = 308 fifoC-- = 196 FIFO Count = 280 fifoC-- = 168 FIFO Count = 280 fifoC-- = 140 FIFO Count = 252 fifoC-- = 112 FIFO Count = 224 fifoC-- = 84 FIFO Count = 196 fifoC-- = 56 FIFO Count = 196 fifoC-- = 28 FIFO Count = 168
Now fifoC is decrementing correctly, but for some reason mpu.GetFIFOCount() is sometimes not correctly reporting the results of the previous call to mpu.GetFIFOBytes(data, length), or maybe mpu.GetFIFOBytes() doesn't block, and so mpu.GetFIFOCount() returns the same count because mpu.GetFIFOBytes(data, length) hasn't completed?
So, I put a 1 mSec delay in that section between the call to mpu.GetFIFOBytes() and a call to mpu.GetFIFOCount(), and got the following output: fifoC = 336 fifoC-- = 308 FIFO Count = 336 fifoC-- = 280 FIFO Count = 308 fifoC-- = 252 FIFO Count = 308 fifoC-- = 224 FIFO Count = 280 fifoC-- = 196 FIFO Count = 280 fifoC-- = 168 FIFO Count = 252 fifoC-- = 140 FIFO Count = 252 fifoC-- = 112 FIFO Count = 252 fifoC-- = 84 FIFO Count = 224 fifoC-- = 56 FIFO Count = 224 fifoC-- = 28 FIFO Count = 196
Now the problem has actually gotten worse - not better!
So, I think I understand what's going on. The MPU6050 adds a new packet to the FIFO every 10 mSec. So, if it takes longer than 10 mSec to remove a packet, you're always going to lose the race and overflow. When I added a delay, all I did was make extraction slower, so I lost the race faster.
So, I still think fifoC should be decremented by 'length' each time, not by 1. However, I now realize that I can't really instrument the code with print statements, as that slows everything down and makes it harder to actually drain the FIFO down to < 1 packet.
Is there any way to temporarily stop the MPU6050 from continuing to add packets to the FIFO? If so, this problem would get *much *easier!
Regards,
Frank
On Wed, Oct 30, 2019 at 3:03 PM Frank Paynter [email protected] wrote:
Homer,
I think you might have an error in your newest version of GetCurrentFIFOPacket():
In the section shown in magenta below, I believe the 'length' variable starts out as the packet size (28 in this case). The mpu.GetFIFOBytes(data,length) call will retrieve an entire 28 byte packet each time as long as there are at least 28 bytes in the FIFO, but you are apparently only decrementing fifoC by 1, not by length as I think you should.
If there were, for example, 280 bytes (10 packets) in the FIFO, you would get something like this:
fifoC FIFO length 280 280 279 252 278 224 277 196 .... 271 000 <<<< oops!
In other words, fifoC would never be less than 28, even after removing all the bytes from the FIFO. And, I think you have the same error in the other sections as well.
I Instrumented your code to printout the values of fifoC at the entrance to the first section, and then the decremented fifoC and the real count from the FIFO with mpu.GetFIFOCount(). The result for a small portion of the run is shown below:
fifoC = 56 fifoC-- = 55 FIFO Count = 28 fifoC-- = 54 FIFO Count = 0 fifoC-- = 53 FIFO Count = 0 fifoC-- = 52 FIFO Count = 0 fifoC-- = 51 FIFO Count = 0 fifoC-- = 50 FIFO Count = 0 fifoC-- = 49 FIFO Count = 0 fifoC-- = 48 FIFO Count = 0 fifoC-- = 47 FIFO Count = 0 fifoC-- = 46 FIFO Count = 0 fifoC-- = 45 FIFO Count = 0 fifoC-- = 44 FIFO Count = 0 fifoC-- = 43 FIFO Count = 0 fifoC-- = 42 FIFO Count = 0 fifoC-- = 41 FIFO Count = 0 fifoC-- = 40 FIFO Count = 0 fifoC-- = 39 FIFO Count = 0 fifoC-- = 38 FIFO Count = 0 fifoC-- = 37 FIFO Count = 0 fifoC-- = 36 FIFO Count = 0 fifoC-- = 35 FIFO Count = 0 fifoC-- = 34 FIFO Count = 0 fifoC-- = 33 FIFO Count = 0 fifoC-- = 32 FIFO Count = 0
Am I missing something?
Frank
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) { // Shrink down to 1 packet
mpu.getFIFOBytes(data, length);
fifoC--;
} if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) { // We got more data while we were shrinking mpu.getFIFOBytes(data, length); fifoC--; } if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) {// we need to be sure, but this shouldn't happen... Shrink some more mpu.getFIFOBytes(data, length); fifoC--;
} } } }
On Wed, Oct 30, 2019 at 12:45 PM Frank Paynter [email protected] wrote:
Homer,
Here it is. It has both versions of your GetCurrentFIFOPacket() function, with the newest one commented out. The results with 400 mSec missing are with the currently uncommented version.
I ran it twice more just now, and one time there were 2 corrupted packet lines in the 400 mSec section, and the other there were no 400 mSec results again.
Regards,
Frank
On Wed, Oct 30, 2019 at 11:32 AM Homer Creutz [email protected] wrote:
Frank,
(apparently all of the 400 mSec delay iterations were skipped).
This is interesting... using the mpu6050? email me your test code. 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=AA6T323JXNPK5QTHBLUY3ITQRGSJLA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECUUP6I#issuecomment-547964921, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T327JXXDRVJPVZ7WOSTDQRGSJLANCNFSM4I6XC3RA .
-- 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)
-- 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)
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 1628, 3192, 4558, 57, 19, 18 Enabling DMP... FIFO packet size = 28 Loop Delay Duration = 600
Msec Yaw Flag 0 1885 -0.01 1 0 1898 -0.01 1 0 1910 -0.01 1 0 1924 -0.01 1 0 1937 -0.01 1 0 1949 -0.01 1 0 1963 -0.01 1 0 1975 -0.01 1 0 1988 -0.01 1 0 2000 -0.01 1 0 2014 -0.01 1 0 2027 -0.01 1 0 2039 -0.01 1 0 2053 -0.01 1 0 2065 -0.01 1 0 2078 -0.01 1 0 2091 -0.01 1 0 2104 -0.01 1 0 2117 -0.01 1 0 2129 -0.01 1 0 2143 -0.01 1 0 2155 -0.01 1 0 2168 -0.01 1 0 2181 0.00 1 0 2194 0.00 1 0 2207 0.00 1 0 2220 0.00 1 0 2232 0.00 1 0 2245 0.00 1 0 2257 0.00 1 0 2271 0.00 1 0 2283 0.00 1 0 2296 0.00 1 0 2309 0.00 1 0 2322 0.00 1 0 2334 0.00 1 0 2348 0.00 1 0 2360 0.00 1 0 2372 0.00 1 0 2385 0.00 1 0 2399 0.00 1 0 2411 0.00 1 0 2423 0.00 1 0 2437 0.00 1 0 2449 0.00 1 0 2461 0.00 1 0 2473 0.00 1 0 2487 -0.00 1 0 2499 -0.00 1 50 2566 -0.00 1 50 2579 -0.00 1 50 2591 -0.00 1 50 2604 -0.00 1 50 2617 -0.00 1 50 2630 -0.00 1 50 2642 -0.00 1 50 2656 -0.00 1 50 2669 -0.00 1 50 2681 -0.00 1 50 2694 -0.00 1 50 2707 -0.00 1 50 2720 -0.00 1 50 2733 -0.00 1 50 2746 -0.00 1 50 2759 -0.00 1 50 2771 -0.01 1 50 2784 -0.01 1 50 2798 -0.01 1 50 2810 -0.01 1 50 2823 -0.01 1 50 2837 -0.01 1 50 2849 -0.01 1 50 2862 -0.01 1 50 2876 -0.01 1 50 2888 -0.01 1 50 2900 -0.01 1 50 2914 -0.01 1 50 2927 -0.01 1 50 2940 -0.01 1 50 2953 -0.01 1 50 2966 -0.01 1 50 2979 -0.01 1 50 2992 -0.01 1 50 3004 -0.01 1 50 3018 -0.01 1 50 3031 -0.01 1 50 3043 -0.01 1 50 3057 -0.01 1 50 3069 -0.01 1 50 3082 -0.01 1 50 3096 -0.01 1 50 3108 -0.01 1 50 3122 -0.01 1 50 3134 -0.01 1 50 3147 -0.01 1 50 3161 -0.01 1 50 3173 -0.01 1 50 3186 -0.01 1 50 3200 -0.01 1 100 3319 -0.01 1 100 3333 -0.01 1 100 3346 -0.01 1 100 3359 -0.01 1 100 3372 -0.01 1 100 3385 -0.01 1 100 3398 -0.01 1 100 3410 -0.01 1 100 3424 -0.01 1 100 3437 -0.01 1 100 3450 -0.01 1 100 3463 -0.01 1 100 3476 -0.01 1 100 3489 -0.01 1 100 3502 -0.01 1 100 3516 -0.01 1 100 3528 -0.01 1 100 3542 -0.01 1 100 3555 -0.01 1 100 3567 -0.01 1 100 3580 -0.01 1 100 3593 -0.01 1 100 3607 -0.01 1 100 3619 -0.01 1 100 3633 -0.01 1 100 3646 -0.01 1 100 3658 -0.01 1 100 3672 -0.01 1 100 3685 -0.01 1 100 3698 -0.01 1 100 3710 -0.01 1 100 3725 -0.01 1 100 3737 -0.01 1 100 3750 -0.01 1 100 3763 -0.01 1 100 3776 -0.01 1 100 3789 -0.01 1 100 3802 -0.01 1 100 3815 -0.01 1 100 3828 -0.01 1 100 3842 -0.01 1 100 3855 -0.01 1 100 3867 -0.01 1 100 3880 -0.01 1 100 3893 -0.01 1 100 3906 -0.01 1 100 3919 -0.01 1 100 3932 -0.01 1 100 3945 -0.01 1 100 3958 -0.01 1 150 4131 -0.01 1 150 4146 -0.01 1 150 4159 -0.01 1 150 4171 -0.01 1 150 4185 -0.01 1 150 4198 -0.01 1 150 4210 -0.01 1 150 4225 -0.01 1 150 4237 -0.01 1 150 4250 -0.01 1 150 4262 -0.01 1 150 4276 -0.01 1 150 4289 -0.01 1 150 4301 -0.01 1 150 4316 -0.01 1 150 4328 -0.01 1 150 4341 -0.01 1 150 4355 -0.01 1 150 4367 -0.01 1 150 4380 -0.01 1 150 4393 -0.01 1 150 4407 -0.01 1 150 4419 -0.01 1 150 4432 -0.01 1 150 4446 -0.01 1 150 4458 -0.01 1 150 4471 -0.01 1 150 4485 -0.01 1 150 4498 -0.01 1 150 4510 -0.01 1 150 4524 -0.01 1 150 4537 -0.01 1 150 4549 -0.01 1 150 4562 -0.01 1 150 4576 -0.01 1 150 4589 -0.01 1 150 4601 -0.01 1 150 4615 -0.01 1 150 4628 -0.01 1 150 4640 -0.01 1 150 4654 -0.01 1 150 4667 -0.01 1 150 4679 -0.01 1 150 4694 -0.01 1 150 4706 -0.01 1 150 4719 -0.01 1 150 4731 -0.01 1 150 4745 -0.01 1 150 4758 -0.01 1 150 4770 -0.01 1 200 4999 -0.02 1 200 5012 -0.02 1 200 5025 -0.02 1 200 5039 -0.02 1 200 5051 -0.02 1 200 5064 -0.02 1 200 5078 -0.02 1 200 5090 -0.02 1 200 5104 -0.02 1 200 5116 -0.02 1 200 5130 -0.02 1 200 5143 -0.02 1 200 5155 -0.02 1 200 5169 -0.02 1 200 5181 -0.02 1 200 5194 -0.02 1 200 5208 -0.02 1 200 5220 -0.02 1 200 5234 -0.03 1 200 5246 -0.03 1 200 5260 -0.03 1 200 5273 -0.03 1 200 5285 -0.03 1 200 5299 -0.03 1 200 5311 -0.03 1 200 5325 -0.03 1 200 5338 -0.03 1 200 5351 -0.03 1 200 5364 -0.03 1 200 5377 -0.03 1 200 5390 -0.03 1 200 5403 -0.03 1 200 5415 -0.03 1 200 5429 -0.03 1 200 5442 -0.03 1 200 5455 -0.03 1 200 5468 -0.03 1 200 5481 -0.03 1 200 5494 -0.03 1 200 5507 -0.03 1 200 5520 -0.03 1 200 5533 -0.03 1 200 5547 -0.03 1 200 5559 -0.03 1 200 5572 -0.03 1 200 5585 -0.03 1 200 5598 -0.03 1 200 5611 -0.03 1 200 5624 -0.03 1 200 5638 -0.03 1 250 5918 -0.03 1 250 5933 -0.03 1 250 5946 -0.03 1 250 5958 -0.03 1 250 5971 -0.03 1 250 5985 -0.03 1 250 5997 -0.03 1 250 6010 -0.03 1 250 6024 -0.03 1 250 6037 -0.03 1 250 6049 -0.03 1 250 6063 -0.03 1 250 6076 -0.03 1 250 6088 -0.03 1 250 6103 -0.03 1 250 6115 -0.03 1 250 6128 -0.03 1 250 6141 -0.03 1 250 6154 -0.03 1 250 6167 -0.03 1 250 6179 -0.03 1 250 6193 -0.03 1 250 6206 -0.03 1 250 6218 -0.03 1 250 6233 -0.03 1 250 6245 -0.03 1 250 6258 -0.03 1 250 6272 -0.03 1 250 6284 -0.03 1 250 6297 -0.03 1 250 6309 -0.03 1 250 6324 -0.03 1 250 6336 -0.03 1 250 6349 -0.03 1 250 6363 -0.03 1 250 6375 -0.03 1 250 6388 -0.03 1 250 6402 -0.03 1 250 6415 -0.03 1 250 6427 -0.03 1 250 6440 -0.03 1 250 6454 -0.03 1 250 6466 -0.03 1 250 6479 -0.03 1 250 6493 -0.03 1 250 6505 -0.03 1 250 6518 -0.03 1 250 6532 -0.03 1 250 6545 -0.03 1 250 6557 -0.03 1 300 6892 -0.03 1 300 6906 -0.03 1 300 6920 -0.03 1 300 6933 -0.03 1 300 6945 -0.03 1 300 6959 -0.03 1 300 6972 -0.03 1 300 6984 -0.03 1 300 6998 -0.03 1 300 7011 -0.03 1 300 7024 -0.03 1 300 7036 -0.03 1 300 7050 -0.03 1 300 7063 -0.03 1 300 7075 -0.03 1 300 7089 -0.03 1 300 7102 -0.03 1 300 7115 -0.03 1 300 7128 -0.03 1 300 7141 -0.03 1 300 7154 -0.03 1 300 7166 -0.03 1 300 7180 -0.03 1 300 7193 -0.03 1 300 7205 -0.03 1 300 7219 -0.03 1 300 7232 -0.03 1 300 7245 -0.03 1 300 7258 -0.03 1 300 7271 -0.03 1 300 7284 -0.03 1 300 7297 -0.03 1 300 7311 -0.03 1 300 7323 -0.03 1 300 7336 -0.03 1 300 7350 -0.03 1 300 7362 -0.03 1 300 7375 -0.03 1 300 7388 -0.03 1 300 7401 -0.03 1 300 7414 -0.03 1 300 7427 -0.03 1 300 7441 -0.03 1 300 7453 -0.03 1 300 7467 -0.03 1 300 7480 -0.04 1 300 7492 -0.04 1 300 7505 -0.03 1 300 7518 -0.03 1 300 7532 -0.03 1 350 7919 -0.03 1 350 7934 -0.03 1 350 7947 -0.03 1 350 7960 -0.03 1 350 7973 -0.03 1 350 7986 -0.03 1 350 8000 -0.03 1 350 8012 -0.03 1 350 8026 -0.03 1 350 8039 -0.03 1 350 8051 -0.04 1 350 8065 -0.04 1 350 8077 -0.04 1 350 8091 -0.03 1 350 8103 -0.03 1 350 8117 -0.04 1 350 8130 -0.04 1 350 8142 -0.04 1 350 8156 -0.04 1 350 8169 -0.03 1 350 8181 -0.04 1 350 8195 -0.04 1 350 8207 -0.04 1 350 8221 -0.04 1 350 8233 -0.04 1 350 8247 -0.04 1 350 8260 -0.04 1 350 8272 -0.04 1 350 8286 -0.04 1 350 8299 -0.04 1 350 8311 -0.04 1 350 8325 -0.04 1 350 8337 -0.04 1 350 8351 -0.04 1 350 8364 -0.04 1 350 8377 -0.04 1 350 8390 -0.04 1 350 8402 -0.04 1 350 8416 -0.04 1 350 8429 -0.04 1 350 8441 -0.04 1 350 8455 -0.04 1 350 8468 -0.04 1 350 8481 -0.04 1 350 8494 -0.04 1 350 8507 -0.04 1 350 8520 -0.04 1 350 8532 -0.04 1 350 8546 -0.04 1 350 8559 -0.04 1 400 9011 -0.05 1 400 9023 -0.05 1 400 9036 -0.05 1 400 9050 -0.05 1 400 9063 -0.05 1 400 9075 -0.05 1 400 9089 -0.05 1 400 9102 -0.05 1 400 9114 -0.05 1 400 9127 -0.05 1 400 9141 -0.05 1 400 9153 -0.05 1 400 9166 -0.05 1 400 9180 -0.05 1 400 9193 -0.05 1 400 9205 -0.05 1 400 9219 -0.05 1 400 9232 -0.05 1 400 9244 -0.05 1 400 9257 -0.05 1 400 9271 -0.05 1 400 9283 -0.05 1 400 9297 -0.05 1 400 9310 -0.05 1 400 9323 -0.05 1 400 9335 -0.05 1 400 9349 -0.05 1 400 9362 -0.05 1 400 9374 -0.05 1 400 9388 -0.05 1 400 9401 -0.05 1 400 9413 -0.05 1 400 9427 -0.05 1 400 9440 -0.05 1 400 9453 -0.05 1 400 9465 -0.05 1 400 9479 -0.05 1 400 9492 -0.05 1 400 9504 -0.05 1 400 9518 -0.05 1 400 9531 -0.05 1 400 9543 -0.05 1 400 9558 -0.05 1 400 9570 -0.05 1 400 9583 -0.05 1 400 9595 -0.05 1 400 9609 -0.05 1 400 9622 -0.05 1 400 9634 -0.05 1 450 10125 -0.06 1 450 10138 -0.06 1 450 10151 -0.06 1 450 10164 -0.06 1 450 10177 -0.06 1 450 10190 -0.06 1 450 10203 -0.06 1 450 10217 -0.06 1 450 10229 -0.06 1 450 10243 -0.06 1 450 10256 -0.06 1 450 10269 -0.06 1 450 10281 -0.06 1 450 10295 -0.06 1 450 10308 -0.06 1 450 10320 -0.06 1 450 10334 -0.06 1 450 10347 -0.06 1 450 10360 -0.06 1 450 10373 -0.06 1 450 10386 -0.06 1 450 10399 -0.06 1 450 10413 -0.06 1 450 10426 -0.06 1 450 10438 -0.06 1 450 10451 -0.06 1 450 10464 -0.06 1 450 10478 -0.06 1 450 10490 -0.06 1 450 10504 -0.06 1 450 10517 -0.06 1 450 10529 -0.06 1 450 10543 -0.06 1 450 10556 -0.06 1 450 10569 -0.06 1 450 10582 -0.06 1 450 10596 -0.06 1 450 10608 -0.06 1 450 10621 -0.06 1 450 10634 -0.06 1 450 10647 -0.06 1 450 10660 -0.06 1 450 10674 -0.06 1 450 10687 -0.06 1 450 10699 -0.06 1 450 10713 -0.07 1 450 10726 -0.07 1 450 10739 -0.07 1 450 10752 -0.07 1 450 10765 -0.07 1 500 11317 -0.07 1 500 11330 -0.07 1 500 11342 -0.07 1 500 11356 -0.07 1 500 11369 -0.07 1 500 11381 -0.07 1 500 11396 -0.07 1 500 11408 -0.07 1 500 11421 -0.07 1 500 11435 -0.07 1 500 11448 -0.07 1 500 11460 -0.07 1 500 11473 -0.07 1 500 11487 -0.07 1 500 11499 -0.07 1 500 11512 -0.07 1 500 11526 -0.07 1 500 11539 -0.07 1 500 11551 -0.07 1 500 11565 -0.07 1 500 11578 -0.07 1 500 11591 -0.07 1 500 11604 -0.07 1 500 11617 -0.07 1 500 11630 -0.07 1 500 11642 -0.07 1 500 11657 -0.07 1 500 11669 -0.07 1 500 11682 -0.07 1 500 11696 -0.07 1 500 11708 -0.07 1 500 11721 -0.07 1 500 11735 -0.07 1 500 11748 -0.07 1 500 11760 -0.07 1 500 11774 -0.07 1 500 11787 -0.07 1 500 11800 -0.07 1 500 11812 -0.07 1 500 11826 -0.07 1 500 11839 -0.07 1 500 11851 -0.07 1 500 11866 -0.07 1 500 11878 -0.07 1 500 11891 -0.07 1 500 11905 -0.07 1 500 11918 -0.07 1 500 11930 -0.07 1 500 11943 -0.07 1 550 12546 -0.07 1 550 12558 -0.07 1 550 12571 -0.07 1 550 12584 -0.07 1 550 12598 -0.07 1 550 12610 -0.07 1 550 12623 -0.07 1 550 12637 -0.07 1 550 12650 -0.07 1 550 12663 -0.07 1 550 12676 -0.07 1 550 12689 -0.07 1 550 12701 -0.07 1 550 12716 -0.07 1 550 12728 -0.07 1 550 12741 -0.07 1 550 12754 -0.07 1 550 12767 -0.07 1 550 12780 -0.08 1 550 12793 -0.08 1 550 12807 -0.08 1 550 12819 -0.08 1 550 12833 -0.08 1 550 12846 -0.08 1 550 12859 -0.08 1 550 12871 -0.08 1 550 12884 -0.08 1 550 12898 -0.08 1 550 12910 -0.08 1 550 12924 -0.08 1 550 12937 -0.08 1 550 12950 -0.08 1 550 12963 -0.08 1 550 12977 -0.08 1 550 12989 -0.08 1 550 13002 -0.08 1 550 13016 -0.08 1 550 13028 -0.08 1 550 13041 -0.08 1 550 13054 -0.08 1 550 13068 -0.08 1 550 13080 -0.08 1 550 13093 -0.08 1 550 13107 -0.08 1 550 13119 -0.08 1 550 13133 -0.08 1 550 13146 -0.08 1 550 13159 -0.08 1 550 13172 -0.08 1 Stopping...
Frank, This works great, up until there is enough loop delay to allow the MPU6050 to completely fill the 1024 byte FIFO. At this point, the function can't properly drain down to 1 packet, because there will always be 16 bytes remaining that can't/won't be extracted (not quite sure why, but....).
Almost. I was thinking that also at first. Rule1 the last packet when complete will always be a good packet this is always true even during an overflow event. Rule2 The second to the last packet will be valid even during the writing of the last packet.
Sequence Empty the FIFO buffer down to 1 packet even if it is overflowed. loop 1 byte at a time until we are down to 1 packet in size. *Check to see if anything eale was written to the buffer should only be 1 packet left.
- No we have a complete packet get it we are done.
- Yes we caught the mpu while filling the packet empty down to 1 packet. loop 1 byte at a time until we are down to 1 packet in size. *Check to see if we have more
- No we have a complete packet get it.
- Yes we must have emptied the FIFO buffer just before the new packet was written and now we caught the packet as it was finishing I can't see us missing it now so loop 1 byte at a time until we are down to 1 packet in size. *Again empty to 1 packet and we are good finally. Get the remaining good packet. FIFO buffer is empty unless a new packet started and we don't care
So knowing that the last packet is good if it has been written to completely we just need to test for no change between reads if none occurs we have a good packet
Starting at about 300 mSec loop delay, the code loses the race with the MPU6050, and the FIFO overflows. Now the drain function drains down to less than 28, but there are still 16 bytes remaining, and the mpu.ReadBytes() function starts failing. From then on, the function always fails to produce good packets.
I believe the solution is to check for 0 < fifoC < length, and if so, remove just fifoC bytes from the buffer, leaving exactly zero remaining.
Worst case scenario X=bad bytes G=Good N=new FIFO Buffer XXXXXXXXXXXXXXXXGGGGGGG~~~All Good~~~~GGGGGGGGGGGGGGGGGGGGGGGGGGGG| end First 16 bytes are bad but always the last 28 bytes are good no matter what so empty down to 28 bytes and check While emptying996 bytes we are left with 28 but we were unlucky (worst case)and the mpu starts Writing the next packet <<<<< GGGGGGGGGGGGGGGGGGGGGGGGGGGGNNNNNNNNN We can't tell if that was enough when we read the buffer so we must take the time to remove down to 28 but the packet wasn't complete so more is added while we were trimming and the once good packet becomes corrupted as we didn't know where the end was. XXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNN Now the new packet is complete and good so one last time we must remove to 28 NNNNNNNNNNNNNNNNNNNNNNNNNNN and good we have 10 ms before we have trouble
This is the plan with my latest sequence. Homer
Homer,
OK, I think I get the idea, but your latest version was shrinking the FIFO contents by 1 packet each time through the loop - not 1 byte! That explains why you had 'fifoC--' instead of 'fifoC -= length', where 'length' was the packetSize passed in via the function signature.
I'm not sure your algorithm is going to work, as it depends on getFIFOCount() always reporting the exact number of bytes currently in the FIFO, but we know it doesn't always get the correct value. If the getFIFOCount() call occurs while the MPU6050 is loading a new packet, then the number returned by getFIFOCount() won't be correct - it will change in just a few microseconds.
In fact, because our proposed polling operation isn't synchronized with the MPU6050's FIFO load cycles, we will never know where we are with respect to the next load event. I think we might need a new 'getFIFOCount_Polling()' function that calls getFIFOCount() repeatedly until two subsequent counts match, and then returns that number. We still won't know when the next FIFO load event will occur, but we'll know that we are on one side or the other of that event, and can adjust appropriately.
The following Excel plot was produced by generating a '1' every 100 rows (i.e. 0.1 ms/row) in Column A, and generating a '1.5' randomly (with 1% probability) in Column B. Column C puts a '2' in any rows in which both the values in A & B are non-zero. As the plot shows, there were no coincidences in 2800 trials, so it probably won't happen very often (but it will happen, of course)
[image: 191031_FIFOLoadsVsCounts.jpg]
Assuming we use a 'getFIFOCount_Polling()' function that calls getFIFOCount() repeatedly every 200 uSec until two adjacent counts agrees, then I think there are only two cases to consider:
- Both calls to getFIFOCount() occur on one side of the load operation. In this case, the value returned will be exactly the same as the regular function, at the cost of an additional 200 uSec. This doesn't mean the count can't change again almost immediately, but for the purposes of pulling bytes out of the FIFO, at least the number will be accurate for that cycle.
- One call falls on one side of the load, and the other falls on the other (or even during) the load. In this case, it may take 3 (or even 4 if we are really unlucky) calls to getFIFOCount() to achieve two subsequent matching numbers, but it will happen.
During the FIFO drain operation, the getFIFOCount_Polling() operation will always return the correct FIFO content length, and since the drain operation will take much much less than 10 mSec, it is guaranteed that there will never be more than one occurrence every 10 mSec or so where the getFIFOCount_Polling() function call will take more than 200 uSec to return a valid count value. On average this means the cost of the new function will be slightly more than 200 uSec over the current total valid packet retrieval time.
I think if we use this new getFIFOCount_Polling() function along with your FIFO drain-by-1-byte-at-a-time algorithm, we can pretty much guarantee error-free operation.
Thoughts?
Frank
On Wed, Oct 30, 2019 at 11:41 PM Homer Creutz [email protected] wrote:
Frank, This works great, up until there is enough loop delay to allow the MPU6050 to completely fill the 1024 byte FIFO. At this point, the function can't properly drain down to 1 packet, because there will always be 16 bytes remaining that can't/won't be extracted (not quite sure why, but....).
Almost. I was thinking that also at first. Rule1 the last packet when complete will always be a good packet this is always true even during an overflow event. Rule2 The second to the last packet will be valid even during the writing of the last packet.
Sequence Empty the FIFO buffer down to 1 packet even if it is overflowed. loop 1 byte at a time until we are down to 1 packet in size. *Check to see if anything eale was written to the buffer should only be 1 packet left.
- No we have a complete packet get it we are done.
- Yes we caught the mpu while filling the packet empty down to 1 packet. loop 1 byte at a time until we are down to 1 packet in size. *Check to see if we have more
- No we have a complete packet get it.
- Yes we must have emptied the FIFO buffer just before the new packet was written and now we caught the packet as it was finishing I can't see us missing it now so loop 1 byte at a time until we are down to 1 packet in size. *Again empty to 1 packet and we are good finally. Get the remaining good packet. FIFO buffer is empty unless a new packet started and we don't care
So knowing that the last packet is good if it has been written to completely we just need to test for no change between reads if none occurs we have a good packet
Starting at about 300 mSec loop delay, the code loses the race with the MPU6050, and the FIFO overflows. Now the drain function drains down to less than 28, but there are still 16 bytes remaining, and the mpu.ReadBytes() function starts failing. From then on, the function always fails to produce good packets.
I believe the solution is to check for 0 < fifoC < length, and if so, remove just fifoC bytes from the buffer, leaving exactly zero remaining.
Worst case scenario X=bad bytes G=Good N=new FIFO Buffer XXXXXXXXXXXXXXXXGGGGGGG~~~All Good~~~~GGGGGGGGGGGGGGGGGGGGGGGGGGGG| end First 16 bytes are bad but always the last 28 bytes are good no matter what so empty down to 28 bytes and check While emptying996 bytes we are left with 28 but we were unlucky (worst case)and the mpu starts Writing the next packet <<<<< GGGGGGGGGGGGGGGGGGGGGGGGGGGGNNNNNNNNN We can't tell if that was enough when we read the buffer so we must take the time to remove down to 28 but the packet wasn't complete so more is added while we were trimming and the once good packet becomes corrupted as we didn't know where the end was. XXXXXXXXXXXXXXXXXXXXXXNNNNNNNNNNNNNNNNNNNNNNNNNNN Now the new packet is complete and good so one last time we must remove to 28 NNNNNNNNNNNNNNNNNNNNNNNNNNN and good we have 10 ms before we have trouble
This is the plan with my latest sequence. 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=AA6T32452E5RKYP3FVVJO33QRJHWVA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECWO5DA#issuecomment-548204172, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T322AF52QZATWWY3ACG3QRJHWVANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank, yep, my bad :) Corrected: note I also made a modification to the 3rd loop to check size each time instead of removing bytes. I figure if we hare here we can be extra careful.
/** Get latest byte from FIFO buffer no matter how much time has passed.
* === GetCurrentFIFOPacket ===
* ================================================================
* Returns 1) when data was received
* 0) when no valid data is available
* ================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
uint16_t fifoC;
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) { // Shrink down to 1 packet
mpu.getFIFOBytes(data, 1);// 1 byte
fifoC--;
}
if ((fifoC = mpu.getFIFOCount()) > length) {
while (fifoC > length) { // We got more data while we were shrinking
mpu.getFIFOBytes(data, 1); //1 byte
fifoC--;
}
while (fifoC = mpu.getFIFOCount()) > length) {// we need to be sure, but this shouldn't happen... Shrink some more and lets check each time
mpu.getFIFOBytes(data, 1); //1 Byte
fifoC--;
}
}
}
while (fifoC && (fifoC < length)) fifoC = mpu.getFIFOCount(); //Finish loading the packet!
//we have only 1 packet!
if (fifoC == length) {
mpu.getFIFOBytes(data, length); //1 packet
return 1;
}
return 0;
}
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(115200);
while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready
Serial.println(F("\nSend any character to begin DMP programming and demo: "));
while (Serial.available() && Serial.read()); // empty buffer
while (!Serial.available()); // wait for data
while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(51);
mpu.setYGyroOffset(8);
mpu.setZGyroOffset(21);
mpu.setXAccelOffset(1150);
mpu.setYAccelOffset(-50);
mpu.setZAccelOffset(1060);
if (devStatus == 0) {
mpu.CalibrateAccel(6);
mpu.CalibrateGyro(6);
Serial.println();
mpu.PrintActiveOffsets();
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
dmpReady = true;
packetSize = mpu.dmpGetFIFOPacketSize();
} else {
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
// configure LED for output
pinMode(LED_PIN, OUTPUT);
uint32_t startMsec, MsecSinceLastYawCheck;
startMsec = millis();
MsecSinceLastYawCheck = 0;
for (int loopDelayMsec = 0; loopDelayMsec < 500; loopDelayMsec = loopDelayMsec + 1) {
delay(loopDelayMsec);
for (size_t i = 0; i < 10; i++) {
while (! GetCurrentFIFOPacket(fifoBuffer, packetSize));
Serial.print(loopDelayMsec);
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);
Serial.println();
}
}
while (1);
}
So I switched to the Simple_MPU6050 project and came up with this code. I got cut and past happy and just missed the most important part the 1 byte at a time this is exactly what the multi-byte i2cdev function does so the time difference is minimal
Simplified Version of readBytes in i2cdev:
int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) {
int8_t count = 0;
uint32_t t1 = millis();
for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) { //loops to get multiple bytes
Wire.beginTransmission(devAddr);
Wire.write(regAddr);
Wire.endTransmission();
Wire.beginTransmission(devAddr);
Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
data[count] = Wire.read(); // Gets 1 Byte
}
}
return count;
}
so there is bo time lost by getting 1 byte at time.
Homer
Homer,
I haven't had a chance to check out your latest creation, but I plan to over the weekend. In the meantime, I tried to look at what is actually happening with the MPU6050 in terms of getting accurate and reliable FIFO counts. So, I created a function called 'GetPollingFIFOCount()' as follows:
int GetPollingFIFOCount() {
int ctr = 0; int lastFIFOCount = mpu.getFIFOCount(); glFIFOCount = mpu.getFIFOCount(); while (glFIFOCount != lastFIFOCount) {
ctr++;
mySerial.printf("%lu\t%d\t%d\t%d\t%d\n", millis(),glLoopDelayMsec, glFIFOCount, lastFIFOCount, ctr);
lastFIFOCount = glFIFOCount;
}
return ctr;
}
and ran it over a series of loop delays from 0 to 600 mSec in 50 mSec steps. I plotted the points at which the GetPollingFIFOCount() function returned a non-zero count to see if there was anything interesting, as shown in the Excel plots below:
[image: 191101 NonZeroFIFOCountDelta2.jpg] [image: 191101 NonZeroFIFOCountDelta1.jpg]
In about 80 seconds I collected almost 200 occurrences of a non-zero FIFO count delta. Most (119 of 185) of these were 28-byte differences as expected, but many (66 of 185) weren't. As the second plot above shows, the non-modal deltas, indicate (I think) that the first and second 'getFIFOCount()' calls occurred while the MPU6050 was still loading the FIFO. In all cases, the count became stable after one additional call to getFIFOCount(), for a total of 3 calls.
In the plots above, the width of the steps in the orange (loop delay) curve indicate how many non-zero deltas occurred during that loop delay period. As can be seen, there were zero such occurrences for loop delays above 150 mSec, but I'm not sure why; there may be something else going on with the test program that prevented those delays from causing non-zero delta occurrences.
The bottom line, however, is that non-zero deltas do occur with some frequency, so anything we do has to take that into account.
Regards,
Frank
On Fri, Nov 1, 2019 at 10:55 AM Homer Creutz [email protected] wrote:
Frank, yep, my bad :) Corrected: note I also made a modification to the 3rd loop to check size each time instead of removing bytes. I figure if we hare here we can be extra careful.
/** Get latest byte from FIFO buffer no matter how much time has passed.
- === GetCurrentFIFOPacket ===
- ================================================================
- Returns 1) when data was received
0) when no valid data is available- ================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint16_t fifoC; if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) { // Shrink down to 1 packet mpu.getFIFOBytes(data, 1);// 1 byte fifoC--; } if ((fifoC = mpu.getFIFOCount()) > length) { while (fifoC > length) { // We got more data while we were shrinking mpu.getFIFOBytes(data, 1); //1 byte fifoC--; } while (fifoC = mpu.getFIFOCount()) > length) {// we need to be sure, but this shouldn't happen... Shrink some more and lets check each time mpu.getFIFOBytes(data, 1); //1 Byte fifoC--; } } } while (fifoC && (fifoC < length)) fifoC = mpu.getFIFOCount(); //Finish loading the packet! //we have only 1 packet! if (fifoC == length) { mpu.getFIFOBytes(data, length); //1 packet return 1; } return 0; }
// ================================================================ // === INITIAL SETUP === // ================================================================
void setup() { // join I2C bus (I2Cdev library doesn't do this automatically) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif Serial.begin(115200); while (!Serial); // wait for Leonardo enumeration, others continue immediately
// initialize device Serial.println(F("Initializing I2C devices...")); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT);
// verify connection Serial.println(F("Testing device connections...")); Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// wait for ready Serial.println(F("\nSend any character to begin DMP programming and demo: ")); while (Serial.available() && Serial.read()); // empty buffer while (!Serial.available()); // wait for data while (Serial.available() && Serial.read()); // empty buffer again
// load and configure the DMP Serial.println(F("Initializing DMP...")); devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity mpu.setXGyroOffset(51); mpu.setYGyroOffset(8); mpu.setZGyroOffset(21); mpu.setXAccelOffset(1150); mpu.setYAccelOffset(-50); mpu.setZAccelOffset(1060); if (devStatus == 0) { mpu.CalibrateAccel(6); mpu.CalibrateGyro(6); Serial.println(); mpu.PrintActiveOffsets(); Serial.println(F("Enabling DMP...")); mpu.setDMPEnabled(true);
dmpReady = true; packetSize = mpu.dmpGetFIFOPacketSize();} else { Serial.print(F("DMP Initialization failed (code ")); Serial.print(devStatus); Serial.println(F(")")); }
// configure LED for output pinMode(LED_PIN, OUTPUT); uint32_t startMsec, MsecSinceLastYawCheck; startMsec = millis(); MsecSinceLastYawCheck = 0;
for (int loopDelayMsec = 0; loopDelayMsec < 500; loopDelayMsec = loopDelayMsec + 1) { delay(loopDelayMsec); for (size_t i = 0; i < 10; i++) { while (! GetCurrentFIFOPacket(fifoBuffer, packetSize)); Serial.print(loopDelayMsec); 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); Serial.println();
}} while (1); }
So I switched to the Simple_MPU6050 project and came up with this code. I got cut and past happy and just missed the most important part the 1 byte at a time this is exactly what the multi-byte i2cdev function does so the time difference is minimal
Simplified Version of readBytes in i2cdev: int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) { int8_t count = 0; uint32_t t1 = millis(); for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) { //loops to get multiple bytes Wire.beginTransmission(devAddr); Wire.write(regAddr); Wire.endTransmission(); Wire.beginTransmission(devAddr); Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { data[count] = Wire.read(); // Gets 1 Byte } } return count; }
so there is bo time lost by getting 1 byte at time.
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=AA6T3265LFWD7Z5I2NR4PQDQRQ7M5A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEC3EZNQ#issuecomment-548818102, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T324TTNKUQEILLSZ37S3QRQ7M5ANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank, Yes I see that "In all cases, the count became stable after one additional call to getFIFOCount(), for a total of 3 calls."
This is where the 3 step test comes from. Steps 1 and 2 Trim in chunks 1 byte at a time the third step has a looping effect to trim check trim until only 28 bytes remain. I will simplify the code:
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
uint16_t fifoC;
Step 1
if (Get FIFOCount > 28) { // Get the fifo count and store it
while (FIFOCount > 28) { // Shrink down to 1 packet
get 1 FIFOBytes
FIFOCount = FIFOCount -1;
}
We should be at 28 but there is a chance that more data was added during our test so we are not quite at the last packet
Step 2
if (Get FIFOCount > 28) { // Get the fifo count and store it
while (FIFOCount > 28) { // Shrink down to 1 packet
get 1 FIFOBytes
FIFOCount = FIFOCount -1;
}
Now we should be at 1 packet but lets test1 more time and this time if there is anything more lets test each time we get a byte as we need to be super careful. This is our last chance to catch the last packet.
Step 3
while (Get FIFOCount > 28) { // Get the latest count each loop instead of just once
get 1 FIFOBytes
FIFOCount = FIFOCount -1;
}
}
}
now let's say we are looping fast and we don't quite have a single packet as the MPU just started to create it so we loop.
We already have the FIFO Count from the first try so let's use it if it is exactly 28 skip this next line it cant be greater as the above code has just limited it to 28. But we can be less but if we are at zero then we need to quickly move on and exit. now if we are not zero but less than 28 we must be within 1 to 2 more readings till we get there so let's finish the packet now instead of waiting and looping around again. (blocking delay to finish loading the packet only)
while (FIFOCount && (FIFOCount < length)) {Get FIFOCount} //Finish loading the packet!
//we have only 1 packet!
if (FIFOCount == length) {
mpu.getFIFOBytes(data, length); //1 packet
return 1; // Success
}
return 0; // No Data yet. There is no fail mode with this code always success or no data.
}
That's my simplified logic with lots of notes.
Homer
Homer,
I ran your code for 10 complete cycles of the entire range of loop delays from 0 to 500 mSec, with the sensor held stationary. As you can see, the retrieved yaw value appears to be valid for the entire time period (about 40 minutes). I think you may have a winner! ;-).
[image: 191102_GetCurrentFIFOPacket2.jpg]
Looking through the code, I see there are lots of while loops, each one a potential infinitely blocking loop; we'll need to make sure we don't fall victim to the same problem the default Arduino Wire library has, where edge conditions can cause infinite hangups. In the case of the more robust Wire libraries like SBWire, the fix was to add a fallback counter 'max_loops' to forcibly terminate the read() and write() while loops if necessary. I think we should consider doing something similar with this code.
Regards,
Frank
On Fri, Nov 1, 2019 at 11:51 PM Homer Creutz [email protected] wrote:
Frank, Yes I see that "In all cases, the count became stable after one additional call to getFIFOCount(), for a total of 3 calls."
This is where the 3 step test comes from. Steps 1 and 2 Trim in chunks 1 byte at a time the third step has a looping effect to trim check trim until only 28 bytes remain. I will simplify the code:
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof uint16_t fifoC; Step 1 if (Get FIFOCount > 28) { // Get the fifo count and store it while (FIFOCount > 28) { // Shrink down to 1 packet get 1 FIFOBytes FIFOCount = FIFOCount -1; }
We should be at 28 but there is a chance that more data was added during our test so we are not quite at the last packet Step 2 if (Get FIFOCount > 28) { // Get the fifo count and store it while (FIFOCount > 28) { // Shrink down to 1 packet get 1 FIFOBytes FIFOCount = FIFOCount -1; } Now we should be at 1 packet but lets test1 more time and this time if there is anything more lets test each time we get a byte as we need to be super careful. This is our last chance to catch the last packet. Step 3 while (Get FIFOCount > 28) { // Get the latest count each loop instead of just once get 1 FIFOBytes FIFOCount = FIFOCount -1; } } } now let's say we are looping fast and we don't quite have a single packet as the MPU just started to create it so we loop. We already have the FIFO Count from the first try so let's use it if it is exactly 28 skip this next line it cant be greater as the above code has just limited it to 28. But we can be less but if we are at zero then we need to quickly move on and exit. now if we are not zero but less than 28 we must be within 1 to 2 more readings till we get there so let's finish the packet now instead of waiting and looping around again. (blocking delay to finish loading the packet only) while (FIFOCount && (FIFOCount < length)) {Get FIFOCount} //Finish loading the packet! //we have only 1 packet! if (FIFOCount == length) { mpu.getFIFOBytes(data, length); //1 packet return 1; // Success } return 0; // No Data yet. There is no fail mode with this code always success or no data. }
That's my simplified logic with lots of notes.
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=AA6T325ORJICDHM4Z64PSRDQRT2NBA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEC4TBOQ#issuecomment-549007546, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T326CHZMGKPZDGOFTA4LQRT2NBANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank,
Wow, what a challenge! As per your suggestion here is some code adding timers and limits to eliminate all blocking instances
/** Get latest byte from FIFO buffer no matter how much time has passed.
* === GetCurrentFIFOPacket ===
* ================================================================
* Returns 1) when data was received
* 0) when no valid data is available
*
* Revision: -Added Timers and loop limits for all possible blocking code
* ================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
uint16_t fifoC;
uint63_t BreakTimer;
if ((fifoC = mpu.getFIFOCount()) > length) {
for(; fifoC > length;fifoC-- { // Shrink down to 1 packet
mpu.getFIFOBytes(data, 1);// 1 byte
}
if ((fifoC = mpu.getFIFOCount()) > length) {
for(; fifoC > length;fifoC-- { // Shrink down to 1 packet
mpu.getFIFOBytes(data, 1); //1 byte
}
// we only had 1 packet so lets never try to get more than 1 packet worth of data for the final shrinking
for(uint16_t C = packetSize; C && (fifoC = mpu.getFIFOCount() > length); C-- { // Shrink down to 1 packet
mpu.getFIFOBytes(data, 1); //1 Byte
}
}
}
BreakTimer = micros();
while (fifoC && (fifoC < length)&&((micros() - BreakTimer) <= (1000))) fifoC= mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
if (fifoC == length) {
//we have only 1 packet!
mpu.getFIFOBytes(data, length); //1 packet
return 1;
}
return 0;
}
My Initial testing looks promising. your routine may shed some light if I made any mistakes. in general, it is simple! too simple right? Why didn't I think of this some years ago? lol
Homer
P.S. Frank, I submitted then corrected the above code as I missed some of my logic and I needed to set fifoC each time I test updated lines:
for(uint16_t C = packetSize; C && (fifoC = mpu.getFIFOCount() > length); C-- { // Shrink down to 1 packet
and
while (fifoC && (fifoC < length)&&((micros() - BreakTimer) <= (1000))) fifoC= mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
Make sure you are using the latest Homer
Homer,
Well, there may be a fly in the ointment; Using your code from yesterday (without the BreakTimer), I plotted the time required to execute GetCurrentFIFOPacket() for increasing loop delays. As you can see, the execution time for GetCurrentFIFOPacket() goes way up as the loop delay (and thus the initial FIFO count) goes up. I don't think this will be acceptable for applications like mine that use a loop delay interval on the order of 100-200 mSec. I think you might want to consider making the first call to GetFIFOBytes() the entire reported length - packetsize, or something like that. Otherwise the literally hundreds of calls to getFIFOBytes() uses up too much time.
[image: 191104_GetCurrentFIFOPacketExecMsec1.jpg]
I will try your new BreakTimer code as soon as I can get to it, but it may not be for a couple of days.
Regards,
Frank
On Sun, Nov 3, 2019 at 11:23 AM Homer Creutz [email protected] wrote:
P.S. Frank, I submitted then corrected the above code as I missed some of my logic and I needed to set fifoC each time I test updated lines:
for(uint16_t C = packetSize; C && (fifoC = mpu.getFIFOCount() > length); C-- { // Shrink down to 1 packetand while (fifoC && (fifoC < length)&&((micros() - BreakTimer) <= (1000))) fifoC= mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
Make sure you are using the latest 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=AA6T324HIHGOWSPHGO7BOI3QR3UG3A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEC5WZ2A#issuecomment-549154024, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T3257WBNG5RPHPOUQ353QR3UG3ANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Homer,
I'm working on some ideas to speed up the GetCurrentFIFOPacket routine, and I ran into a problem for which you may have some insight. I was trying to pull lots of bytes out of the FIFO all at once with mpu.getFIFOBytes(bitBucket, (fifoC - length)), where, 'bitBucket' is defined as
uint8_t bitBucket[1024];
and fifoC is the result from my getPollingFIFOCount() routine.
This all goes smoothly until I try to pull 252 bytes from the FIFO, at which point mpu.getFIFOBytes() hangs permanently. Do you know if there are any limitations on what I can do with this function?
TIA,
Frank
On Sun, Nov 3, 2019 at 12:32 PM Frank Paynter [email protected] wrote:
Homer,
Well, there may be a fly in the ointment; Using your code from yesterday (without the BreakTimer), I plotted the time required to execute GetCurrentFIFOPacket() for increasing loop delays. As you can see, the execution time for GetCurrentFIFOPacket() goes way up as the loop delay (and thus the initial FIFO count) goes up. I don't think this will be acceptable for applications like mine that use a loop delay interval on the order of 100-200 mSec. I think you might want to consider making the first call to GetFIFOBytes() the entire reported length - packetsize, or something like that. Otherwise the literally hundreds of calls to getFIFOBytes() uses up too much time.
[image: 191104_GetCurrentFIFOPacketExecMsec1.jpg]
I will try your new BreakTimer code as soon as I can get to it, but it may not be for a couple of days.
Regards,
Frank
On Sun, Nov 3, 2019 at 11:23 AM Homer Creutz [email protected] wrote:
P.S. Frank, I submitted then corrected the above code as I missed some of my logic and I needed to set fifoC each time I test updated lines:
for(uint16_t C = packetSize; C && (fifoC = mpu.getFIFOCount() > length); C-- { // Shrink down to 1 packetand while (fifoC && (fifoC < length)&&((micros() - BreakTimer) <= (1000))) fifoC= mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
Make sure you are using the latest 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=AA6T324HIHGOWSPHGO7BOI3QR3UG3A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEC5WZ2A#issuecomment-549154024, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T3257WBNG5RPHPOUQ353QR3UG3ANCNFSM4I6XC3RA .
-- 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)
Homer,
Never mind - I see now that the 'length' parameter for getFIFOBytes() is a uint8_t, thereby limiting it to 256. However, when I dig deeper, see that getFIFOBytes calls 'I2Cdev::readBytes(devAddr, MPU6050_RA_FIFO_R_W, length, data);', and this calls 'size_t readBytes( uint8_t *buffer, size_t length) { return readBytes((char *)buffer, length); }' and here I think length can be any length - not restricted to a uint8_t object. Do you know why getFIFOBytes was restricted to a uint8_t?
TIA,
Frank
On Sun, Nov 3, 2019 at 10:25 PM Frank Paynter [email protected] wrote:
Homer,
I'm working on some ideas to speed up the GetCurrentFIFOPacket routine, and I ran into a problem for which you may have some insight. I was trying to pull lots of bytes out of the FIFO all at once with mpu.getFIFOBytes(bitBucket, (fifoC - length)), where, 'bitBucket' is defined as
uint8_t bitBucket[1024];
and fifoC is the result from my getPollingFIFOCount() routine.
This all goes smoothly until I try to pull 252 bytes from the FIFO, at which point mpu.getFIFOBytes() hangs permanently. Do you know if there are any limitations on what I can do with this function?
TIA,
Frank
On Sun, Nov 3, 2019 at 12:32 PM Frank Paynter [email protected] wrote:
Homer,
Well, there may be a fly in the ointment; Using your code from yesterday (without the BreakTimer), I plotted the time required to execute GetCurrentFIFOPacket() for increasing loop delays. As you can see, the execution time for GetCurrentFIFOPacket() goes way up as the loop delay (and thus the initial FIFO count) goes up. I don't think this will be acceptable for applications like mine that use a loop delay interval on the order of 100-200 mSec. I think you might want to consider making the first call to GetFIFOBytes() the entire reported length - packetsize, or something like that. Otherwise the literally hundreds of calls to getFIFOBytes() uses up too much time.
[image: 191104_GetCurrentFIFOPacketExecMsec1.jpg]
I will try your new BreakTimer code as soon as I can get to it, but it may not be for a couple of days.
Regards,
Frank
On Sun, Nov 3, 2019 at 11:23 AM Homer Creutz [email protected] wrote:
P.S. Frank, I submitted then corrected the above code as I missed some of my logic and I needed to set fifoC each time I test updated lines:
for(uint16_t C = packetSize; C && (fifoC = mpu.getFIFOCount() > length); C-- { // Shrink down to 1 packetand while (fifoC && (fifoC < length)&&((micros() - BreakTimer) <= (1000))) fifoC= mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
Make sure you are using the latest 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=AA6T324HIHGOWSPHGO7BOI3QR3UG3A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEC5WZ2A#issuecomment-549154024, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T3257WBNG5RPHPOUQ353QR3UG3ANCNFSM4I6XC3RA .
-- 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)
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank
May have a fix for reading more bytes but I Believe the limit is still 32 bytes per I2c request instance.
I think there is a BUFFER_LENGTH limit to how many bytes you can receive per I3c Request.
Simplified Version created from readBytes in i2cdev This function works with Arduino Version > 100 only Added 16Bit Length.:
#ifndef BUFFER_LENGTH
// band-aid fix for platforms without Wire-defined BUFFER_LENGTH (removed from some official implementations)
#define BUFFER_LENGTH 32
int16_t I2Cdev::readMoreBytes(uint8_t devAddr, uint8_t regAddr, uint16_t length, uint8_t *data, uint16_t timeout) {
Serial.print("The i2c Buffer Size is:");
Serial.print(BUFFER_LENGTH );
uint16_t count = 0;
uint32_t t1 = millis();
for (uint16_t k = 0; k < length; k += min((uint16_t)length, BUFFER_LENGTH)) { //loops to get multiple bytes
Wire.beginTransmission(devAddr);
Wire.write(regAddr);
Wire.endTransmission();
Wire.beginTransmission(devAddr);
Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
data[count] = Wire.read(); // Gets 1 Byte
}
}
}
return count;
}
Try This one out
note: the i2c Buffer size is only 32 bytes and then we loop anyway Homer
Homer,
Thanks for the info. It appears that mpu.getFIFOBytes() currently works OK for 28-byte lengths, so no real need to hack i2cdev for 4 more bytes. However, if I2Cdev::readMoreBytes() can read any number of bytes (albeit with looping after buffer length), why does mpu.getFIFOBytes() use a uint8_t for the 'length' parameter? Also, when I tried changing 'length' from uint8_t to uint16_t (and making the required changes in the .h file), it *still *hung for lengths > 250 or so. Any idea why?
Frank
On Tue, Nov 5, 2019 at 2:50 AM Homer Creutz [email protected] wrote:
Frank
May have a fix for reading more bytes but I Believe the limit is still 32 bytes per I2c request instance.
I think there is a BUFFER_LENGTH limit to how many bytes you can receive per I3c Request.
Simplified Version created from readBytes in i2cdev This function works with Arduino Version > 100 only Added 16Bit Length.:
#ifndef BUFFER_LENGTH // band-aid fix for platforms without Wire-defined BUFFER_LENGTH (removed from some official implementations) #define BUFFER_LENGTH 32
int16_t I2Cdev::readMoreBytes(uint8_t devAddr, uint8_t regAddr, uint16_t length, uint8_t *data, uint16_t timeout) {
Serial.print("The i2c Buffer Size is:"); Serial.print(BUFFER_LENGTH );
uint16_t count = 0; uint32_t t1 = millis(); for (uint16_t k = 0; k < length; k += min((uint16_t)length, BUFFER_LENGTH)) { //loops to get multiple bytes Wire.beginTransmission(devAddr); Wire.write(regAddr); Wire.endTransmission(); Wire.beginTransmission(devAddr); Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { data[count] = Wire.read(); // Gets 1 Byte } } } return count; }
Try This one out
note: the i2c Buffer size is only 32 bytes and then we loop anyway 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=AA6T323RWGOY56DAAOEY3KLQSEQWBA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDB5CEA#issuecomment-549703952, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T326Z7LITWB22ZVWEX4LQSEQWBANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Frank, I Think this might Fit Jeff's Expertise better as he wrote the i2cdev Library.
So I would guess that there is no advantage to asking for more than 32 bytes per loop as this is the optimal buffer size. this saves 5 calls over the i2c bus per byte over my code. I'm sure there may be additional speed steps but the i2c bus is the bottleneck.
Let us see... Something like...
/** Get latest byte from FIFO buffer no matter how much time has passed.
* === GetCurrentFIFOPacket ===
* ================================================================
* Returns 1) when data was received
* 0) when no valid data is available
*
* Revision: -Added Timers and loop limits for all possible blocking code
* ================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
uint16_t fifoC;
uint63_t BreakTimer;
uint8_t Trash[BUFFER_LENGTH];
if ((fifoC = mpu.getFIFOCount()) > length) {
for (uint8_t k = 0; k < fifoC - length ; k += min((int)fifoC - length, BUFFER_LENGTH)){
mpu.getFIFOBytes(Trash, (uint8_t)min(fifoC - length - k, BUFFER_LENGTH));
}
// no more optimization needed as we will be less than 32 bytes at this point
if ((fifoC = mpu.getFIFOCount()) > length) {
mpu.getFIFOBytes(Trash, fifoC - length ); //1 byte
// we only had 1 packet so lets never try to get more than 1 packet worth of data for the final shrinking
// If we get here we are doing it 1 byte at a time to give the buffer time to load
for(uint16_t C = packetSize; C && (fifoC = mpu.getFIFOCount() > length); C-- { // Shrink down to 1 packet
mpu.getFIFOBytes(Trash, 1); //1 Byte
}
}
}
BreakTimer = micros();
while (fifoC && (fifoC < length)&&((micros() - BreakTimer) <= (1000))) fifoC= mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
if (fifoC == length) {
//we have only 1 packet!
mpu.getFIFOBytes(data, length); //1 packet
return 1;
}
return 0;
}
Quick edit probably with mistakes
Homer
Quickly stepping in to answer this: the 32-byte limitation comes from the underlying I2C hardware layer, specifically the Wire library in this case. When you call requestFrom(), that's the moment when the transaction occurs on the SDA/SCL lines; incoming data is stored in Wire's internal RX buffer, and it enforces a maximum length to avoid buffer overruns:
https://github.com/arduino/ArduinoCore-avr/blob/c8d6aef6d9331af1ec8dea6f78b4e43174cdb55d/libraries/Wire/src/Wire.cpp#L109-L112
I ran into this limitation very early on in MPU-6050 experiments, so I wrote the I2Cdev class to work around it as best as possible by chunking larger operations into pieces. The MPU-6050 itself would probably have no issue whatsoever doing a very long read or write operation, but you'd have to increase the buffer size to accommodate it. (Note, the samd core for example has a larger buffer size due to its own Wire implementation, and other platforms may use something bigger than 32 as well.)
Carry on with your in-depth troubleshooting... :)
Thanks Jeff!! I always enjoy hearing from the i2c Expert :)
When we get this 100% we will have a simple fast function to retrieve the most current packet from the FIFO buffer no matter how much time has passed. This will fix the FIFO overflow condition and only return valid data.
Homer PS. Hold off on my latest pull request I realized I had a bit of overkill with the way I did it this version is much simpler and faster. I have to thank Frank again for helping me realize this ultimate fix to the FIFO buffer overflow plague that hampers this MPU series.
Frank Latest Version working
/** Get latest byte from FIFO buffer no matter how much time has passed.
=== GetCurrentFIFOPacket ===
================================================================
Returns 1) when data was received
0) when no valid data is available
Revision: -Added Timers and loop limits for all possible blocking code
================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
int16_t fifoC;
uint32_t BreakTimer;
uint8_t Trash[BUFFER_LENGTH];
if ((fifoC = mpu.getFIFOCount()) > length) {
fifoC = fifoC - length; // Save the last packet
uint16_t RemoveBytes = min((int)fifoC, BUFFER_LENGTH);
while (fifoC) { // fifo count will reach zero so this is safe
RemoveBytes = min((int)fifoC, BUFFER_LENGTH);
mpu.getFIFOBytes(Trash, (uint8_t)RemoveBytes);
fifoC -= RemoveBytes;
}
// no more optimization needed as we will be less than 1 packet at this point
if ((fifoC = mpu.getFIFOCount()) > length) {
mpu.getFIFOBytes(Trash, fifoC - length ); // Have less than 1 packet
// we only had 1 packet so lets never try to get more than 1 packet worth of data for the final shrinking
// If we get here we are doing it 1 byte at a time to give the buffer time to load
for (uint16_t C = packetSize; C && ((fifoC = mpu.getFIFOCount()) > length); C--) { // Shrink down to 1 packet
mpu.getFIFOBytes(Trash, 1); //1 Byte
}
}
}
BreakTimer = micros();
while (fifoC && (fifoC < length) && ((micros() - BreakTimer) <= (1000))) fifoC = mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
if (fifoC == length) {
//we have only 1 packet!
mpu.getFIFOBytes(data, length); //1 packet
return 1;
}
return 0;
}
I hope we have a winner Homer
Homer, Jeff,
Jeff, thanks for jumping to address this issue. The explanation you gave is certainly helpful, but doesn't explain why mpu.getFIFOBytes(uint8_t* data, uint8_t length) uses a uint8_t object for the length parameter. I would have thought that you could give mpu.getFIFOBytes() any length up to the size of the FIFO itself (which I understand to be either 1024 or 512 bytes, and it would be the caller's responsibility to provide a suitably large buffer. Then mpu.getFIFOBytes() would call i2cdev::ReadBytes() as appropriate.
However, after screwing around with it for a while, I discovered that the length parameter is uint8_t "all the way down" (as in "it's turtles all the way down!"), so I guess it's up to the programmer to wrap mpu.getFIFOBytes() inside something like 'getLotsOfBytes(uint8_t* buffer, uint16_t any_length)
So, I created the attached short program to test the idea of a 'getManyFIFOBytes()' function that would repeatedly append a 'packetSize' chunk of bytes to a buffer provided by the caller, followed by 1 byte at a time if necessary to get the entire requested length. It's been a while since I have done any pointer gymnastics, so please feel free to 'improve' as necessary ;-).
Regards,
Frank
PS: Homer, just got your email, I'll take a look at it soon.
On Tue, Nov 5, 2019 at 1:09 PM Jeff Rowberg [email protected] wrote:
Quickly stepping in to answer this: the 32-byte limitation comes from the underlying I2C hardware layer, specifically the Wire library in this case. When you call requestFrom(), that's the moment when the transaction occurs on the SDA/SCL lines; incoming data is stored in Wire's internal RX buffer, and it enforces a maximum length to avoid buffer overruns:
https://github.com/arduino/ArduinoCore-avr/blob/c8d6aef6d9331af1ec8dea6f78b4e43174cdb55d/libraries/Wire/src/Wire.cpp#L109-L112
I ran into this limitation very early on in MPU-6050 experiments, so I wrote the I2Cdev class to work around it as best as possible by chunking larger operations into pieces. The MPU-6050 itself would probably have no issue whatsoever doing a very long read or write operation, but you'd have to increase the buffer size to accommodate it. (Note, the samd core for example has a larger buffer size due to its own Wire implementation, and other platforms may use something bigger than 32 as well.)
Carry on with your in-depth troubleshooting... :)
— 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=AA6T32YHF3FN5CGMV6VHV7TQSGZGFA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDDYNZQ#issuecomment-549947110, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323KUUHG5DZEMQMCPULQSGZGFANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
Jeff, Homer,
Please take a look at the results I just posted on my blog at https://www.fpaynter.com/2019/10/mpu6050-fifo-buffer-management-study/ - the '06 November 2019 Update' section at the very end. I think I have pretty much nailed down all the issues with the polling arrangement vs interrupt-driven operations. I'm pretty confident it can now be done reliably, but the time cost for longer loop delays is fairly significant. I could also be blowing smoke, and would appreciate if one or both of you would cast your expert eyes on this ;-).
Regards,
Frank
On Wed, Nov 6, 2019 at 12:59 PM Frank Paynter [email protected] wrote:
Homer, Jeff,
Jeff, thanks for jumping to address this issue. The explanation you gave is certainly helpful, but doesn't explain why mpu.getFIFOBytes(uint8_t* data, uint8_t length) uses a uint8_t object for the length parameter. I would have thought that you could give mpu.getFIFOBytes() any length up to the size of the FIFO itself (which I understand to be either 1024 or 512 bytes, and it would be the caller's responsibility to provide a suitably large buffer. Then mpu.getFIFOBytes() would call i2cdev::ReadBytes() as appropriate.
However, after screwing around with it for a while, I discovered that the length parameter is uint8_t "all the way down" (as in "it's turtles all the way down!"), so I guess it's up to the programmer to wrap mpu.getFIFOBytes() inside something like 'getLotsOfBytes(uint8_t* buffer, uint16_t any_length)
So, I created the attached short program to test the idea of a 'getManyFIFOBytes()' function that would repeatedly append a 'packetSize' chunk of bytes to a buffer provided by the caller, followed by 1 byte at a time if necessary to get the entire requested length. It's been a while since I have done any pointer gymnastics, so please feel free to 'improve' as necessary ;-).
Regards,
Frank
PS: Homer, just got your email, I'll take a look at it soon.
On Tue, Nov 5, 2019 at 1:09 PM Jeff Rowberg [email protected] wrote:
Quickly stepping in to answer this: the 32-byte limitation comes from the underlying I2C hardware layer, specifically the Wire library in this case. When you call requestFrom(), that's the moment when the transaction occurs on the SDA/SCL lines; incoming data is stored in Wire's internal RX buffer, and it enforces a maximum length to avoid buffer overruns:
https://github.com/arduino/ArduinoCore-avr/blob/c8d6aef6d9331af1ec8dea6f78b4e43174cdb55d/libraries/Wire/src/Wire.cpp#L109-L112
I ran into this limitation very early on in MPU-6050 experiments, so I wrote the I2Cdev class to work around it as best as possible by chunking larger operations into pieces. The MPU-6050 itself would probably have no issue whatsoever doing a very long read or write operation, but you'd have to increase the buffer size to accommodate it. (Note, the samd core for example has a larger buffer size due to its own Wire implementation, and other platforms may use something bigger than 32 as well.)
Carry on with your in-depth troubleshooting... :)
— 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=AA6T32YHF3FN5CGMV6VHV7TQSGZGFA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDDYNZQ#issuecomment-549947110, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T323KUUHG5DZEMQMCPULQSGZGFANCNFSM4I6XC3RA .
-- 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)
Great observation Jeff
Changed the code again with the following results:
A) Time to fill the FIFO buffer to B) Packets or C) bytes B) Number of Packets C) FIFO count D) Needed space in bytes for the Packets (FIFO buffer has overflowed when this is greater than the FIFO count) E) Time needed to Retrieve the Bytes
A, B, C, D, E,
10040, 1, 28, 28, 1332,
19956, 2, 56, 56, 2636,
29964, 3, 84, 84, 3740,
39952, 4, 112, 112, 4820,
50068, 5, 140, 140, 5924,
60048, 6, 168, 168, 7020,
69820, 7, 196, 196, 8112,
80052, 8, 224, 224, 9240,
90020, 9, 252, 252, 10180,
100128, 10, 280, 280, 10436, resetFIFO and Get next packet
119960, 11, 308, 308, 10428, resetFIFO and Get next packet
130068, 12, 336, 336, 10420, resetFIFO and Get next packet
139804, 13, 364, 364, 10644, resetFIFO and Get next packet
150152, 14, 392, 392, 10440, resetFIFO and Get next packet
159904, 15, 420, 420, 10440, resetFIFO and Get next packet
170008, 16, 448, 448, 10440, resetFIFO and Get next packet
179952, 17, 476, 476, 10648, resetFIFO and Get next packet
190116, 18, 504, 504, 10432, resetFIFO and Get next packet
200068, 19, 532, 532, 10460, resetFIFO and Get next packet
209984, 20, 560, 560, 10456, resetFIFO and Get next packet
219944, 21, 588, 588, 10432, resetFIFO and Get next packet
230020, 22, 616, 616, 10444, resetFIFO and Get next packet
239952, 23, 644, 644, 10640, resetFIFO and Get next packet
250080, 24, 672, 672, 10444, resetFIFO and Get next packet
260048, 25, 700, 700, 10456, resetFIFO and Get next packet
269988, 26, 728, 728, 10440, resetFIFO and Get next packet
199916, 27, 512, 756, 10656, resetFIFO and Get next packet
290100, 28, 784, 784, 10440, resetFIFO and Get next packet
300012, 29, 812, 812, 10652, resetFIFO and Get next packet
310168, 30, 840, 840, 10444, resetFIFO and Get next packet
319864, 31, 868, 868, 10648, resetFIFO and Get next packet
330180, 32, 896, 896, 10432, resetFIFO and Get next packet
339956, 33, 924, 924, 10440, resetFIFO and Get next packet
350112, 34, 952, 952, 10432, resetFIFO and Get next packet
360032, 35, 980, 980, 10436, resetFIFO and Get next packet
369960, 36, 1008, 1008, 10432, resetFIFO and Get next packet
379968, 37, 1024, 1036, 10420, Overflowed & resetFIFO and Get next packet
using the following code:
/** Get the latest byte from FIFO buffer no matter how much time has passed.
=== GetCurrentFIFOPacket ===
================================================================
Returns 1) when data was received
0) when no valid data is available
Revision: -Added Timers and loop limits for all possible blocking code
================================================================ */
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length) { // overflow proof
int16_t fifoC;
uint32_t BreakTimer;
uint8_t Trash[BUFFER_LENGTH];
if ((fifoC = mpu.getFIFOCount()) > length) {
if (fifoC > 260) { // if you waited to get the FIFO buffer to > 260 bytes it will take longer to get the last packet in the FIFO Buffer than it will take to reset the buffer and wait for the next to arrive
mpu.resetFIFO();
BreakTimer = micros();
fifoC = 0;
while (!(fifoC = mpu.getFIFOCount()) && ((micros() - BreakTimer) <= (11000))) ;
}
fifoC = max(0, fifoC - length); // Save the last packet
uint16_t RemoveBytes = min((int)fifoC, BUFFER_LENGTH);
while (fifoC) { // fifo count will reach zero so this is safe
RemoveBytes = min((int)fifoC, BUFFER_LENGTH);
mpu.getFIFOBytes(Trash, (uint8_t)RemoveBytes);
fifoC -= RemoveBytes;
}
// no more optimization needed as we will be less than 1 packet at this point
if ((fifoC = mpu.getFIFOCount()) > length) {
mpu.getFIFOBytes(Trash, fifoC - length ); // Have less than 1 packet
}
}
BreakTimer = micros();
while (fifoC && (fifoC < length) && ((micros() - BreakTimer) <= (1000))) fifoC = mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
if (fifoC == length) {
//we have only 1 packet!
mpu.getFIFOBytes(data, length); //1 packet
return 1;
}
return 0;
}
uint8_t GetCurrentFIFOPacketTimed(uint8_t *data, uint8_t length) { // overflow proof
int16_t fifoC, StartfifoC;
uint32_t BreakTimer;
uint8_t Trash[BUFFER_LENGTH];
uint32_t StartTime, DeltaT;
StartTime = micros();
if ((StartfifoC = fifoC = mpu.getFIFOCount()) > length) {
if (fifoC > 260) {
mpu.resetFIFO();
BreakTimer = micros();
fifoC = 0;
while (!(fifoC = mpu.getFIFOCount()) && ((micros() - BreakTimer) <= (11000))) ;
}
fifoC = max(0, fifoC - length); // Save the last packet
uint16_t RemoveBytes = min((int)fifoC, BUFFER_LENGTH);
while (fifoC) { // fifo count will reach zero so this is safe
RemoveBytes = min((int)fifoC, BUFFER_LENGTH);
mpu.getFIFOBytes(Trash, (uint8_t)RemoveBytes);
fifoC -= RemoveBytes;
}
// no more optimization needed as we will be less than 1 packet at this point
if ((fifoC = mpu.getFIFOCount()) > length) {
mpu.getFIFOBytes(Trash, fifoC - length ); // Have less than 1 packet
}
}
BreakTimer = micros();
while (fifoC && (fifoC < length) && ((micros() - BreakTimer) <= (1000))) fifoC = mpu.getFIFOCount(); //Finish loading the packet! or skip after 1 millisecond of checking.
if (fifoC == length) {
//we have only 1 packet!
mpu.getFIFOBytes(data, length); //1 packet
DeltaT = micros() - StartTime;
Serial.print(DeltaT);
Serial.print(",");
return 1;
}
Serial.println();
return 0;
}
Conclusion Looking at the magic number of 252 bytes we can see that it is quicker to Reset the FIFO buffer than it is to empty it Example: Taking 90020us we get 9 packets with 252 bytes of data in the FIFO buffer taking10180us to retrieve Taking 100128us we get 10 packets with 280 bytes of data in the FIFO buffer by resetting it we can retrieve the Next Newer packet in just 10436us By resetting the buffer at any byte count over 252 we can consistently retrieve the next packet in less time than it takes to empty the current buffer and clean up any overflow.
so we have 2 options we can block or bail. Blocking Code would be:
if (fifoC > 260) {
mpu.resetFIFO();
BreakTimer = micros();
fifoC = 0;
while (!(fifoC = mpu.getFIFOCount()) && ((micros() - BreakTimer) <= (11000))) ;
}
Bail would be:
if (fifoC > 260) {
mpu.resetFIFO();
return 0;
}
The blocking code makes more sense as it will return a valid reading in a short time compared to the 100ms delay it took allowing the buffer to fill to this level. Bailing would only invite the buffer to refill and bail again stopping progress.
Testing code used for proofing:
// ================================================================
// === MAIN PROGRAM LOOP ===
// ================================================================
void loop() {
static uint32_t StartT, DT;
static uint8_t PacketCount = 1;
uint16_t fifoC;
static uint8_t C = 0;
// Get PacketCount Packets and watch for overflow conditions 1024 and 512 depending on the MPU model
while ((fifoC = mpu.getFIFOCount()) < (packetSize * PacketCount)) {
if ((fifoC == 1024) || (fifoC == 512)) break;
}
// We have the number of packets needed let check the time
DT = micros() - StartT;
StartT = micros(); // a new packet timer has started even though we haven't got the current packet
Serial.print(DT);
Serial.print(", ");
Serial.print(PacketCount);
Serial.print(", ");
Serial.print(fifoC);
Serial.print(", ");
Serial.print(packetSize * PacketCount);
Serial.print(", ");
if (!GetCurrentFIFOPacketTimed(fifoBuffer, packetSize)) return; // Get the current packet
PacketCount += C;
C = 1;
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);
Serial.println();
return;
}
Homer
The explanation you gave is certainly helpful, but doesn't explain why mpu.getFIFOBytes(uint8_t* data, uint8_t length) uses a uint8_t object for the length parameter. I would have thought that you could give mpu.getFIFOBytes() any length up to the size of the FIFO itself (which I understand to be either 1024 or 512 bytes, and it would be the caller's responsibility to provide a suitably large buffer.
You are correct. There's no good reason for why that argument is a uint8_t instead of size_t or uint16_t. My only lame excuse is that I probably assumed a call to that function would be grabbing a packet at a time, and that should be way less than 256 bytes. (Not a safe assumption, clearly.)
I've read through the detailed blog post quickly, and the in-depth study here is pretty remarkable. Am I correct that the following two unexpected behaviors are the source of much of the original confusion:
- Interrupt count does not match DMP packet count (2:1 ratio)
- If a FIFO overflow occurs, it doesn't stop storing data but simply loops back around, continuing normally and overwriting whatever was there before (i.e. 1024 bytes of data are always fresh, but since
1024 % packetSize != 0, the tail will be mid-packet if the FIFO is full)
Is that right?
Jeff, Homer,
Yes, that is pretty much correct. I believe I narrowed the 2:1 problem down to the interrupt line being pulsed every 5 mSec, while the MPU is loading the FIFO with packets every 10 mSec. I have no idea where the extra interrupt pulses are coming from, as disabling the DMP interrupt via the MPU's registers disables all interrupt line activity, and re-enabling DMP interrupts causes interrupts at 5 mSec intervals to re-appear. Maybe there is some internal DMP function that runs at 200Hz?
The FIFO overflow issue is the real killer, as you can see from the work Homer has done. At one point I thought the real solution to this mess was to simply disable DMP FIFO loads when the FIFO was nearly full, thus avoiding packet corruption. I noticed there is actually some commented-out code in MPU6050.h intended to do this, but I couldn't find anything in the MPU6050 specs that would support this feature. Maybe that is only available in some later chip release? Being able to stop the FIFO from overflowing would be very nice.
FWIW, I'm using my blog site as a kind of engineering notebook, so I can hopefully avoid running in circles too much! ;-).
Any thoughts?
Frank
On Thu, Nov 7, 2019 at 12:36 PM Jeff Rowberg [email protected] wrote:
The explanation you gave is certainly helpful, but doesn't explain why mpu.getFIFOBytes(uint8_t* data, uint8_t length) uses a uint8_t object for the length parameter. I would have thought that you could give mpu.getFIFOBytes() any length up to the size of the FIFO itself (which I understand to be either 1024 or 512 bytes, and it would be the caller's responsibility to provide a suitably large buffer.
You are correct. There's no good reason for why that argument is a uint8_t instead of size_t or uint16_t. My only lame excuse is that I probably assumed a call to that function would be grabbing a packet at a time, and that should be way less than 256 bytes. (Not a safe assumption, clearly.)
I've read through the detailed blog post quickly, and the in-depth study here is pretty remarkable. Am I correct that the following two unexpected behaviors are the source of much of the original confusion:
- Interrupt count does not match DMP packet count (2:1 ratio)
- If a FIFO overflow occurs, it doesn't stop storing data but simply loops back around, continuing normally and overwriting whatever was there before (i.e. 1024 bytes of data are always fresh, but since 1024 % packetSize != 0, the tail will be mid-packet if the FIFO is full)
Is that right?
— 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=AA6T325EN4A2TH5YDSNSE3LQSRG3BA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDNGTWI#issuecomment-551184857, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T32ZJUIXDPZUZ4OQIHBTQSRG3BANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
I know that my original assumption about the FIFO (which wasn't ridiculous on its face, but should have been verified) is that an overflow condition would set a flag and then stop filling more data until you read or reset the buffer. In light of this, it's not hard to see why the example code behaves badly in the case of an overflow. My hope was to keep the overflow from occurring, but that clearly isn't always doable or even desirable in your infrequent-read case.
Concerning the double interrupt, does it occur immediately after you first enable the DMP, or only after the FIFO is full? Just a guess that I'd have to investigate (if you haven't already), but is there a possibility that it's a FIFO overflow detection interrupt?
With the knowledge that valid data is always head-aligned in the FIFO and the partial packet is at the tail--assuming that the head and tail pointers keep moving as new data is added (and overwritten) after an overflow occurs--the following should be true:
- If no FIFO overflow has occurred, you can always read exactly
[packetsize]bytes to get the next chronological packet in the FIFO (as long as there are at least[packetsize]bytes available, of course). - If a FIFO overflow has occurred and you want to keep as much data as possible, you can read and discard exactly
[fifosize % packetsize]bytes to realign the tail to the beginning of the next valid packet, then continue reading normally (ideally right away to avoid another overflow). - If a FIFO overflow has occurred and you only care about immediate data, you can just reset the FIFO and then wait one packet interval before reading
[packetsize]bytes (even if more are available).
Point 3 may be the simplest in your case, if you can use a simple non-blocking delay whenever you want to read the instantaneous DMP output:
- Reset FIFO
- Store
millis()result int0 - Once
millis() - t0 > 10, read one packet from FIFO (assuming DMP is configured for 100 Hz output)
There's a 10ms cycle time that could be eliminated by staying on top of the FIFO, but as long as you can keep executing other stuff during that 10ms, I'm betting that doesn't matter in your case. This approach requires zero knowledge about anything else the MPU is doing and theoretically guarantees that you'll always get good data without interrupts, buffering, or anything else to complicate the process.
Any obvious holes in this analysis based on what you have seen?
Jeff,
Actually the mpu.resetFIFO was the technique I used for quite a while, and it does seem to work. What I did was to reset the FIFO and then call mpu.GetFIFOCount() repeatedly until the result was == 1 full packet, then read. I think that technique was a bit inelegant, but worked. Homer's recent experiments indicate that the mpu.ResetFIFO() technique is actually cheaper (timewise) than anything else for loop delays more than about 350 mSec for a 1024-byte buffer and 175 mSec for a 512 byte buffer.
Regarding the 5 mSec vs 10 mSec interrupt pulse issue, AFAICT, the 5 mSec pulse train is always on, or always off - no middle ground. I think I would have noticed by now if the rate changed by a factor of 2, but I suppose stranger things have happened ;-).
Homer?
Frank
On Thu, Nov 7, 2019 at 4:28 PM Jeff Rowberg [email protected] wrote:
I know that my original assumption about the FIFO (which wasn't ridiculous on its face, but should have been verified) is that an overflow condition would set a flag and then stop filling more data until you read or reset the buffer. In light of this, it's not hard to see why the example code behaves badly in the case of an overflow. My hope was to keep the overflow from occurring, but that clearly isn't always doable or even desirable in your infrequent-read case.
Concerning the double interrupt, does it occur immediately after you first enable the DMP, or only after the FIFO is full? Just a guess that I'd have to investigate (if you haven't already), but is there a possibility that it's a FIFO overflow detection interrupt?
With the knowledge that valid data is always head-aligned in the FIFO and the partial packet is at the tail--assuming that the head and tail pointers keep moving as new data is added (and overwritten) after an overflow occurs--the following should be true:
- If no FIFO overflow has occurred, you can always read exactly [packetsize] bytes to get the next chronological packet in the FIFO (as long as there are at least [packetsize] bytes available, of course).
- If a FIFO overflow has occurred and you want to keep as much data as possible, you can read and discard exactly [fifosize % packetsize] bytes to realign the tail to the beginning of the next valid packet, then continue reading normally (ideally right away to avoid another overflow).
- If a FIFO overflow has occurred and you only care about immediate data, you can just reset the FIFO and then wait one packet interval before reading [packetsize] bytes (even if more are available).
Point 3 may be the simplest in your case, if you can use a simple non-blocking delay whenever you want to read the instantaneous DMP output:
- Reset FIFO
- Store millis() result in t0
- Once millis() - t0 > 10, read one packet from FIFO
There's a 10ms cycle time that could be eliminated by staying on top of the FIFO, but as long as you can keep executing other stuff during that 10ms, I'm betting that doesn't matter in your case. This approach requires zero knowledge about anything else the MPU is doing and theoretically guarantees that you'll always get good data without interrupts, buffering, or anything else to complicate the process.
Any obvious holes in this analysis based on what you have seen?
— 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=AA6T327AD3I3XPIJ2LHBMXLQSSB7NA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDN4AKA#issuecomment-551272488, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T326XBWYMMED73EECUETQSSB7NANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
All,
So here's a run for various programmed loop delays using the 'brute force' mpu.resetFIFO() technique to obtain the latest MPU6050 packet. As can be seen in the following Excel plot, the time required to reset the FIFO and wait for a new packet is a relatively constant 8 mSec, across all loop delay settings, and the programming is trivial compared to what we've been using. I am beginning to think 'simpler is better' in this case ;-).
[image: 191106_Overflow8Test2.jpg]
And here's the 'simplified' getCurrentFIFOPacket() code:
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length, uint16_t max_loops) { mpu.resetFIFO(); int countloop = 0;
while (mpu.getFIFOCount() < packetSize && countloop < max_loops) { countloop++; }
if (countloop >= max_loops) { return 0; }
//if we get to here, there should be exactly one packet in the FIFO mpu.getFIFOBytes(data, packetSize); return 1; }
On Thu, Nov 7, 2019 at 6:20 PM Frank Paynter [email protected] wrote:
Jeff,
Actually the mpu.resetFIFO was the technique I used for quite a while, and it does seem to work. What I did was to reset the FIFO and then call mpu.GetFIFOCount() repeatedly until the result was == 1 full packet, then read. I think that technique was a bit inelegant, but worked. Homer's recent experiments indicate that the mpu.ResetFIFO() technique is actually cheaper (timewise) than anything else for loop delays more than about 350 mSec for a 1024-byte buffer and 175 mSec for a 512 byte buffer.
Regarding the 5 mSec vs 10 mSec interrupt pulse issue, AFAICT, the 5 mSec pulse train is always on, or always off - no middle ground. I think I would have noticed by now if the rate changed by a factor of 2, but I suppose stranger things have happened ;-).
Homer?
Frank
On Thu, Nov 7, 2019 at 4:28 PM Jeff Rowberg [email protected] wrote:
I know that my original assumption about the FIFO (which wasn't ridiculous on its face, but should have been verified) is that an overflow condition would set a flag and then stop filling more data until you read or reset the buffer. In light of this, it's not hard to see why the example code behaves badly in the case of an overflow. My hope was to keep the overflow from occurring, but that clearly isn't always doable or even desirable in your infrequent-read case.
Concerning the double interrupt, does it occur immediately after you first enable the DMP, or only after the FIFO is full? Just a guess that I'd have to investigate (if you haven't already), but is there a possibility that it's a FIFO overflow detection interrupt?
With the knowledge that valid data is always head-aligned in the FIFO and the partial packet is at the tail--assuming that the head and tail pointers keep moving as new data is added (and overwritten) after an overflow occurs--the following should be true:
- If no FIFO overflow has occurred, you can always read exactly [packetsize] bytes to get the next chronological packet in the FIFO (as long as there are at least [packetsize] bytes available, of course).
- If a FIFO overflow has occurred and you want to keep as much data as possible, you can read and discard exactly [fifosize % packetsize] bytes to realign the tail to the beginning of the next valid packet, then continue reading normally (ideally right away to avoid another overflow).
- If a FIFO overflow has occurred and you only care about immediate data, you can just reset the FIFO and then wait one packet interval before reading [packetsize] bytes (even if more are available).
Point 3 may be the simplest in your case, if you can use a simple non-blocking delay whenever you want to read the instantaneous DMP output:
- Reset FIFO
- Store millis() result in t0
- Once millis() - t0 > 10, read one packet from FIFO
There's a 10ms cycle time that could be eliminated by staying on top of the FIFO, but as long as you can keep executing other stuff during that 10ms, I'm betting that doesn't matter in your case. This approach requires zero knowledge about anything else the MPU is doing and theoretically guarantees that you'll always get good data without interrupts, buffering, or anything else to complicate the process.
Any obvious holes in this analysis based on what you have seen?
— 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=AA6T327AD3I3XPIJ2LHBMXLQSSB7NA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDN4AKA#issuecomment-551272488, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T326XBWYMMED73EECUETQSSB7NANCNFSM4I6XC3RA .
-- 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)
Jeff and Frank,
"Concerning the double interrupt..."
They happen at @ 5ms intervals at the instant the interrupts are enabled. I've beaten this one to death and haven't found or seen any solution out there for it.
"... assuming that the head and tail pointers keep moving as new data is added..."
This is correct. The only issue that I have discovered you can catch the FIFO buffer being filled and get a faulty FIFO count. leading to a corrupted last packet if not checked. Using the physical Interrupt helps by giving you a good time to read the buffer. without this, you could be picking the exact time the FIFO buffer is written. (Successfully tested this theory)
If a FIFO overflow has occurred and you want to keep as much data as possible, you can read and discard exactly [fifosize % packetsize] bytes to realign the tail to the beginning of the next valid packet, then continue reading normally (ideally right away to avoid another overflow).
This is correct and to give you an idea of how long it takes to empty the buffer several additional packets will already be available by the time you clear the buffer to this point in time. The last packet in the buffer will be old news by the time you're finally getting to that data.
If a FIFO overflow has occurred and you only care about immediate data, you can just reset the FIFO and then wait for one packet interval before reading
It's worse than this. At 9 packets worth of data, it is cheaper timewise to reset and wait than it is to try to catch up. The likely hood that at the 5 to 8 packets point, catching up wouldn't be worth the trouble and resetting would be faster as the next packet wouldn't likely arrive before 10ms passes.
(I'm testing the theory that the fixed clock on the MPU6050 DMP isn't related to the FIFO buffer reset. meaning that you could reset the buffer moments before the next packet arrives and still get the nest packet on time. I'm trying to envision a routine that can predict the next packet arrival and decide to reset or read and catch up. This code is possibly in the works but it may become overkill if I don't discover a way to match the MPU's FIFO clock)
What I've learned:
- If you're only needing the current packet and you have 9 or greater packets it is absolutely quicker to reset and pound GetFIFOCount() to detect when the newest packet becomes available.
- If you overflow just reset and wait for the next packet it's much faster than correcting the corrupted buffer a sifting through to the last packet and solves everything.
- You can't rely on only one GetFIFOCount() request as you can catch the MPU in the process of filling the FIFO buffer getting a misleading FIFO Count. This is usually only an issue when you are recovering from an overflow otherwise you can tell that the FIFO buffer is properly filled as the FIFO byte count can be evenly divided by packet size.
Homer
All,
Do we know for sure that mpu.resetFIFO() always results in a completely new packet being loaded into the FIFO. In other words, what happens if the mpu.resetFIFO() call occurs while a packet is being loaded? Everything I have seen to date is consistent with the idea that the first packetSize bytes loaded into the FIFO after a reset are always a valid packet, but I don't see that written in stone anywhere ;-).
Regards,
Frank
On Thu, Nov 7, 2019 at 6:59 PM Homer Creutz [email protected] wrote:
Jeff and Frank,
"Concerning the double interrupt..."
They happen at @ 5ms intervals at the instant the interrupts are enabled. I've beaten this one to death and haven't found or seen any solution out there for it.
"... assuming that the head and tail pointers keep moving as new data is added..."
This is correct. The only issue that I have discovered you can catch the FIFO buffer being filled and get a faulty FIFO count. leading to a corrupted last packet if not checked. Using the physical Interrupt helps by giving you a good time to read the buffer. without this, you could be picking the exact time the FIFO buffer is written. (Successfully tested this theory)
If a FIFO overflow has occurred and you want to keep as much data as possible, you can read and discard exactly [fifosize % packetsize] bytes to realign the tail to the beginning of the next valid packet, then continue reading normally (ideally right away to avoid another overflow).
This is correct and to give you an idea of how long it takes to empty the buffer several additional packets will already be available by the time you clear the buffer to this point in time. The last packet in the buffer will be old news by the time you're finally getting to that data.
If a FIFO overflow has occurred and you only care about immediate data, you can just reset the FIFO and then wait for one packet interval before reading
It's worse than this. At 9 packets worth of data, it is cheaper timewise to reset and wait than it is to try to catch up. The likely hood that at the 5 to 8 packets point, catching up wouldn't be worth the trouble and resetting would be faster as the next packet wouldn't likely arrive before 10ms passes.
(I'm testing the theory that the fixed clock on the MPU6050 DMP isn't related to the FIFO buffer reset. meaning that you could reset the buffer moments before the next packet arrives and still get the nest packet on time. I'm trying to envision a routine that can predict the next packet arrival and decide to reset or read and catch up. This code is possibly in the works but it may become overkill if I don't discover a way to match the MPU's FIFO clock)
What I've learned:
- If you're only needing the current packet and you have 9 or greater packets it is absolutely quicker to reset and pound GetFIFOCount() to detect when the newest packet becomes available.
- If you overflow just reset and wait for the next packet it's much faster than correcting the corrupted buffer a sifting through to the last packet and solves everything.
- You can't rely on only one GetFIFOCount() request as you can catch the MPU in the process of filling the FIFO buffer getting a misleading FIFO Count. This is usually only an issue when you are recovering from an overflow otherwise you can tell that the FIFO buffer is properly filled as the FIFO byte count can be evenly divided by packet size.
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=AA6T322NPN3PFW73D6UYB7DQSSTW7A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDOIBRI#issuecomment-551321797, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T324JXWOLZ7ARVS2GNLDQSSTW7ANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
I have been following this thread for a while and would like to ask a question. Be aware I haven't gotten the code off GitHub for quite a while so anything I might have is hopelessly outdated. That being said...
I don't understand the problem with determining where the extra interrupts are coming from. Doesn't the interrupt handler check the few possible sources and simply return or at least process these unwanted interrupts differently? I haven't looked deeply into how the MPU6050 handles interrupts but most processors have status registers ( or separate vectors) for handling interrupts. Are you saying you are getting a known interrupt at an unexpected time or and unexpected interrupt? I find it hard to believe it is better to Poll than handle interrupts. My quick review of the mpu6050 data sheet said; I believe; that there are 4 interrupt sources. I admit I have not read this datasheet thoroughly so this may be wrong. The point is there has to be a way to determine where every interrupt comes from and process them accordingly.
maine,
Yes, you would think, wouldn't you ;-). Join the fun and figure it out for us, because we haven't been able to! ;-).
Frank
On Thu, Nov 7, 2019 at 9:03 PM msaine [email protected] wrote:
I have been following this thread for a while and would like to ask a question. Be aware I haven't gotten the code off GitHub for quite a while so anything I might have is hopelessly outdated. That being said...
I don't understand the problem with determining where the extra interrupts are coming from. Doesn't the interrupt handler check the few possible sources and simply return or at least process these unwanted interrupts differently? I haven't looked deeply into how the MPU6050 handles interrupts but most processors have status registers ( or separate vectors) for handling interrupts. Are you saying you are getting a known interrupt at an unexpected time or and unexpected interrupt? I find it hard to believe it is better to Poll than handle interrupts. My quick review of the mpu6050 data sheet said; I believe; that there are 4 interrupt sources. I admit I have not read this datasheet thoroughly so this may be wrong. The point is there has to be a way to determine where every interrupt comes from and process them accordingly.
— 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=AA6T32ZXIMRW5BY46QBBNSLQSTCF5A5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDOPDAY#issuecomment-551350659, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T325OM3TUOANVKGDO2CDQSTCF5ANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)
The issue is that the MPU-6050's documentation is quite sparse concerning anything DMP-related. The INT_STATUS register notes nothing about the DMP:
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf#page=28
It's possible that it mimics the MPU-6500 somewhat, which has more info available:
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6500-Register-Map2.pdf#page=30
@paynterf or @ZHomeSlice, did you read the INT_STATUS register value on each of the 200Hz interrupt signals to see which bits are set, by chance?
Jeff,
@paynterf or @ZHomeSlice, did you read the INT_STATUS register value on each of the 200Hz interrupt signals to see which bits are set, by chance?
Yes it is always bit 0 the data ready for both the 5ms interrupts
Homer
To all our friends :) This Document might shed some light on the DMP setup. Note that the registers represented here may not match the registers found in V6.12 or the earlier V2.0 of the DMP Firmware to adjust for the differences use the provided V6.12 DMP register map (DMP_Image.h) found here: (DMP_Image.h for V6.12 With additions at the bottom for my Library)
Invensense DMP Documentation I have rounded up: Application Note - Programming Sequence for DMP Hardware Functions v12 (....pdf
5.7 Discusses interrupt Status Although I've not been able to get Bit1 to trigger when DMP interrupt is generated. I believe it is set in error on Bit0 along with Data ready interrupt generating the 2 hits on the DMP The DMP uses 2 readings to calculate its values and that is at 200hz giving the 5ms interrupt tick
in the code, we set register 0x38 to 2 meaning that the DMP interrupt is enabled on page 39:
Enable DMP Interrupt 5. Write {0x02} to INT_ENABLE (0x38)
Register 0x3A – Interrupt Status
INT_STATUS
Description:
This register shows the interrupt status of each interrupt generation source. Each bit will clear after the register is read.
For information regarding the corresponding interrupt enable bits, please refer to Register 56.
For a list of I2C Master interrupts, please refer to Register 54.
Bits 2 and 1 are reserved.
Parameters:
7) FF_INT This bit automatically sets to 1 when a Free Fall interrupt has been generated.
The bit clears to 0 after the register has been read.
6) MOT_INT This bit automatically sets to 1 when a Motion Detection interrupt has been generated.
The bit clears to 0 after the register has been read.
5) ZMOT_INT This bit automatically sets to 1 when a Zero Motion Detection interrupt has been generated.
The bit clears to 0 after the register has been read.
4) FIFO_OFLOW_INT This bit automatically sets to 1 when a FIFO buffer overflow interrupt has been generated.
The bit clears to 0 after the register has been read.
3) I2C_MST_INT This bit automatically sets to 1 when an I2C Master interrupt has been generated. For a list of I2C Master interrupts, please refer to Register 54.
The bit clears to 0 after the register has been read.
2) Not Used "Reserved"
1) ** "Reserved but shows:" DMP_INT This bit automatically sets to 1 when the DMP interrupt has been generated.
0)DATA_RDY_INT This bit automatically sets to 1 when a Data Ready interrupt is generated.
The bit clears to 0 after the register has been read.
Found this at 10.1 DMP Interrupt Each time a set of data is written to the FIFO, it raises an interrupt. Since the interrupt can come from multiple sources, the user should confirm that it is related to one of the advanced hardware features described in this document by reading the Interrupt Status register (0x3A). If the interrupt was raised by an advanced hardware feature, then the value in this register should be 0x02. The contents of the FIFO can be read at this point. To learn the procedure to read the MPU FIFO, refer to InvenSense Product Specification and Register Map documents.
Again I never get 0x02 I only got 0x01 from that register. Homer
Homer I was trying to look at how the interrupts are handled and came across these macros #define INT_STATUS_READ_WOM_INT(Data) MPUi2cRead(0x3A, 1, 6, (uint8_t *)Data) // 1 Wake on motion interrupt occurred. #define INT_STATUS_READ_FIFO_OFLOW_INT(Data) MPUi2cRead(0x3A, 1, 4, (uint8_t *)Data) // 1 Fifo Overflow interrupt occurred. #define INT_STATUS_READ_FSYNC_INT(Data) MPUi2cRead(0x3A, 1, 3, (uint8_t *)Data) // 1 Fsync interrupt occurred. #define INT_STATUS_READ_RAW_DATA_RDY_INT(Data) MPUi2cRead(0x3A, 1, 0, (uint8_t *)Data) // T 1 Sensor Register Raw Data sensors are updated and Ready to be read.
The one thing I am concerned about is the fact that once the register is read the bits are cleared. What is the point of having 4 macros if when the first is executed the register is cleared and the rest become invalid? Seems to me that there should be a single read of that register and have the results stored in a protected variable and a flag to indicate whether it has been checked for each function, not four possible reads.
I am still looking for the ISR routine to see the actual processing of the interrupt. I am still trying to find my way around the Arduino environment.
Monty
MSaine Very interested in your macros
Frank, Jeff & MSaine Testing what resetFIFO() does. Conclusions: Fifo Reset does NOT seem to reset the DMP timer. so even after the resetFIFO(), the next data arrives at exactly 10ms later from the time the previous event.
Test Code:
#define FIFOResetShift 1000
int FindDMPTiming() {
int16_t fifoC;
uint32_t Last, StartTime, DeltaT;
uint16_t Testing = 0;
uint32_t MSDelay = 9900 - FIFOResetShift;
int DetectedSaveEvent;
mpu.resetFIFO();
while(!mpu.getFIFOCount());
Last = micros();
while (Testing++) {
delayMicroseconds(MSDelay);
do {
while(!(fifoC = mpu.getFIFOCount()))MSDelay+=1;
StartTime = micros();
DetectedSaveEvent = 0;
if (fifoC && (fifoC < packetSize)) DetectedSaveEvent = 1;
else MSDelay--;
} while (!fifoC);
delayMicroseconds(FIFOResetShift);
mpu.resetFIFO(); //Keep the Buffer from overflowing
Serial.print ("Test#");
Serial.print(Testing);
Serial.print("\tfifoC = ");
Serial.print(DetectedSaveEvent ? " *" : " ");
Serial.print(fifoC);
Serial.print ("\tPredited TS = ");
Serial.print(Last + DeltaT);
Serial.print ("\tTime Stamp = ");
Serial.print(StartTime);
DeltaT = StartTime - Last;
Serial.print ("\tDeltaT = ");
Serial.print(DeltaT);
Serial.print ("\tMSDelay = ");
Serial.print(MSDelay);
Serial.println();
Last = StartTime;
}
}
This code lands a delay that finds the exact time the buffer is written to. Watch the MSDelay time it will drop to a lower value and settle down at this time the fifoC value will start showing *## values that are not 28 we are detecting the exact time the FIFO was written to catching a partial packet. Also, look for the DeltaT which will float very near 10000us
The other values are for further predictions. my goal is to find a routine that will nail down the exact time the *## values are written and consistently capture them. Goal: Then I can make an exact timer watching the micros() value to snag the partial packet. we can then assume that the full packet will be there by the time we get to read the 28th byte from the buffer.
msaine, You mentioned the use of interrupts vs just using code. I am hoping to create a routine that will eliminate the need to check for the int pin trigger but keep the timing needed so something like this could be used to capture the next FIFO packet:
Not tested:
unsigned long _PacketTimer;
void setup(){
...
uint8_t fifoC;
mpu.resetFIFO();
while (1) {
while (!(fifoC = mpu.getFIFOCount())); // look for a packet
fifo _PacketTimer = micros(); // Set the _PacketTimer as fast as we can
if (fifoC && fifoC < packetSize) break; //Found what we are looking for a partial packet;
else mpu.resetFIFO(); //This was a full packet so lets shoot for another we need to detect a partial packet.
}
}
#define SafetyMargin 100
void loop() {
// We are assuming that the inherent programming delay will allow the packet to be ready to be safe we can add a safety margin value to give it a shift to the future without affecting the overall timer
if ( millis() - _PacketTimer >= (10000 + SafetyMargin)) {
_PacketTimer += (10000);
mpu.getFIFOBytes(fifoBuffer, packetSize);
// Use the data
}
}
I realize that the uno timer may not stay consistent with additional tests that trigger every so many reading We could continue to refine the timer even more.
Homer
All,
While trying to figure out why my MPU6050 setup works fine until I run the motors on my robot, I ran across what I think is an interesting bit of information about the MPU6050 response to the mpu.resetFIFO() call, which I was using in a 'brute force' approach for 'GetCurrentFIFOPacket()'. Apparently it doesn't always recover from this operation, but hangs and never loads any more packets into the FIFO. Here's my original algorithm. You can see that I just reset the MPU FIFO and then loop until there are exactly 28 bytes available, and then grab them and exit. I also have a backup max_loops counter to prevent infinite blocking. When I run this code, it will run fine for seconds or minutes, but then eventually returns an error code that shows the while loop maxed out the counter (set for 100 loops). at 2 Msec delay per loop, this is equivalent to waiting 200 mSec for 28 packets to show up. When I look at the data in detail, it becomes apparent that the FIFO count on error exit is 0 bytes, implying that the DMP never started up again after the FIFO reset (or the FIFO itself never got re-enabled, or something else entirely)
uint8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length, uint16_t max_loops) { mpu.resetFIFO(); delay(1); //int countloop = 0;
fifoCount = mpu.getFIFOCount(); GetPacketLoopCount = 0;
while (fifoCount < packetSize && GetPacketLoopCount < max_loops) { GetPacketLoopCount++; fifoCount = mpu.getFIFOCount(); delay(2); }
if (GetPacketLoopCount >= max_loops) { return 0; }
//if we get to here, there should be exactly one packet in the FIFO mpu.getFIFOBytes(data, packetSize); return 1; }
So I modified the algorithm to include an outer loop that calls resetFIFO() again (up to 3 times) if the inner loop maxes out the 100-loop count. When I do this, the program will run "forever" (i.e. much longer than it ever did before without crashing). I instrumented the code to print out the number of times the inner loop executed, and the number of times the outer loop executed. As can be seen in the following plot, the inner loop executes between 0 and 15 times, which I assume is because the 'resetFIFO()' call can happen anywhere in the 10 mSec window between normal FIFO load operations. Then, 4 times within the 3 minutes or so shown here, the outer loop counter jumped from 1 to 2, indicating that the first try with mpu.resetFIFO() didn't work, but the second one did. There have been no '3' results that I have seen so far.
[image: 191110 GetCurrentFIFOPacket resetFIFO Test1.jpg]
Here's a plot showing the full run (almost 17 minutes without error). In this plot there are 19 instances where the first mpu.resetFIFO() call resulted in disabling subsequent packet loads into the FIFO. The plot itself runs about 17 minutes, so there are more than one occurrence per minute where the resetFIFO operation malfunctions for one reason or another. Again, the second operation always succeeds.
[image: 191110 GetCurrentFIFOPacket resetFIFO Test2.jpg]
Any thoughts?
TIA,
Frank
On Sat, Nov 9, 2019 at 12:02 PM Homer Creutz [email protected] wrote:
MSaine Very interested in your macros
Frank, Jeff & MSaine Testing what resetFIFO() does. Conclusions: Fifo Reset does NOT seem to reset the DMP timer. so even after the resetFIFO(), the next data arrives at exactly 10ms later from the time the previous event.
Test Code:
#define FIFOResetShift 1000
int FindDMPTiming() { int16_t fifoC; uint32_t Last, StartTime, DeltaT; uint16_t Testing = 0; uint32_t MSDelay = 9900 - FIFOResetShift; int DetectedSaveEvent; mpu.resetFIFO(); while(!mpu.getFIFOCount()); Last = micros(); while (Testing++) {
delayMicroseconds(MSDelay); do { while(!(fifoC = mpu.getFIFOCount()))MSDelay+=1; StartTime = micros(); DetectedSaveEvent = 0; if (fifoC && (fifoC < packetSize)) DetectedSaveEvent = 1; else MSDelay--; } while (!fifoC); delayMicroseconds(FIFOResetShift); mpu.resetFIFO(); //Keep the Buffer from overflowing Serial.print ("Test#"); Serial.print(Testing); Serial.print("\tfifoC = "); Serial.print(DetectedSaveEvent ? " *" : " "); Serial.print(fifoC); Serial.print ("\tPredited TS = "); Serial.print(Last + DeltaT); Serial.print ("\tTime Stamp = "); Serial.print(StartTime); DeltaT = StartTime - Last; Serial.print ("\tDeltaT = "); Serial.print(DeltaT); Serial.print ("\tMSDelay = "); Serial.print(MSDelay); Serial.println(); Last = StartTime;} }
This code lands a delay that finds the exact time the buffer is written to. Watch the MSDelay time it will drop to a lower value and settle down at this time the fifoC value will start showing *## values that are not 28 we are detecting the exact time the FIFO was written to catching a partial packet. Also, look for the DeltaT which will float very near 10000us
The other values are for further predictions. my goal is to find a routine that will nail down the exact time the *## values are written and consistently capture them. Goal: Then I can make an exact timer watching the micros() value to snag the partial packet. we can then assume that the full packet will be there by the time we get to read the 28th byte from the buffer.
msaine, You mentioned the use of interrupts vs just using code. I am hoping to create a routine that will eliminate the need to check for the int pin trigger but keep the timing needed so something like this could be used to capture the next FIFO packet:
Not tested:
unsigned long _PacketTimer; void setup(){ ... uint8_t fifoC; mpu.resetFIFO(); while (1) { while (!(fifoC = mpu.getFIFOCount())); // look for a packet fifo _PacketTimer = micros(); // Set the _PacketTimer as fast as we can if (fifoC && fifoC < packetSize) break; //Found what we are looking for a partial packet; else mpu.resetFIFO(); //This was a full packet so lets shoot for another we need to detect a partial packet. } } #define SafetyMargin 100 void loop() { // We are assuming that the inherent programming delay will allow the packet to be ready to be safe we can add a safety margin value to give it a shift to the future without affecting the overall timer if ( millis() - _PacketTimer >= (10000 + SafetyMargin)) { _PacketTimer += (10000); mpu.getFIFOBytes(fifoBuffer, packetSize);
// Use the data} }
I realize that the uno timer may not stay consistent with additional tests that trigger every so many reading We could continue to refine the timer even more.
Homer
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jrowberg/i2cdevlib/issues/479?email_source=notifications&email_token=AA6T323WZT3ZMW37IP6CFFTQS3UJJA5CNFSM4I6XC3RKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEDUKOJQ#issuecomment-552118054, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA6T3236OPSX3KOP4QDAGGLQS3UJJANCNFSM4I6XC3RA .
-- G.Frank Paynter, PhD OSU ESL Research Scientist (ret) EM Workbench LLC 614 638-6749 (cell)