Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with SPI data updates #42

Open
DaudiGabriel opened this issue Apr 21, 2020 · 13 comments
Open

Issue with SPI data updates #42

DaudiGabriel opened this issue Apr 21, 2020 · 13 comments
Labels
sticky Issue is closed - but left open for information only

Comments

@DaudiGabriel
Copy link

DaudiGabriel commented Apr 21, 2020

Subject of the issue

If the main loop evaluation time in an Arduino sketch is slightly larger than the update rate of the sensor, the Sensor will not report any updates via SPI any more.
Not sure, whether this is a library problem or whether there is some internal (inside the BNO080) buffer overflow, which stops the sensor from working properly.

Your workbench

  • What development board or microcontroller are you using?
    -> Teensy 4.0
  • What version of hardware or breakout board are you using?
    -> don't know
  • How is the breakout board to your microcontroller?
    -> connected with SPI
  • How is everything being powered?
    -> USB power supply
  • Are there any additional details that may help us help you?
    -> no

Steps to reproduce

Slightly modified version of SPI example "Example1-RotationVector"

  • Sample time of 10 ms, delay of 9 ms in main loop --> everything works fine
#include "SparkFun_BNO080_Arduino_Library.h"
BNO080 myIMU;

//These pins can be any GPIO
byte imuCSPin = 10;
byte imuWAKPin = 14;
byte imuINTPin = 16;
byte imuRSTPin = 15;

unsigned long startTime; //Used for calc'ing Hz
long measurements = 0;   //Used for calc'ing Hz

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println("BNO080 SPI Read Example");
  
  if(myIMU.beginSPI(imuCSPin, imuWAKPin, imuINTPin, imuRSTPin) == false)
  {
    Serial.println("BNO080 over SPI not detected. Are you sure you have all 6 connections? Freezing...");
    while(1);
  }

  myIMU.enableRotationVector(10); //Send data update every 10ms
  
  startTime = millis();
}

void loop()
{
  Serial.println("Doing other things");
  delay(9); //You can do many other things. We spend most of our time printing and delaying.
  
  //Look for reports from the IMU
  if (myIMU.dataAvailable() == true)
  {
    measurements++;

    Serial.print((float)measurements / ((millis() - startTime) / 1000.0), 2);
    Serial.print(F("Hz"));

    Serial.println();
  }
}
  • Sample time of 10 ms, delay of 11 ms in main loop --> measurements will stop after a few updates
#include "SparkFun_BNO080_Arduino_Library.h"
BNO080 myIMU;

//These pins can be any GPIO
byte imuCSPin = 10;
byte imuWAKPin = 14;
byte imuINTPin = 16;
byte imuRSTPin = 15;

unsigned long startTime; //Used for calc'ing Hz
long measurements = 0;   //Used for calc'ing Hz

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println("BNO080 SPI Read Example");
  
  if(myIMU.beginSPI(imuCSPin, imuWAKPin, imuINTPin, imuRSTPin) == false)
  {
    Serial.println("BNO080 over SPI not detected. Are you sure you have all 6 connections? Freezing...");
    while(1);
  }

  myIMU.enableRotationVector(10); //Send data update every 10ms
  
  startTime = millis();
}

void loop()
{
  Serial.println("Doing other things");
  delay(9); //You can do many other things. We spend most of our time printing and delaying.
  
  //Look for reports from the IMU
  if (myIMU.dataAvailable() == true)
  {
    measurements++;

    Serial.print((float)measurements / ((millis() - startTime) / 1000.0), 2);
    Serial.print(F("Hz"));

    Serial.println();
  }
}

Expected behavior

Measurements over SPI should still be available

Actual behavior

Can not read any data from sensor

@PaulZC
Copy link
Collaborator

PaulZC commented Apr 27, 2020

Hi @DaudiGabriel ,
Just an update to let you know that we are investigating this issue.
I can replicate your issue using a SparkFun RedBoard (ATmega328P) and the following code:

#include <SPI.h>

#include "SparkFun_BNO080_Arduino_Library.h"
BNO080 myIMU;

//These pins can be any GPIO
byte imuCSPin = 10;
byte imuWAKPin = 9;
byte imuINTPin = 8;
byte imuRSTPin = 7;

unsigned long startTime; //Used for calc'ing Hz
long measurements = 0; //Used for calc'ing Hz

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println("BNO080 SPI Read Example");

  myIMU.enableDebugging(Serial); //Pipe debug messages to Serial port
  
  if(myIMU.beginSPI(imuCSPin, imuWAKPin, imuINTPin, imuRSTPin) == false)
  {
    Serial.println("BNO080 over SPI not detected. Are you sure you have all 6 connections? Freezing...");
    while(1);
  }

  //You can also call begin with SPI clock speed and SPI port hardware
  //myIMU.beginSPI(imuCSPin, imuWAKPin, imuINTPin, imuRSTPin, 1000000);
  //myIMU.beginSPI(imuCSPin, imuWAKPin, imuINTPin, imuRSTPin, 1000000, SPI1);

  //The IMU is now connected over SPI
  //Please see the other examples for library functions that you can call

  myIMU.enableRotationVector(10); //Send data update every 10ms

  Serial.println(F("Rotation vector enabled"));
  Serial.println(F("Output in form i, j, k, real, accuracy"));

  startTime = millis();
}

