BNO08x on a QT Py ESP32 Pico not working

Breakout boards, sensors, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
User avatar
adafruit2
 
Posts: 22148
Joined: Fri Mar 11, 2005 7:36 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by adafruit2 »

gary, wanna try that code kindly donated by gamma?

User avatar
argonblue
 
Posts: 93
Joined: Wed Apr 25, 2012 12:18 am

Re: BNO08x on a QT Py ESP32 Pico not working

Post by argonblue »

Be sure to add the extra pullup resistor to SDA (about 2K to 3K ohms).
Interesting. I think that breakout board comes with pullup resistors installed? Do you still need the additional pullup if you lower the I2C clock speed to 100kHz?

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by gammaburst »

Hi argonblue,

The timing problem is independent of I2C clock frequency, so slowing the clock won't help.

Here's a simple test to see if your BNO055/BNO085 project has the I2C timing problem: Connect a short wire to SDA and grab its bare end with two fingers. If your project stutters/crashes, it has the problem.

Details: The extra pullup resistor is a tricky fix that helps overcome an SDA-to-SCL setup-time violation caused by the BNO055/BNO085 chip during clock-stretching. The symptom is occasional or frequent I2C corruption. By adding an extra resistor (roughly 2K or 3K ohms) that pulls-up SDA more strongly than SCL, SDA now rises more quickly than SCL, thereby providing additional nanoseconds of setup time. That doesn't eliminate the timing violation, but it reduces the violation sufficiently to avoid malfunction.


Hi adafruit2 and other folks,

This is my understanding/opinion:

Lots of folks call that .inf file a "driver", but it's merely a text file that helps Windows identify your new gadget as a USB Communications Device Class (CDC) gadget. Windows already has the required CDC driver (executable code).

Basically, you use Device Manager to discover your new CDC gadget's PID and VID identifier strings, then carefully copy the strings into a generic CDC .inf file, then optionally modify the product name strings, and then use Device Manager with the .inf file to "update" your gadget. Beware, the modified .inf file has no signature credentials, so you need to click through a red warning message. After that, you'll find a copy of your .inf file in \Windows\inf.

If you want to undo your .inf installation, use Device Manager to "uninstall" your gadget, and tell it to "delete the driver software". The .inf copy will disappear from \Windows\inf.

I've done those steps several times on my Win7 with two different Adafruit ESP32 boards.


I have a Win10 machine too.

User avatar
garyrkey
 
Posts: 13
Joined: Fri Feb 07, 2014 8:14 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by garyrkey »

Thanks, gammaburst! You got me where I wanted to go.
I'm talking to the BNO08x, and it is telling everything I want to hear!

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by gammaburst »

Yay!
Have fun with your project.

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by gammaburst »

Hi adafruit2,

Regarding the problem: "Plain" ESP32 and Adafruit BNO08x library seem to not work together:

A few days ago I too saw that problem when I switched from a QT Py ESP32-S2 (Adafruit 5348) to a Feather32 HUZZAH (Adafruit 3619).

I may have fixed it. I connected an I2C analyzer and saw message problems after the attempted BNO soft reset. I edited library file "Adafruit_BNO08x.cpp" and replaced function "i2chal_open()" with the following code. The Feather32 now works fine for me.

Code: Select all

#warning Experimental BNO08x soft reset
static int i2chal_open(sh2_Hal_t *self)
{
  uint8_t softreset_pkt[] = {5, 0, 1, 0, 1};
  while (!i2c_dev->write(softreset_pkt, 5))  // send soft reset until success
    delay(30);
  delay(300);     // allow plenty of time for BNO to reboot
  return 0;
}
That inspired me to improve the soft reset code in my 28-June-2022 example sketch:

Code: Select all

#include <Wire.h>

#define I2C_PORT    2           // 1 selects first I2C port, 2 selects second I2C port
#define BNO_ADDR    0x4A        // I2C address of BNO085 (0x4A if SA0=0, 0x4B if SA0=1)
//#define pinRST    A0         // comment-out this line to soft-reset BNO with a command, uncomment this line to output a hard-reset pulse to BNO's RST pin
#define I2C_CLOCK   200000L     // I2C clock rate
#define SERIAL_BAUD 115200L     // serial port baud rate
#define SENSOR_US   10000L      // time between sensor reports, microseconds, 10000L is 100 Hz, 20000L is 50 Hz, etc.

