sparkfun / SparkFun_BNO08x_Arduino_Library

An Arduino Library for the BNO08x IMU combination triple axis accelerometer/gyro/magnetometer packaged with an ARM Cortex M0+ running powerful algorithms.
Other
14 stars 7 forks source link

MCU keeps resetting the sensor #2

Closed tomy983 closed 9 months ago

tomy983 commented 1 year ago

Subject of the issue

The MCU keeps resetting the sensor if enabling multiple reports

Your workbench

Steps to reproduce

Configure for SPI, enable multiple reports.

Expected behavior

Reports enables

Actual behavior

MCU keep resetting BNO086

Removing the resetCheck from enableReport() here fixes the issue. Increasing the counter in this line unfortunately it is not enough.

lewispg228 commented 1 year ago

Hi @tomy983, Thank you for bringing this to our attention.

I was able to replicate this issue with a ESP32-WROOM-32E (The SparkFun IoT Redboard). I found a solution by adding in a 100ms delay at the end of the enableReports() function within the sketch. Like so:


void setReports(void) {
  Serial.println("Setting desired reports");
  if (myIMU.enableRotationVector() == true) {
    Serial.println(F("Rotation vector enabled"));
    Serial.println(F("Output in form i, j, k, real, accuracy"));
  } else {
    Serial.println("Could not enable rotation vector");
  }
  delay(100); // This delay allows enough time for the BNO086 to accept the new configuration and clear its reset status
}

I believe this slight delay is allowing the BNO086 to accept the new configuration and clear its reset status. FWW, I tried bringing this delay down a few times, and it seems that when it gets at or below 40ms, then the repetitive resetting issue comes back.

With only this addition of the delay of 100ms, I was able to leave the rest of the library alone.

And so (at least with my setup using the ESP32-WROOM-32E) I'm not sure that the hal_wait_for_int() inside enableReports at line 1172 is causing the issue.

I'm curious to know how this was solving the issue for you. Either way, would you be willing to try adding in this 100ms delay (and keeping the hal_wait_for_int() ) and see how it goes for you?

Let us know and thanks, Pete

tomy983 commented 1 year ago

Hi Pete, Adding the delay as you said fixed the issue. It looks like that no matter what I do, the first call to getSensorEvent() in the loop (in the setup does not) causes the sensor to reset. Which is actually desirable, since also the first call to enable the accelerometer report during setup fails. I've tried different ways, adding delay, waiting for interrupt, commanding wake, calling setReports() only in setup and only after getSensorEvent(), but for me apparently the way is only let the first setReports()partially fail in setup and recall it (needed anyway because the reset) in the loop(). I hope I made myself clear..

I am playing with this sensor this days, so if you need something tested or else, let me know. My ultimate goal is to have a reliable sensor reading and publish using micro-ROS at 100Hz an imu_msg and a mag_msg...

On the other hand... If I could ask... (maybe you have a better place where to ask), I have two boards practically identical, esp32-s3 and BNO086 on board and not much else, and on both I have the following issues:

#include <Arduino.h>
#include <SparkFun_BNO08x_Arduino_Library.h>

#define SPI
// #define I2C
#define I2C_FREQ 100000

BNO08x myIMU;

#ifdef SPI
SPIClass *vspi = NULL;
#define VSPI FSPI
#endif

#define VSPI_MISO_SDA 1
#define VSPI_SCLK_SCL 13
#define VSPI_MOSI_I2C_ADD 14
#define BNO08X_CS 11
#define BNO08X_INT 2
#define BNO08X_RESET 12
#define BNO08X_PS0 42
#define BNO08X_PS1 41

// internal copies of the IMU data
float ax, ay, az, gx, gy, gz, qx, qy, qz, qw, mx, my, mz;
byte linAccuracy = 0;
byte gyroAccuracy = 0;
byte magAccuracy = 0;
float quatRadianAccuracy = 0;
byte quatAccuracy = 0;

int bno_reset_count = 0;

unsigned long previousMillis = 0;
const long printInterval = 500;

void error_loop()
{
    while (1)
        ;
}

