Sparkfun BNO080 - Teensy 3.6 >> 4.0

Status
Not open for further replies.
Well - not sure which library you are using or sketch on the above but something strange is definitely going on.

On another front, similar to this lib, the Teensy 4 is having problems with Garmin's lidar Lite V3 using sparkfuns' library as well. It sees the address no problem with Scanner but that distance data is fixed at some maximum distance - only returns 9953 cm.

It does seem to work on the Teensy 3.5 without a problem though.
 
Well - not sure which library you are using or sketch on the above but something strange is definitely going on.

On another front, similar to this lib, the Teensy 4 is having problems with Garmin's lidar Lite V3 using sparkfuns' library as well. It sees the address no problem with Scanner but that distance data is fixed at some maximum distance - only returns 9953 cm.

It does seem to work on the Teensy 3.5 without a problem though.

That's odd - only easy to check thing would to be sure it has good GND and power - and the pullups are healthy/good.
 
@mjs513, @defragster, @Paul...

I sort of backed off, the changes (back to Sparkfun current release to get ideas of what maybe is going on

Thoughts so far, or better yet wondering, what maybe differences in T3.x and T4 code base...

Also after Italian food out with Wine and Grapa so might not make any sense ;)

Wondering about clock stretching as the BNO080 document from Sparkfun says:
The master device generally drives the clock. However,if the slave device requires additional time to respond it can force the clock low, only releasing the line when it is prepared to deliver more data.The master device MUST support clock stretching

So first wondering what that might mean to SCL pin? So looked at how T3.x configures the SCL pin,

So for example the WireKinetis.cpp file for TwoWire::Begin has:
Code:
	reg = portConfigRegister(hardware.scl_pin[scl_pin_index]);
	mux = PORT_PCR_MUX(hardware.scl_mux[scl_pin_index]);
	*reg = mux|[COLOR="#FF0000"]PORT_PCR_ODE[/COLOR]|PORT_PCR_SRE|PORT_PCR_DSE;
So it configures the SCL pin to be Open Drain, plus SLew Rate enable, plus Drive Strength enable.