// *******************
// **  Output data  **
// *******************

int16_t iqw, iqx, iqy, iqz;             // quaternion, integer

static void output_data()
{
  // my BNO08x orientation dot is towards left rear, rotate BNO08x quaternion to NED conventions
  float q0 = iqw+iqz;
  float q1 = iqx+iqy;
  float q2 = iqx-iqy;
  float q3 = iqw-iqz;
  float norm = 1 / sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
  q0 *= norm;
  q1 *= norm;
  q2 *= norm;
  q3 *= norm;
  Serial.print("Quaternion: ");
  Serial.print(q0, 4);  Serial.print(" ");
  Serial.print(q1, 4);  Serial.print(" ");
  Serial.print(q2, 4);  Serial.print(" ");
  Serial.print(q3, 4);  Serial.println();
}

#if I2C_PORT == 1                       // use first I2C port
  #define WIRE Wire
  #define SELECT_I2C_PINS()
#elif I2C_PORT == 2                     // use second I2C port
  #define WIRE Wire1
  #define SELECT_I2C_PINS()  WIRE.setPins(SDA1,SCL1)  // Adafruit advises this for QT Py ESP32-S2
#endif

// *******************************
// **  Request desired reports  **
// *******************************

#define QUAT_REPORT  0x05               // quaternion report, see 6.5.18
#define TIME_REPORT  0xFB               // time report, see 7.2.1

static void request_reports(void)
{
  // request quaternion reports, see 6.5.4
  static const uint8_t cmd_quat[] = {21, 0, 2, 0, 0xFD, QUAT_REPORT, 0, 0, 0, (SENSOR_US>>0)&255, (SENSOR_US>>8)&255, (SENSOR_US>>16)&255, (SENSOR_US>>24)&255, 0, 0, 0, 0, 0, 0, 0, 0};
  WIRE.beginTransmission(BNO_ADDR);  WIRE.write(cmd_quat, sizeof(cmd_quat));  WIRE.endTransmission();
  // at 10ms rate, BNO08x outputs most reports in one burst, Gyro-Quat-Lac-Mag, however Acc is asynchronous and a few percent faster. Situation may vary with SENSOR_US and maximum sensor rates.
}

// ******************************************
// **  Check for and parse sensor reports  **
// ******************************************

static void ensure_read_available(int16_t length)  // ensure a read byte is available, if necessary reread and discard 4-byte SHTP header, then read as much length as possible
{
  if (!WIRE.available())
    WIRE.requestFrom(BNO_ADDR,4+length), WIRE.read(), WIRE.read(), WIRE.read(), WIRE.read();
}

static void check_report()
{
  int16_t length;
  uint8_t channel __attribute__((unused));
  uint8_t seqnum  __attribute__((unused));

  WIRE.requestFrom(BNO_ADDR,4+1);       // read 4-byte SHTP header and first byte of cargo
  length  = WIRE.read();                // length LSB
  length |= (WIRE.read() & 0x7F) << 8;  // length MSB (ignore continuation flag)
  channel = WIRE.read();                // channel number
  seqnum  = WIRE.read();                // sequence number (ignore)
  length -= 4;                          // done reading SHTP Header
  if (length <= 0 || length > 1000)     // if null/bad/degenerate SHTP header
    return;

  while (length)                        // while more reports in cargo
  {
    uint8_t buf[20];                    // report buffer, big enough for longest interesting report (uninteresting reports will be ignored)
    uint16_t n = 0;                     // index into report buffer

    ensure_read_available(length);
    buf[n++] = WIRE.read();             // first byte of report
    length--;

    // known reports
    if (channel==3 && buf[0]==TIME_REPORT && length >= 5-1)
    {
      for (uint8_t n=1; n<5; n++)       // read remainder of report
      {
        ensure_read_available(length);
        buf[n] = WIRE.read();
        length--;
      }
      continue;
    }
    if (channel==3 && buf[0]==QUAT_REPORT && length >= 14-1)
    {
      for (uint8_t n=1; n<14; n++)      // read remainder of report
      {
        ensure_read_available(length);
        buf[n] = WIRE.read();
        length--;
      }
      iqw = *(int16_t*)&buf[10];
      iqx = *(int16_t*)&buf[4];
      iqy = *(int16_t*)&buf[6];
      iqz = *(int16_t*)&buf[8];
      output_data();
      continue;
    }

    // unknown reports
    while (length)                      // discard remainder of cargo (shouldn't happen very often)
    {
      ensure_read_available(length);
      WIRE.read();
      length--;
    }
    continue;
  }
  return;
}