void printResetReasonName()
{
    const char *reasons[] = {
        "Not Applicable",
        "Power On Reset",
        "Internal System Reset",
        "Watchdog Timeout",
        "External Reset",
        "Other"};
    Serial.println("**********BNO08x reset**********");
    Serial.print("Reset n.");
    Serial.print(bno_reset_count);
    Serial.print(" with reason: ");
    Serial.println(reasons[myIMU.getResetReason()]);
    bno_reset_count++;
}

void setReports()
{
    // delay(500); // Give some time to recover after a reset // DOES NOT MAKE I BETTER
    Serial.println("Setting desired reports");
    if (myIMU.enableAccelerometer(18) == true)
        Serial.println("Accelerometer enabled");
    else
        Serial.println("Could not enable Accelerometer");
    // delay(100); NOT NEEDED // This delay allows enough time for the BNO086 to accept the new configuration and clear its reset status
    if (myIMU.enableGyro(18) == true)
        Serial.println("Gyro enabled");
    else
        Serial.println("Could not enable Gyro");
    // delay(100); NOT NEEDED // This delay allows enough time for the BNO086 to accept the new configuration and clear its reset status
    if (myIMU.enableRotationVector(9) == true)
        Serial.println("RV enabled");
    else
        Serial.println("Could not enable RV");
    //  delay(100); NOT NEEDED // This delay allows enough time for the BNO086 to accept the new configuration and clear its reset status
    if (myIMU.enableMagnetometer(25) == true)
        Serial.println("Magnetometer enabled");
    else
        Serial.println("Could not enable Magnetometer");
    Serial.println("Done setting desired reports");
    delay(100); // NEEDED
}

void setup()
{
    delay(2000); // To not miss first debug messages
    Serial.begin(115200);
    delay(200); // Stabilize serial
    Serial.print("Setup BNO with ");
    /*PS1 PS0 MODE
      0   0   I2C
      0   1   UART-RVC
      1   0   UART
      1   1   SPI*/
    pinMode(BNO08X_PS1, OUTPUT);
    pinMode(BNO08X_PS0, OUTPUT);
#ifdef SPI
    digitalWrite(BNO08X_PS1, HIGH);
    digitalWrite(BNO08X_PS0, HIGH);
    Serial.println("SPI interface.");
#endif
#ifdef I2C
    digitalWrite(BNO08X_PS1, LOW);
    digitalWrite(BNO08X_PS0, LOW);
    // with i2c define address 4B or 4A with mosi pin/ pull down present
    pinMode(VSPI_MOSI_I2C_ADD, OUTPUT);
    digitalWrite(VSPI_MOSI_I2C_ADD, HIGH); // 0x4B
    Serial.println("I2C interface.");
#endif

    // BNO086 hardware reset after settings
    // ********* Sparkfun lib already perform reset at init

    // Serial.println("BNO086 reset.");
    // pinMode(BNO08X_RESET, OUTPUT);
    // digitalWrite(BNO08X_RESET, HIGH);
    // delay(10);
    // digitalWrite(BNO08X_RESET, LOW);
    // delay(10);
    // digitalWrite(BNO08X_RESET, HIGH);

#ifdef I2C
    Wire.setPins(VSPI_MISO_SDA, VSPI_SCLK_SCL);
    // Try to initialize!
    Wire.begin();
    Wire.setClock(I2C_FREQ);
    delay(100);
    Serial.print("i2c ferq:");
    Serial.println(Wire.getClock());
    if (!myIMU.begin(0x4B, Wire, BNO08X_INT, BNO08X_RESET))
    {
        Serial.println("Failed to find BNO08x chip");
        error_loop();
    }
#endif
#ifdef SPI
    vspi = new SPIClass(VSPI);
    vspi->begin(VSPI_SCLK_SCL, VSPI_MISO_SDA, VSPI_MOSI_I2C_ADD, BNO08X_CS); // SCLK, MISO, MOSI, SS
    pinMode(vspi->pinSS(), OUTPUT);                                          // VSPI SS
    if (myIMU.beginSPI(BNO08X_CS, BNO08X_INT, BNO08X_RESET, 30000000, *vspi) == false)
    {
        Serial.println("Failed to find BNO08x chip");
        error_loop();
    }
#endif

    Serial.println("BNO08x Found!");
    for (int n = 0; n < myIMU.prodIds.numEntries; n++)
    {
        Serial.print("Part ");
        Serial.print(myIMU.prodIds.entry[n].swPartNumber);
        Serial.print(": Version :");
        Serial.print(myIMU.prodIds.entry[n].swVersionMajor);
        Serial.print(".");
        Serial.print(myIMU.prodIds.entry[n].swVersionMinor);
        Serial.print(".");
        Serial.print(myIMU.prodIds.entry[n].swVersionPatch);
        Serial.print(" Build ");
        Serial.println(myIMU.prodIds.entry[n].swBuildNumber);
    }

    // FIRST CALL OF myIMU.getSensorEvent() IN LOOP CAUSES A BNO086 RESET.
    // CALLING IT IN SETUP DOES NOT MAKE IT BETTER.
    while (!digitalRead(BNO08X_INT)) // WAIT BNO086 TO BE READY
        ;
    if (myIMU.wasReset()) // IT WAS RESET DURING init...
        printResetReasonName();
    setReports(); // FIRST CALL FAILS
}