Where if we look at how SCL is defined on T4, we see things like:
Code:
		*(portControlRegister(hardware.scl_pins[newindex].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3);
		*(portConfigRegister(hardware.scl_pins[newindex].pin)) = hardware.scl_pins[newindex].mux_val;
		if (hardware.scl_pins[newindex].select_input_register) {
		 	*(hardware.scl_pins[newindex].select_input_register) =  hardware.scl_pins[newindex].select_val;		
		}
So we enable: a 22K pull up resistor. Not Open Drain... So I tried adding ODE option to this and so far that did not help. Wondering if I need to remove PU resistor define?

So probably need to experiment with some different settings.

Also in T4 manual 46.3.2.6 Pin Configuration Push-Pull 2 wire support, it says:
Push-pull 2-wire support: A push-pull 2-wire configuration is also available to the
LPI2C master that may support a partial high speed mode, if the LPI2C is the only
master and all I2C pins on the bus are at the same voltage. This will configure the
SCL pin as push-pull for every clock except the 9th clock pulse, to allow high speed
mode compatible slaves to perform clock stretching. In this mode, the SDA pin is
tristated for master-receive data bits and master-transmit ACK/NACK bits, and is
configured as push-pull at other times. To avoid the risk of contention when SDA is
Functional description
i.MX RT1060 Processor Reference Manual, Rev. 1, 12/2018
2880 NXP Semiconductors
push-pull, the pin can be configured for open-drain operation, as part of the device specific
configuration.

So I tried configuring SCL/SDA pins like:
Code:
*(portControlRegister(hardware.scl_pins[scl_pin_index_].pin)) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_SPEED(1) | IOMUXC_PAD_ODE;
Still no luck... More debugging, which may wait until morning.
 
That's odd - only easy to check thing would to be sure it has good GND and power - and the pullups are healthy/good.
Yep odd indeed. Checked ground and power, even had it running off a ext 5v source with same results. Added 4.7k pullups to 3.3v on SDA/SCL. Note - it runs on 5v but has a builtin 3.3v level shifter for SDA/SCL. At a lose here
 
Next update: I hooked up To 3.5 using QWIIC with their breakout cable - unchanged Sparkfun code. And see:
screenshot.jpg

And again some dump of the start of the LA info:
Code:
Time [s],Packet ID,Address,Data,Read/Write,ACK/NAK
3.921990632000000,0,0x96,0x05,Write,ACK
3.922077566000000,0,0x96,0x00,Write,ACK
3.922164500000000,0,0x96,0x01,Write,ACK
3.922251436000000,0,0x96,0x00,Write,ACK
3.922338368000000,0,0x96,0x01,Write,ACK
3.972910702000000,1,0x97,0x71,Read,ACK
3.973000022000000,1,0x97,0x00,Read,ACK
3.973086702000000,1,0x97,0x07,Read,ACK
3.973173634000000,1,0x97,0xFF,Read,NAK
3.973280296000000,,0x97,,Read,NAK
4.073736964000000,3,0x97,0x14,Read,ACK
4.073823892000000,3,0x97,0x01,Read,ACK
4.073910824000000,3,0x97,0x00,Read,ACK
4.073997760000000,3,0x97,0x00,Read,NAK
4.074221256000000,4,0x97,0x14,Read,ACK
4.074308572000000,4,0x97,0x81,Read,ACK
4.074395630000000,4,0x97,0x00,Read,ACK
4.074482564000000,4,0x97,0x01,Read,ACK
4.074570690000000,4,0x97,0x00,Read,ACK
4.074657500000000,4,0x97,0x01,Read,ACK
4.074744434000000,4,0x97,0x04,Read,ACK
4.074832594000000,4,0x97,0x00,Read,ACK
4.074919370000000,4,0x97,0x00,Read,ACK
4.075008020000000,4,0x97,0x00,Read,ACK
4.075097786000000,4,0x97,0x00,Read,ACK
4.075184436000000,4,0x97,0x80,Read,ACK
4.075271374000000,4,0x97,0x06,Read,ACK
4.075359780000000,4,0x97,0x31,Read,ACK
4.075446842000000,4,0x97,0x2E,Read,ACK
4.075533778000000,4,0x97,0x30,Read,ACK
4.075620712000000,4,0x97,0x2E,Read,ACK
4.075707646000000,4,0x97,0x30,Read,ACK
4.075794842000000,4,0x97,0x00,Read,ACK

Now back to T4: Again capture:
screenshot.jpg

This is more zoomed into the third group. But you will see the Logic Analyzer complains that the 97+ is missing ACK/NAK...

A zoom in on the T3.5 of that region of stuff:
screenshot.jpg

So not sure yet if it is something like a difference in start or repeat start or...
 
With the delays added seems to put things in synch. So the question is if with delays would seem to say it needs more time to get the all the data? Did you try with a increased buffer size?


EDIT:
Did you notice this in the RotationVector Example?
Code:
  //Are you using a ESP? Check this issue for more information: https://github.com/sparkfun/SparkFun_BNO080_Arduino_Library/issues/16
//  //=================================
//  delay(100); //  Wait for BNO to boot
//  // Start i2c and BNO080
//  Wire.flush();   // Reset I2C
//  IMU.begin(BNO080_DEFAULT_ADDRESS, Wire);
//  Wire.begin(4, 5); 
//  Wire.setClockStretchLimit(4000);
//  //=================================
If you look at the issue - its exactly the same as the problem we are seeing:
I have tried different things, including setting different parameters on Wire library, but nothing works. Even when ESP8266 recognizes that there is a sensor attached, which seems to be about 70% of the time, the loop() function does not generate any data. If I turn on debugging, I get a steady stream of 'I2C Timeout' messages.
 
Last edited:
@mjs513 - I am thinking that the delays may sort of at times limp around some issues in the Wire library. In particular when it does two
requestFrom requests in a rwo, where it still has control of the buss
MSR=3000301, MCR:1, MFSR=1

So in the MSR case here it says Buss is busy and master is busy and we have one thing still in queue. Code to patch for the earlier BNO... hack checked if MFSR&7 and if so killed the queue... Which in this case is probably wrong.

So trying to figure out when it should clear the queue and when not... Maybe it will turn out that is is some error state we should be finding and clearing or???

Or maybe code is not correct for how it closes out the prvious requestFrom, or ???

Again I am not an I2C master...
 
@KurtE - as you already know neither I am but I do agree with you - the delays are just addressing the symptons not the issues. Just guessing at what could actually be wrong. Wonder if it would work if we revert the BNO055 change if it would work? or have it just wait for an ACK and timeout if it doesn't receive it at some time -- playing around and looking at lib maybe 50-100ms?
 
@KurtE
Just as a quick and dirty test I reverted the T4 wire library to prior to the BNO055 change with the "hack checked if MFSR&7.." and retested with Lidar Lite V3 getDistance sketch and it worked with no problem. So you are probably on to something. Going to retest the BNO080 original now and will post an update.

EDIT: Unfortunately reverting the change does not work for the BNO080 using the original lib or my hacked up version. But it did fix the issue with lidar lite v3.
 
@mjs513 - Still shooting blanks...

But I also notice that there are delays associated with Starts.
Example here is the send of reset (first thing done by BNO980)
screenshot.jpg

Now look at same thing from T4: Notice long delay after first byte:
screenshot.jpg

Edit: Side note: You can ignore several of the functions like beginTransmission and write as they simply store something in an array.
In this case everything is in the endTransission...
 
In case related and to be sure you saw this Paul Post:
In case anyone finds this question later by search, I2C clock stretching is supported on all Teensy 3.x and 4.0 boards.

But there is a timeout which limits the maximum clock stretch, so a hung or crashed I2C device can't cause your program to stall indefinitely.

Perhaps it needs a longer timeout?

Though if a clock stretch by slave - it seems that would show on the LA?
 
@defragster - @KurtE
Thanks for the post - never saw that one. 8 more to go. Probably missing something somewhere but when I go through wireIMXRT.cpp I don't see anything associated with timeout that is not commented out? So I must be missing something?
 
I think there could be multiple parts to the clock stretching.

First in I2C registers MCFGR1, the PINCFG field which we don't set. But if you look at PINCFG(0) it says: Bi-directional open drain for master and slave

I think that maybe second part might be: PADCTL, which I mean to change again after backed out most everyhing.

Currently in ::begin and setSCL/setSDA we have:
Code:
	*(portControlRegister(hardware.sda_pins[sda_pin_index_].pin)) |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3);
