BNO086 I2C Communication problem with Teensy 4.1

@PaulStoffregen

Was doing some more poking around with this chip and how its using RST and INT. Definitely don't think its as I2C issue - more of device/libary issue. As a note Sparkfun uses the CEVA library for interfacing with the device.
Did a bit more of a deep dive into the specs and the 2 libraries. Here is what I found:

1. Adafruit library uses an older version of the Hillcrest SHTP protocol geared to the BNO080 and BNO085 which they have break outs for. They do not support separate INT/RST pins in there library except for SPI implementation. Some examples seem to work, partial work or fail after a few readings.
a. more_reports example; seems to provide data for some reports but gives messages about can not read sensor periodically​
b. rotation vector example: gives a few report outputs then the sensor keeps reseting​
c. quaternion_yaw_pitch_roll example: seems to work.​
2. The Sparkfun library uses the latest released version of the SHTP protocol with the CEVA Sensor Hub driver.

3. Reading the documents referenced on the Sparkfun product page: https://www.sparkfun.com/products/22857 especially the Sensor Hub Transport Protocol seems to indicate that using the interrupt pin is mandatory, but does not appear to work with only the INT pin set with the Sparkfun library. But the example that @KurtE and I put together does work with just INT which was based on the olde version of SHTP.

From https://docs.sparkfun.com/SparkFun_...N*MTcwMTgwNTg5Ni43LjEuMTcwMTgwNzQyNy42MC4wLjA. it states
1. The H_INTN pin is the application interrupt line that indicates the BNO08X requires attention. This should be tied to a GPIO with wake capability. The interrupt is active low.
2. NRST is the reset line for the BNO08X and can be either driven by the application processor or the board reset.
which may explain why the BNO086 needs the RST pin connected.

Don't think I am going to dig any deeper unless there is an issue as @PaulStoffregen stated
EDIT:
Just as a note, from the sparkfun examples:
// For the most reliable interaction with the SHTP bus, we need
// to use hardware reset control, and to monitor the H_INT pin.
// The H_INT pin will go low when its okay to talk on the SHTP bus.
// Setup without INT/RST control (Not Recommended)
 
Last edited:
Since I am a glutton for punishment here a few boards tested where if you just hook up I2c without INT/RST connected they don't work:
Arduino GIGA R1
Arduino R4 WiFI
ESP32S2
ESP32 Micromod.

They do work if you hook up INT and RST pins. Ok I am done with this device.
 
@PaulStoffregen

Posted on the Sparkfun forum and someone referenced me to the hook up guide and there is a big note on the hardware hookup page:
As of v1.0.3, you will need to wire up the reset and interrupt pins. Using only the I2C port was not sufficient enough to get the BNO086 to work reliably with a microcontroller.

The I/O pins have also been changed for the reset and interrupt pins! Make sure to adjust your connections accordingly.
 
Was doing a little more testing of the BNO086 and thought I would post this update.

When running a couple of the examples at 400khz I would get a sensor reset error and then you would see no output after the setReports. Reading a Sparkfun issue in their repo found this in: https://github.com/sparkfun/SparkFun_BNO08x_Arduino_Library/issues/2#issuecomment-1836815134

>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);

So I changed the I2C clockspeed to 350khz in the examples I was playing with and it worked. So suggest that if it does not work for you at 400khz change the clock to 350khz.
 
I am trying to use the Adafruit's BNO085 board, their library and a Teensy 3.6.

- directly after an upload in Arduino: works in 70%, in 30% shows "I2C address not found"
- if plugged into a power supply via USB: works in 100%

However, once it initializes, it seems to work properly. So, I placed the initialization in a loop. It did not help until I added delays:
C++:
while(1) {
    delay(100);
    Wire.setSCL(33);
    Wire.setSDA(34);
    Wire.setClock(350000L);
    Wire.begin();
    delay(100);
    if(!bno08x.begin_I2C(BNO08x_I2CADDR_DEFAULT, &Wire)) {
        Serial.println("Failed to find BNO08x chip");
        Wire.end();
    } else
         break;
};
Serial.println("BNO08x found");
Sometimes I see it iterate twice.
 
Last edited:
I am trying to use the Adafruit's BNO085 board, their library and a Teensy 3.6.

- directly after an upload in Arduino: works in 70%, in 30% shows "I2C address not found"
- if plugged into a power supply via USB: works in 100%

However, once it initializes, it seems to work properly. So, I placed the initialization in a loop. It did not help until I added delays:
Unfortunately, I do not have Adafruint BNO055 to test with the Adafruit library but just a couple of things of note.