void loop()
{
    if (myIMU.getSensorEvent() == true) // FIRST CALL RESETS BNO086
    {
        uint8_t eventId = myIMU.getSensorEventID();
        switch (eventId)
        {
        case SENSOR_REPORTID_ACCELEROMETER:
            ax = myIMU.getAccelX();
            ay = myIMU.getAccelY();
            az = myIMU.getAccelZ();
            linAccuracy = myIMU.getAccelAccuracy();
            break;
        case SENSOR_REPORTID_GYROSCOPE_CALIBRATED:
            gx = myIMU.getGyroX();
            gy = myIMU.getGyroY();
            gz = myIMU.getGyroZ();
            gyroAccuracy = myIMU.getGyroAccuracy();
            break;
        case SENSOR_REPORTID_MAGNETIC_FIELD:
            mx = myIMU.getMagX();
            my = myIMU.getMagY();
            mz = myIMU.getMagZ();
            magAccuracy = myIMU.getMagAccuracy();
            break;
        case SENSOR_REPORTID_ROTATION_VECTOR:
            qw = myIMU.getQuatReal();
            qx = myIMU.getQuatI();
            qy = myIMU.getQuatJ();
            qz = myIMU.getQuatK();
            quatAccuracy = myIMU.getQuatAccuracy();
            quatRadianAccuracy = myIMU.getQuatRadianAccuracy();
            break;
        default:
            Serial.print("************************** Other Event: ");
            Serial.println(eventId);
            break;
        }
    }
    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= printInterval)
    {
        previousMillis = currentMillis;
        char buf[200];
        sprintf(buf, "ax: %f, ay: %f, az: %f \ngx: %f, gy: %f, gz: %f \nqx: %f, qy: %f, qz: %f, qw: %f \nmx: %f, my: %f, mz: %f", ax, ay, az, gx, gy, gz, qx, qy, qz, qw, mx, my, mz);
        Serial.println(buf);
    }
    if (myIMU.wasReset())
    {
        printResetReasonName();
        setReports();
    }
}
lewispg228 commented 10 months ago

Hi @tomy983 , Glad to hear the fix worked for you. We just verified this on all three SPI examples, and pushed a new release with this delay included at the end of setReports.

Regarding the other two issues you mentioned in your last comment. We will dig into those asap. We should be able to test this out early next week with our hardware (ESP32 IoT Redboard and the breakout).

Note, for best reliability, we recommend wiring up reset and INT. Our initial guess is that this could help with reliability at higher I2C clock speeds.

If you are still experiencing issues with these two other issues, would you mind filing them as separate issues on this github repo?

Thanks and we will report back soon with our testing results early next week.

lewispg228 commented 9 months ago

Hi @tomy983 , As the initial issue described in this issue has been resolved with the additional delay, we are going to close out this issue.

In terms of the I2S Speed. If any one comes across this conversation and is running into the same thing, we would recommend trying 350Khz, as that seems to work reliably with our setup (ESP32 IoT Redboard and QWIIC/INT/RST). Also note, there has been an issue using setClock(), and so the work around currently is to include it in the begin function like so: Wire.begin(SDA, SCL, 350000);

And we have not been able to replicate the Gyro axis swapping issue on our setup, so please let us know if you are still experiencing that and/or have found a solution.

Thanks, Pete