void loop()
{
  Serial.println("Doing other things");
  delay(6); //You can do many other things. We spend most of our time printing and delaying.
  
  //Look for reports from the IMU
  if (myIMU.dataAvailable() == true)
  {
    float quatI = myIMU.getQuatI();
    float quatJ = myIMU.getQuatJ();
    float quatK = myIMU.getQuatK();
    float quatReal = myIMU.getQuatReal();
    float quatRadianAccuracy = myIMU.getQuatRadianAccuracy();
    measurements++;

    Serial.print(quatI, 2);
    Serial.print(F(","));
    Serial.print(quatJ, 2);
    Serial.print(F(","));
    Serial.print(quatK, 2);
    Serial.print(F(","));
    Serial.print(quatReal, 2);
    Serial.print(F(","));
    Serial.print(quatRadianAccuracy, 2);
    Serial.print(F(","));
    Serial.print((float)measurements / ((millis() - startTime) / 1000.0), 2);
    Serial.print(F("Hz"));

    Serial.println();
  }
  
}

If I decrease the delay inside the loop to 5ms, the code works as expected. With the delay set to 6ms, the updates freeze after 1 or 2 seconds.
I will keep investigating!
Best wishes,
Paul

@PaulZC
Copy link
Collaborator

PaulZC commented Apr 27, 2020

I’m starting to understand this. If we set the enableRotationVector interval to 40ms or more, the BNO080 does not seem to care if we take more than 40ms to acknowledge the interrupt and read the data. If we set the interval to less than that, then it seems we MUST respond to the INT within one interval otherwise the BNO080 freezes. More investigation tomorrow...

@FidencioYzaguirreIII
Copy link

The datasheet for the BNO080, in section 1.3.4.2, mentions that it may be necessary to wake the chip when communicating with it using SPI.

https://cdn.sparkfun.com/assets/1/3/4/5/9/BNO080_Datasheet_v1.3.pdf

I suspect that during the case that the loop is slower then the update rate that the chip puts itself to sleep. I have yet to discover a way to flat out disable this sleep method from the very beginning.

I do have some code though that I believe should wake the chip

For the .h file
void wake(); // Wake sensor up

For the .cpp file

void BNO080::wake() {

    digitalWrite(_wake, LOW);   // Begin  Wake operation
    
    if (_i2cPort == NULL) {
        bool chipSelect = false;

        for (int counter = 0; counter < 300; counter++)
        {
            if (digitalRead(_int) == LOW) {
                digitalWrite(_cs, LOW);
                chipSelect = true;
            }

            if (chipSelect && (digitalRead(_int) == HIGH)) {
                break;
            }
                
            //if (_printDebug == true)
            //    _debugPort->println(F("SPI Wait"));
        }

        if (_printDebug == true && !chipSelect)
            _debugPort->println(F("SPI INT timeout on wake"));
    }
    digitalWrite(_cs, HIGH);
	digitalWrite(_wake, HIGH); 
}

I attempted to use implement the above code with a smart waker system in my Arduino Sketch. However I have seen limited success. There is either an issue with the code above or my smart waker.

Also note to the original poster. I'm the Factorem guy who reported a similar issue in the Sparkfun forums. I thought I was done with the issue back then but looks like I have ran into it again. Just happened to be doing some searching on the web when I ran into your post on the pjrc forums. Noticed your post linked back to my original post on the issue and I felt compelled to give any assistance I could.

@FidencioYzaguirreIII
Copy link

I spent today testing and can't seem to wake the chip back up. There is probably an issue with the wake code I provided. Will attempt to look into this again tomorrow.

@PaulZC
Copy link
Collaborator

PaulZC commented Apr 28, 2020

Hi @FidencioYzaguirreIII ,
Thank you for your comments - they are very useful.
In the following plot: the purple trace is the SPI CS; the yellow trace is the INT signal. At the center of the trace, the BNO080 pulls INT low briefly but then it goes high again - returning to a voltage which is not quite as high as normal. The high state will cause dataAvailable to return false.
My assumption was that a buffer was filling up, causing the BNO080 to go into some kind of error state. But sleep is a good explanation too. Except I cannot explain why the chip would go to sleep so soon after an SPI transfer?
12

@FidencioYzaguirreIII
Copy link

I've attempted contacting CEVA, they now own Hillcrest Labs, to see if there is a way to disable the sleep function. If I get a response I will be sure to post about it. Also thank you for the oscilloscope data.