So we take whatever is there and turn on PU resistor...

I was thinking to change it to be more like more closely to T3.x
Code:
	*(portControlRegister(hardware.sda_pins[sda_pin_index_].pin)) = IOMUXC_PAD_ODE |IOMUXC_PAD_SRE |  IOMUXC_PAD_DSE(5)| IOMUXC_PAD_SPEED(1);

It is interesting, I get lots of stuff on LA if I have debug printing turned on, but almost nothing if I don't....


Still debuggin
 
Still trying to get better handle on it.
But I did push up a WIP branch (https://github.com/KurtE/Wire/tree/T4_BNO80_issues)

Modified Test app works some of the time:
Code:
/*
  Using the BNO080 IMU
  By: Nathan Seidle
  SparkFun Electronics
  Date: December 21st, 2017
  License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

  Feel like supporting our work? Buy a board from SparkFun!
  https://www.sparkfun.com/products/14586

  This example shows how to output accelerometer values

  Hardware Connections:
  Attach the Qwiic Shield to your Arduino/Photon/ESP32 or other
  Plug the sensor onto the shield
  Serial.print it out at 9600 baud to serial monitor.
*/

#include <Wire.h>

#include "SparkFun_BNO080_Arduino_Library.h"
BNO080 myIMU;

void setup()
{
  while (!Serial && millis() < 5000) ;
  Serial.begin(9600);
  Serial.println();
  Serial.println("BNO080 Read Example");
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  Wire.begin();
  Serial.println("After Wire.begin()");
  Serial.flush();
  delay(50);
  /*
  Serial.printf(" VERID:%08x", (uint32_t)LPI2C1_VERID);
  Serial.printf(" PARAM:%08x", (uint32_t)LPI2C1_PARAM);
  Serial.printf(" MCR:%08x", (uint32_t)LPI2C1_MCR);
  Serial.printf(" MSR:%08x", (uint32_t)LPI2C1_MSR);
  Serial.printf(" MIER:%08x", (uint32_t)LPI2C1_MIER);
  Serial.printf(" MDER:%08x", (uint32_t)LPI2C1_MDER);
  Serial.println(); Serial.flush();
  Serial.printf(" MCFGR0:%08x", LPI2C1_MCFGR0);
  Serial.printf(" MCFGR1:%08x", LPI2C1_MCFGR1);
  Serial.printf(" MCFGR2:%08x", LPI2C1_MCFGR2);
  Serial.printf(" MCFGR3:%08x", LPI2C1_MCFGR3);
  Serial.println(); Serial.flush();
  Serial.printf(" MDMR:%08x", (uint32_t)LPI2C1_MDMR);
  Serial.printf(" MCCR0:%08x", (uint32_t)LPI2C1_MCCR0);
  Serial.printf(" MCCR1:%08x", (uint32_t)LPI2C1_MCCR1);
  Serial.println(); Serial.flush();
  Serial.printf(" MFCR:%08x", (uint32_t)LPI2C1_MFCR);
  Serial.printf(" MFSR:%08x", (uint32_t)LPI2C1_MFSR);
//  Serial.printf(" MTDR:%08x", (uint32_t)LPI2C1_MTDR);
//  Serial.printf(" MRDR:%08x", (uint32_t)LPI2C1_MRDR);
  Serial.println(); Serial.flush();;
*/
  myIMU.begin();

  Wire.setClock(400000); //Increase I2C data rate to 400kHz

  myIMU.enableAccelerometer(50);    //We must enable the accel in order to get MEMS readings even if we don't read the reports.
  myIMU.enableRawAccelerometer(50); //Send data update every 50ms
  myIMU.enableGyro(50);
  myIMU.enableRawGyro(50);
  myIMU.enableMagnetometer(50);
  myIMU.enableRawMagnetometer(50);

  Serial.println(F("Raw MEMS readings enabled"));
  Serial.println(F("Output is: (accel) x y z (gyro) x y z (mag) x y z"));
}

void loop()
{
  //Look for reports from the IMU
  if (myIMU.dataAvailable() == true)
  {
    int x = myIMU.getRawAccelX();
    int y = myIMU.getRawAccelY();
    int z = myIMU.getRawAccelZ();

    Serial.print(x);
    Serial.print("\t");
    Serial.print(y);
    Serial.print("\t");
    Serial.print(z);
    Serial.print("\t");

    int gx = myIMU.getRawGyroX();
    int gy = myIMU.getRawGyroY();
    int gz = myIMU.getRawGyroZ();

    Serial.print(gx);
    Serial.print("\t");
    Serial.print(gy);
    Serial.print("\t");
    Serial.print(gz);
    Serial.print("\t");

    int mx = myIMU.getRawMagX();
    int my = myIMU.getRawMagY();
    int mz = myIMU.getRawMagZ();

    Serial.print(mx);
    Serial.print("\t");
    Serial.print(my);
    Serial.print("\t");
    Serial.print(mz);
    Serial.print("\t");

    Serial.println();
  }
}

Still trying to figure out some of the timings stuff. Like the Hold time SETHOLD MCCR0

Probably won't get much more done tonight.
 
@KurtE

Re: SETHOLD for MCCRO: Did you look at Table 46-9 pg 2879.

If you remember I have a PR changing that section so we can get up to 3Mhz:https://github.com/PaulStoffregen/Wire/pull/17. Here it is for your consideration. Two things had to be done: (1) changed to 60Mhz clock
Code:
//use 60Mhz clock 
    CCM_CSCDR2 = (CCM_CSCDR2 & ~CCM_CSCDR2_LPI2C_CLK_PODF(63));
	CCM_CCSR = 0;

and then change the timinings:
Code:
	if (frequency < 400000) {
		// 100 kHz
		port->MCCR0 = LPI2C_MCCR0_CLKHI(55) | LPI2C_MCCR0_CLKLO(59) |
			LPI2C_MCCR0_DATAVD(25) | LPI2C_MCCR0_SETHOLD(40);
		port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(2);
		port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(5) | LPI2C_MCFGR2_FILTSCL(5) |
			LPI2C_MCFGR2_BUSIDLE(3900);
	} else if (frequency < 1000000) {
		// 400 kHz
		port->MCCR0 = LPI2C_MCCR0_CLKHI(31) | LPI2C_MCCR0_CLKLO(40) |
			LPI2C_MCCR0_DATAVD(8) | LPI2C_MCCR0_SETHOLD(17);
		port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(1);
		port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(2) | LPI2C_MCFGR2_FILTSCL(2) |
			LPI2C_MCFGR2_BUSIDLE(3900);
	} else if (frequency < 3000000) {
		// 1 MHz
		port->MCCR0 = LPI2C_MCCR0_CLKHI(9) | LPI2C_MCCR0_CLKLO(18) |
			LPI2C_MCCR0_DATAVD(4) | LPI2C_MCCR0_SETHOLD(9);
		port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(1);
		port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(1) | LPI2C_MCFGR2_FILTSCL(1) |
			LPI2C_MCFGR2_BUSIDLE(3900);
	} else {
		// 3.33 MHz
		port->MCCR0 = LPI2C_MCCR0_CLKHI(2) | LPI2C_MCCR0_CLKLO(4) |
			LPI2C_MCCR0_DATAVD(1) | LPI2C_MCCR0_SETHOLD(4);
		port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(1);
		port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(1) | LPI2C_MCFGR2_FILTSCL(1) |
			LPI2C_MCFGR2_BUSIDLE(3900);
	}
Think there are some similarities in sethold settings.

PS> I ran your changes and it worked out of the box.

EDIT: That also seems to fix the issue I was having with Lidar Lite V3.
 
Last edited:
@KurtE

I just incorporated my setclock changes to get 3Mhz along with using the 60Mhz clock instead of the 24 Mhz clock and retested with your changes.

BNO080 - ran the rawReadings, timestamp and rotationVector examples and all ran without an issue and having to restart.

Lidar Lite V3 - worked as advertised. The original issue I posted seems to be resolved with the latest changes.
 
@KurtE

I just incorporated my setclock changes to get 3Mhz along with using the 60Mhz clock instead of the 24 Mhz clock and retested with your changes.

BNO080 - ran the rawReadings, timestamp and rotationVector examples and all ran without an issue and having to restart.

Lidar Lite V3 - worked as advertised. The original issue I posted seems to be resolved with the latest changes.

Sounds like, I should/will incorporate your speed changes and run them again on mine.

We probably should also try the other BNO... and see if it still works as well.

Kurt

EDIT: Forgot to mention - Yes I had looked over that table many times, although it did not have 24mhz... and the values for SETHOLD that we were using looked off...
 
Sounds like, I should/will incorporate your speed changes and run them again on mine.

We probably should also try the other BNO... and see if it still works as well.

Kurt

Here save you the time: View attachment WireIMXRT.zip

Have to get some coffee and the on to the other BNO once I find it :)