I have never had much luck with the Adafruit Library using Sparkfun BNO080 or their BNO086 breakout boards. I typically use the Sparkfun library for the BNO sensors. With their library you have to use the reset and interrupt pins in addition to the SDA/SCL pins. According to the info provided using these pins provide reliable communication with the BNO sensors.

With that said I hooked up a BNO086 but was having issues with initialization using even the Sparkfun library with any of the teensy's (3.6 or 4.1). I did track the issue down though. If you delete these lines in the enableReport function in the Sparkfun_BNO08x_Arduino_library it works reliably:

Code:
/*
  if(_int_pin != -1) {
    if (!hal_wait_for_int()) {
      return 0;
      }
  }
  */

You might want to give it a try.

Edit: with that said I changed to function to read:

Code:
/**
 * @brief Enable the given report type
 *
 * @param sensorId The report ID to enable
 * @param interval_us The update interval for reports to be generated, in
 * microseconds
 * @param sensorSpecific config settings specific to sensor/reportID.
 * (e.g. enabling/disabling possible activities in personal activity classifier)
 * @return true: success false: failure
 */
bool BNO08x::enableReport(sh2_SensorId_t sensorId, uint32_t interval_us,
                                      uint32_t sensorSpecific) {
  static sh2_SensorConfig_t config;

  // These sensor options are disabled or not used in most cases
  config.changeSensitivityEnabled = false;
  config.wakeupEnabled = false;
  config.changeSensitivityRelative = false;
  config.alwaysOnEnabled = false;
  config.changeSensitivity = 0;
  config.batchInterval_us = 0;
  config.sensorSpecific = sensorSpecific;

  config.reportInterval_us = interval_us;
 
  #if !defined(TEENSYDUINO)
  if(_int_pin != -1) {
    if (!hal_wait_for_int()) {
      return 0;
      }
  }
  #endif
 
  int status = sh2_setSensorConfig(sensorId, &config);

  if (status != SH2_OK) {
    return false;
  }

  return true;
}
 
Last edited:
@ithinu

Ok just found a BNO085 from adafruit and hooked up to a Teensy 3.6 and used the latest Adafruit BNO08X library.

Setup was hooking up I2C via the QWIIC connector to wire using pins 18/19 and adafruit skethces worked with mods to either library or their library. Data flowing to serial monitor.

If I use pins 33/34:
Code:
  // Try to initialize!
  Wire.setSCL(33);
  Wire.setSDA(34);
  if (!bno08x.begin_I2C()) {
  //if (!bno08x.begin_UART(&Serial1)) {  // Requires a device with > 300 byte UART buffer!
  //if (!bno08x.begin_SPI(BNO08X_CS, BNO08X_INT)) {
    Serial.println("Failed to find BNO08x chip");
    while (1) { delay(10); }
  }
  Serial.println("BNO08x Found!");

Again no issues. No external power was applied.

Maybe you have a loose wire.
 
You may be right @mjs13, I assumed that 3.6 uses internal pull-up resistors on its I2C bus, just like 4.1 does. I'll add external ones and hopefully I won't need my suspicious workaround anymore.

I'll write tomorrow.
 
Would it work as a weak pull-up in 3.6? The wires have less than 10 cm.
C++:
    digitalWrite(SCL, 1);
    digitalWrite(SDA, 1);

edit: It got stranger, the above makes the workaround loop run twice each time, while
C++:
    digitalWrite(SCL, 0);
    digitalWrite(SDA, 0);
for the ~20 times I tested, initializes the IMU in the first iteration each single time.

edit2: The original code initializes the IMU also 100% first try now, no matter if cold or warm, so maybe the 0's change nothing (because of that, when I misplaced the code with 1's so that it had no effect, I concluded that it helped).
 
Last edited:
@ithinu

You don't need pullups or do anything special. Just hook it up to the Teensy 3.6:
3.3v -> 3.3v
GND -> GND
SCL -> pin 33
SDA -> pin 34

and your startup should look like this, as I mentioned before:
C++:
  // Try to initialize!
  Wire.setSCL(33);
  Wire.setSDA(34);
  if (!bno08x.begin_I2C()) {
  //if (!bno08x.begin_UART(&Serial1)) {  // Requires a device with > 300 byte UART buffer!
  //if (!bno08x.begin_SPI(BNO08X_CS, BNO08X_INT)) {
    Serial.println("Failed to find BNO08x chip");
    while (1) { delay(10); }
  }
  Serial.println("BNO08x Found!");

Thats what worked for me.
 
Back
Top