// **********************
// **  Setup and Loop  **
// **********************

void setup()
{
  Serial.begin(SERIAL_BAUD);            // initialize serial
  Serial.println("\nRunning...");

  #ifdef pinRST                         // hard reset BNO by pulsing its RST pin
    //hard_reset();
    pinMode(pinRST,OUTPUT);
    digitalWrite(pinRST,LOW);
    delay(2);                           // because 1 sometimes gets truncated
    digitalWrite(pinRST,HIGH);
    delay(300);                         // let BNO reboot, about 150 works marginally, so let's double it
  #endif

  // pinMode(A1,OUTPUT);  digitalWrite(A1,HIGH);  delayMicroseconds(10);  digitalWrite(A1,LOW);  delayMicroseconds(10);  // scope trigger for debugging

  SELECT_I2C_PINS();
  WIRE.begin();                         // initialize I2C
  WIRE.setClock(I2C_CLOCK);

  // clear I2C bus, just in case
  WIRE.beginTransmission(BNO_ADDR);
  WIRE.endTransmission();

  #ifndef pinRST                        // if no hard reset, soft reset BNO by sending SHTP "reset" command, see 1.3.1
    do
    {
      static const uint8_t cmd_reset[] = {5, 0, 1, 0, 1};
      delay(30);
      WIRE.beginTransmission(BNO_ADDR);
      WIRE.write(cmd_reset, sizeof(cmd_reset));
    }  while (WIRE.endTransmission());  // if failed to send reset command, try again
    delay(300);                         // let BNO reboot, about 150 works marginally, so let's double it
  #endif

  request_reports();                    // request desired reports

  do                                    // wait until BNO outputs non-zero quaternions
    check_report();
  while (!iqw && !iqx && !iqy && !iqz);
}

void loop()
{
  check_report();                       // check for reports
}
My 26-June-2022 example sketch contains this line of code:
bno08x.enableReport(SH2_ROTATION_VECTOR,100);
The value needs to be microseconds, so 100 is bogus. It should be 10000 (for 100 Hz messages) or 100000 (for 10 Hz messages). Sorry if I messed up anyone with that!

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by gammaburst »

Hi adafruit2,

Good news! After a long UPS shipping delay, I received some QT Py ESP32 Pico modules (Adafruit 5395).
I tested one with my soft-reset library modification (previous message).
The QT Py ESP32 Pico now seems to work fine with BNO085.
Can you confirm this adafruit2?

I had trouble following the instruction for installing the Windows driver for the Pico.
These two pages link to driver CH341SER.ZIP:
https://www.adafruit.com/product/5395
https://learn.adafruit.com/adafruit-qt- ... -ide-setup
But that didn't work - my Device Manager showed "USB Single Serial" with yellow exclamation mark.
I noticed the CH9102F on my Pico requires USB\VID_1A86&PID_55D4 which is in this driver:
http://www.wch-ic.com/downloads/CH343SER_ZIP.html
I installed CH343SER_ZIP using Adafuit's above instructions (unzip, run SETUP.EXE).
The Pico serial port now detects as "USB-Enhanced-SERIAL CH9102" and works fine.

QT Py. Oh now I get it. Cutie pie.

User avatar
adafruit2
 
Posts: 22148
Joined: Fri Mar 11, 2005 7:36 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by adafruit2 »

:) can you submit a PR for that fix to github? that's the best way for us to test it - and if it works, merge it into the library!

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by adafruit_support_carter »

@gammaburst I tested but could not recreate your success with getting this working on a QT Py ESP32 Pico:
https://github.com/adafruit/Adafruit_BN ... 1182127608

The latest ESP32 BSP turns on some compiler flags that cause previous warns to now be errors:
https://github.com/adafruit/Adafruit_BNO08x/issues/19
I did a quick patch for all those locally to get things to compile. So I'm not 100% same as current library code. I doubt that has anything to do with this.