EDIT: Ok found it - tested a few of the sketches and they seem to be working. One funny thing seem to have to power on and off sometimes after I initially upload a sketch - its kind of hit or miss.
 
Last edited:
Thanks @mjs513... Already did the edit, plus remove my added digitalWriteFast calls and ran it on BNO080 and looks like it is working. I pushed the changes up to github.

Looks like the starts/restarts are not as bad as before...

Found my BNO055, just going to look up on Adafruit site to remember if it has PU resistors on it... and patch in wires...

EDIT: I just hooked it up with the 4 wires and the Raw data sketch appears to run without changes using the new stuff :D

Will go ahead and issue PR
 
@KurtE
Great work on getting it working. Would never of thought about making that change to the pin configurations - was looking a more complicated change.
 
@KurtE
Great work on getting it working. Would never of thought about making that change to the pin configurations - was looking a more complicated change.

Thanks, I think the biggest thing was that the (My) fix for BNO55 took sledgehammer approach for clearing the FIFO queue if you ever entered the endTransmission, or requestFrom functions, which KILLED the ability to do repeat Starts... (I think).

So the main fix was to NOT kill the FIFO if we enter and we are master and busy (MSR register - BBF, MBF). I think this was killing the repeat starts, which the code for BNO80 relied on.

Pin configuration: Looked at how T3.x configured versus what we were doing and wondered.

PR issued: https://github.com/PaulStoffregen/Wire/pull/18
 
@KurtE

Went ahead and closed PR#17 since you incorporated the clock changes into your PR. No sense I having duplicate PRs.
 
@mjs513 @PaulStoffregen -

I will do a little more hacking, unless someone wants to beat me to it ;)

First issue: The hung buss. Which I am in right now.

Will duplicate some of the code of WireKinetis.cpp in the endTransmision, it calls off to wait_idle, which in here it looks like if it waits > 16ms it bails out.
It also turns off Wire and turns it back on...

Working on it now...
 
@KurtE
Just a FYI - found the discount link and broke down and ordered a Saleae Logic 8. Should have it next week - gave up not having a good one.

Sounds like the same as the original issue where I kind of added delays all over those function calls?
 
Status
Not open for further replies.
Back
Top