@PaulZC
Copy link
Collaborator

PaulZC commented Apr 29, 2020

Thank you @FidencioYzaguirreIII & @DaudiGabriel ,
We have contacted Hillcrest Labs too. I will come back to you if they are able to offer any more advice.
At the moment, our advice has to be: if you set the the Rotation Vector Report Interval to 10ms, you need to make sure that you are able to read it at that rate. Delaying the read on every second report seems to be acceptable, but delaying the read on every report does cause the SPI interface to lock up. We don't believe the BNO080 is going to sleep, an internal buffer filling up seems more likely.
Best wishes,
Paul

@PaulZC PaulZC added the in progress This is being investigated. No solution as yet. label Apr 29, 2020
@FidencioYzaguirreIII
Copy link

FidencioYzaguirreIII commented Apr 29, 2020

Found out the datasheet I was looking at was out of date.

Current Version
https://www.ceva-dsp.com/wp-content/uploads/2019/10/BNO080_085-Datasheet.pdf

Turns out that there is a watchdog timer on the BNO080 that resets the sensor.

The BNO085 on the other hand will timeout and retry the operation. (Hint to Sparkfun make a BNO085 module)
The BNO085 is suppose to be backwards compatible with the BNO080. The changes are for new software libraries.

@DaudiGabriel
Copy link
Author

Thanks all for the effort so far. At least I know now that I was not to stupid to connect the sensor the right way and that it is a sensor problem!

I am curious whether this problem also occurs when using I2C with the interrupt pin, but unfortunately I have no time to test this right now...

@FidencioYzaguirreIII
Copy link

@DaudiGabriel I believe the issue will not occur on I2C from what I gather from the datasheet. Only issue will be dealing with the a speed bottleneck since SPI is faster then I2C.

@PaulZC
Copy link
Collaborator

PaulZC commented Apr 30, 2020

We are now in contact with CEVA about this. More updates to follow soon!

@PaulZC
Copy link
Collaborator

PaulZC commented May 2, 2020

We now understand more about what is happening to the chip. Being slow to read the SPI data does appear to be filling an internal buffer and causes the chip to perform a reset (“Initialize (unsolicited)”).
At the moment, our advice is still: if you set the the Rotation Vector Report Interval to 10ms, you need to make sure that you are able to read it at that rate.

PaulZC added a commit that referenced this issue May 2, 2020
@PaulZC
Copy link
Collaborator

PaulZC commented May 11, 2020

Hi @DaudiGabriel & @FidencioYzaguirreIII ,
CEVA have come back with more information about this issue. It is normal behavior for the BNO080 and is documented in section 1.2.4.1 of the datasheet:
image

printPacket reveals this:

Header: 17 00 03 10 Body: FB 2B FF FF FF 05 10 01 00 7E 03 B5 04 48 DC C8 34 81 10 Length:23 Channel:Sensor-report
Header: 17 00 03 11 Body: FB 15 00 00 00 05 11 01 00 7F 03 B5 04 47 DC C7 34 83 10 Length:23 Channel:Sensor-report
Header: 17 00 03 12 Body: FB 17 00 00 00 05 12 01 00 7F 03 B5 04 48 DC C7 34 83 10 Length:23 Channel:Sensor-report
Header: 17 00 03 13 Body: FB D0 FF FF FF 05 13 01 00 7F 03 B6 04 47 DC C7 34 84 10 Length:23 Channel:Sensor-report
Header: 17 00 03 14 Body: FB 80 FF FF FF 05 14 01 00 80 03 B6 04 47 DC C7 34 86 10 Length:23 Channel:Sensor-report
Header: 17 00 03 15 Body: FB 7C FF FF FF 05 15 01 00 80 03 B6 04 48 DC C7 34 87 10 Length:23 Channel:Sensor-report
Header: 14 01 00 00 Body: 00 01 04 00 00 00 00 80 06 31 2E 30 2E 30 00 02 Length:276 Channel:Command
Header: 14 00 02 00 Body: F1 00 84 00 00 00 01 00 00 00 00 00 00 00 00 00 Length:20 Channel:Control
Header: 05 00 01 00 Body: 01 Length:5 Channel:Executable

The penultimate Control Channel packet (length 20 (4 + 16)) is a command response (0xF1) for command 0x84 which is “Initialize (unsolicited)”.
The ultimate Executable Channel packet (length 5 (4 + 1)) is a “reset complete” (0x01).

This issue is now resolved - but I am going to leave it open and mark it as sticky to help future users with the same issue.
Thank you again for your help on this.
Best wishes,
Paul

@PaulZC PaulZC added sticky Issue is closed - but left open for information only and removed in progress This is being investigated. No solution as yet. labels May 11, 2020
@sparkfun sparkfun locked as resolved and limited conversation to collaborators May 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
sticky Issue is closed - but left open for information only
Projects
None yet
Development

No branches or pull requests

3 participants