What ESP32 BSP version were you using when you ran your test?

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by gammaburst »

Hi adafruit_support_carter,

Let's see if I can provide enough info to help you reproduce what I'm doing...

QT Py ESP32 Pico (Adafruit 5395) connected to BNO08x (Adafruit 4754).
Notice extra SDA pullup resistor
:
QT Py ESP32 Pico connected to BNO08x with extra SDA pullup resistor
QT Py ESP32 Pico connected to BNO08x with extra SDA pullup resistor
IMG_2646a.jpg (161.93 KiB) Viewed 432 times
My build environment:
- Win7 64-bit running on i7 processor
- Arduino IDE 1.8.5
- ESP32 support - not sure how to tell, Library Manager shows "ESP32 Built-In by Gochkov and Grokhtkov version 2.0.0"
- Library Adafruit_bno08x version 1.2.1, modified with my aforementioned soft reset patch.

My sketch:

Code: Select all

#include <Adafruit_BNO08x.h>

#define I2C_PORT  2                     // 1 selects first I2C port, 2 selects second I2C port

Adafruit_BNO08x bno08x(-1);

void setup(void)
{
  Serial.begin(115200);

  #if I2C_PORT == 1                     // use first I2C port
    bno08x.begin_I2C();
  #elif I2C_PORT == 2                   // use second I2C port
    Wire1.setPins(SDA1, SCL1);          // Adafruit 5348 QT Py ESP32-S2: Qwiic connector uses second I2C port
    bno08x.begin_I2C(BNO08x_I2CADDR_DEFAULT, &Wire1);
  #endif
  Wire.setClock(200000L);               // I2C speed, 400 kHz is a little fast for default pullups

  bno08x.enableReport(SH2_ROTATION_VECTOR, 10000);  // report rate, microseconds
}

void loop()
{
  sh2_SensorValue_t sensorValue;
  if (!bno08x.getSensorEvent(&sensorValue))
    return;

  switch (sensorValue.sensorId)
  {
    case SH2_ROTATION_VECTOR:
      Serial.print("Quaternion: ");
      Serial.print(sensorValue.un.rotationVector.real,4);  Serial.print(" ");
      Serial.print(sensorValue.un.rotationVector.i,4);     Serial.print(" ");
      Serial.print(sensorValue.un.rotationVector.j,4);     Serial.print(" ");
      Serial.print(sensorValue.un.rotationVector.k,4);     Serial.println();
      break;
  }
}
I've selected board "Adafruit QT Py ESP32". I click Upload button, wait a while (I don't see your compile errors), see "Hard resetting via RTS pin", then I press Ctrl+Shift+M to see nice Quaternion data scrolling in serial monitor window (set to 115200 baud).

Remember to install the extra SDA pullup resistor, or else you're asking for trouble.

User avatar
gammaburst
 
Posts: 1015
Joined: Thu Dec 31, 2015 12:06 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by gammaburst »

Hi adafruit_support_carter,

Sounds like you had some trouble building the project.

I'm not sure what is "latest ESP32 BSP".

I just noticed that my Boards Manager includes: "esp32 by Expressif Systems version 2.0.3 INSTALLED". That sounds vaguely familiar. I may have recently "updated" it. I occasionally walk through all my "Updatable" Board Manager and Library Manager items and "Update" them (a tedious and slow process).

I haven't encountered "I2C address not found" during my experiments with this issue.

Back on June 24, adafruit2 mentioned "esp32 is not getting correct data and its getting confused", which sounds like it's getting further than your "I2C address not found", so maybe you can examine that build environment?
viewtopic.php?f=19&t=191933#p930175

User avatar
adafruit_support_carter
 
Posts: 29168
Joined: Tue Nov 29, 2016 2:45 pm

Re: BNO08x on a QT Py ESP32 Pico not working

Post by adafruit_support_carter »

Sorry for the delay. This sort of got lost and had at least one other pull request that needed to be taken care of prior. Just revisited this and have submitted a pull request to hopefully fix:
https://github.com/adafruit/Adafruit_BNO08x/pull/21

And here's the related issue thread:
https://github.com/adafruit/Adafruit_BNO08x/issues/18

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Products from Adafruit”