Teensy 4.0 and Adafruit BNO055

Status
Not open for further replies.

Maikeru

New member
Hi,
I was wondering if somebody has also problems with the teensy 4.0 board. Trying to run the Adafruit BNO055 on a Teensy 4.0 with the standard Adafruit examples in Arduino/Teensyduino, it firstly doesn't get into the loop part until I remove the check for the BNO055 is present and then it doesn't get any values and shows only zeros.

Using my Teensy 3.6 board, it perfectly runs, like on my Arduino Nano.
Apologies if someone thinks this is better placed in the Adafruit forum, but then it a difference between two teensy boards I don't understand.

Thank you a lot in advance.

Mike
 
Thank you!, indeed commenting the Reset section in the library does make it work. Now is this a teensy 4.0 or an Adafruit problem?
 
I found the issue on the bosch site and the work around. Also just saw something on the Adafruit site about something like it and resetting. So think the issue is probably on the Adafruit side.
 
Just as a test - I had found this on the adafruit forum: https://forums.adafruit.com/viewtopic.php?t=133511#p664391
Simply hook up the reset line to a spare GPIO line on your controller and toggle it low for at least 20 nsec, then drive it high and keep it there for at least 650 msec before you start initialization (yes, that long!).
which equates to this instead of the write8
Code:
  pinMode(3, OUTPUT);
  digitalWrite(3, LOW);
  delayNanoseconds(20);
  digitalWrite(3, HIGH);
  delay(650);
Haven't done exhaustive testing on this but the raw example does run. There may be other problems. I also haven't tested with i2c_t3 to see if that helped
 
@Maikeru - @PaulStoffregen

Just as a quick test I hooked up the BNO055 to a T3.6 with the reset command uncommented:
Code:
  write8(BNO055_SYS_TRIGGER_ADDR, 0x20);

and the examples work without a problem. So may or may not be a BNO055 problem but a T4 problem. Think Paul needs to do his debugging to get the correct answer.
 
For the heck of it, went to my display and sensors box and found an BNO055 and hooked up the same as Paul.

Ran Wire example scanner:
Code:
Scanning...
Device found at address 0x28  (BNO055,EM7180,CAP1188)
done

And running the same test, I see the same hang. It appears to kill the system totally, that is I updated the test program:
Code:
while (!Serial && millis() < 5000) ;
  Serial.begin(9600);
  Serial.println("Orientation Sensor Test"); Serial.println("");
  Serial.flush();
  delay(500);
...
And nothing shows up in the display. Commenting out the above line and it appears to run...
Will hook up Logic Analyzer and see if it shows anything...
 
@KurtE

Thanks for checking - Mike

Edit: I did put some prints and delays in write function in wire but it hangs on that one command but not on the T3.6?
 
I also looked at it with Logic Analyzer and it outputs the reset command, which I did not notice anything unusual...

Then it tried to output the next command, which it NAKEd once and that was the last I2C output.
screenshot.jpg
Showed both Analog and digital values here..

Will look at it more later, got some other stuff needing to get done.
 
Last edited:
I did a quick look at running the same sketch with a T3.0 (I thought I was grabbing a 3.2, but...)

So ran it again and the with the Reset function in place, sure enough the next output Was Setup to write to 50 NAK, Setup RED 51 NAK.

Which was the LAST output on T4. But here this sequence repeats something like 47 Times until we get a
Setup Write 50 ACK Write 0, SETUP Read 51 ... If I look at how long it took between the output of the Reset until I got a valid ACK it was about .5 seconds. There was about a 10ms gap between the retries.

And then continues and runs again.

This feels like the WireIMXRT code is not properly handling the NAK and doing the retries.


That is all for now... Will try to look again tomorrow.

Kurt
 
@KurtE

Not sure if this will help but I uncommented the printf's in endtransmission in wireIMXRT.cpp:
Code:
Orientation Sensor Raw Data Test

Chip ID
m=1
MSR=1, MFSR=0
t=0
start 50
Switch Mode
m=3000101
MSR=3000101, MFSR=1
t=1
start 50
t=3
BNO055_SYS_TRIGGER_ADDR
m=301
MSR=301, MFSR=0
t=0
start 50
m=301
MSR=301, MFSR=0
t=0
start 50
NACK, f=2, i=3
status timeout = 1000
status timeout = 1000
status timeout keeps repeating infinitely...……
 
@mjs513 - Good morning, I decided to instrument the code as well with digitalWriteFast calls. I knew that the BNO055 code was hanging after the reset was sent, and it did one query and got a NAK... Should repeat the query until it received a valid response of it's id...

That is this code in their begin method:
Code:
/* Reset */
  write8(BNO055_SYS_TRIGGER_ADDR, 0x20);
  /* Delay incrased to 30ms due to power issues https://tinyurl.com/y375z699 */
  delay(30);
  while (read8(BNO055_CHIP_ID_ADDR) != BNO055_ID) {
    delay(10);
  }

So I put some writes in their read8 code:
Code:
byte Adafruit_BNO055::read8(adafruit_bno055_reg_t reg) {
  byte value = 0;
  digitalWriteFast(0, HIGH);
  digitalWriteFast(1, HIGH);
  _wire->beginTransmission(_address);
#if ARDUINO >= 100
  _wire->write((uint8_t)reg);
#else
  _wire->send(reg);
#endif
  _wire->endTransmission();
  digitalWriteFast(1, LOW);
  _wire->requestFrom(_address, (byte)1);
#if ARDUINO >= 100
  value = _wire->read();
#else
  value = _wire->receive();
#endif
  digitalWriteFast(0, LOW);

  return value;
}
And Capturing this, I see:
screenshot.jpg

So the code makes it throught the first read8 call, delays 10ms and calls again, which hangs in the write code, probably for sure in the endTransmission call
 
@KurtE

Yeah that's pretty much what I am seeing as well.

It will make it through the first read8 which gets the CHIP ID. The next write8 is to Switch Mode's to Configuration mode. The third write is for the rest with the BNO055_SYS_TRIGGER_ADDR, 0x20 which gets stuck in endTransmission it seems.

EDIT: A couple of other things. This might also be related to the MPL3115 issue I was having: https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=207003&viewfull=1#post207003. The solution to that was to add a delay before endtransmission. I did try that but no luck for this one.

Also, early on (beginning of this year) I had a problem with i2cscanner not working - Paul put in a fix for 1.46-beta4 and that seemed to resolve it - not sure what the fix was though - didn't look at the time.

Issue: https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=194081&viewfull=1#post194081
 
Last edited:
@mjs513 @PaulStoffregen - I think one hint is what you printed out:
Code:
status timeout = 1000

At first I thought the 1000 was simply the timeout value, then saw that it is the value from the MSR

So 1000 -> FEF is FIFO ERROR FLAG -
FIFO Error Flag
Detects an attempt to send or receive data without first generating a (repeated) START condition. This
can occur if the transmit FIFO underflows when the AUTOSTOP bit is set. When FIFO Error Flag is set,
the LPI2C master will send a STOP condition (if busy), and will not initiate a new START condition until
FIFO Error Flag has been cleared.
0b - No error
1b - Master sending or receiving data without a START condition
Next up try to detect this flag and clear it and see what happens?

EDIT: It still hangs...
 
@KurtE @PaulStoffregen

fifo_used always seems to be = 4. Not sure if that means anything.
 
@...

I also updated the code to print out everything (like @mjs513 did earlier) plus add a printf at start of endTransmission and requestFrom to get ideas of what is going on...
Code:
endTransmission 2 (00000050 00000000 00000000) 00000001
m=00000001
MSR=00000001, MFSR=00000000
t=0
start 00000050

requestFrom 00000028 00000001 00000001
idle2, msr=00000301
MSR=00000301, MFSR=00000000
t=0
r=1

endTransmission 3 (00000050 0000003D 00000000) 00000001
m=00000301
MSR=00000301, MFSR=00000000
t=0
start 00000050

endTransmission 3 (00000050 0000003F 00000020) 00000001
m=00000301
MSR=00000301, MFSR=00000000
t=0
start 00000050

endTransmission 2 (00000050 00000000 00000020) 00000001
m=00000301
MSR=00000301, MFSR=00000000
t=0
start 00000050
NACK, f=2, i=3

requestFrom 00000028 00000001 00000001
idle2, msr=00000701
MSR=[COLOR="#FF0000"]00000701[/COLOR], MFSR=[COLOR="#FF0000"]00000001[/COLOR]
t=1
Status = 00001100
Status = 00001100
Status = 00001100
Status = 00001100
Status = 00001100
Status = 00001100
Status = 00001100
Status = 00001100
In this case it appears to have hung in request from:
Interesting info: MSR is 701(NDF-NACK, SDF-Stop Detect, EPF-End Packet, TDF-Transmit Dat)
Most of the others were 301 which does not have NACK which makes sense.

BUT: MFSR=1 says that there is something already in TX FIFO, So maybe this needs to be cleared? otherwise we end up with 1100 or
Fifo Error flag, EPF...
 
@KurtE

That seems to make sense - fifo_used comes in at 4 so the fifo prints never seem to hit.
 
@PaullStoffregen @mjs513 ...

I used a few sledge hammers and I got it to not stick... But not sure if correct to do?

The main thing is I clear out FIFO queue and clear FTF

Here are the two functions. Note: with the sketch in this thread, I receiving back all zeros...

Code:
uint8_t TwoWire::endTransmission(uint8_t sendStop)
{
	//printf("\nendTransmission %d (%x %x %x) %x\n", txBufferLength,txBuffer[0], txBuffer[1], txBuffer[2], sendStop);
	uint32_t i=0, len, status;

	len = txBufferLength;
	if (!len) return 4; // no data to transmit

	// wait while bus is busy
	while (1) {
		status = port->MSR; // pg 2899 & 2892
		if (!(status & LPI2C_MSR_BBF)) break; // bus is available
		if (status & LPI2C_MSR_MBF) break; // we already have bus control
		// TODO: timeout...
	}
	//printf("m=%x\n", status);

	// Wonder if MFSR we should maybe clear it?
	if ( port->MFSR & 0x7) {
		port->MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF;  // clear the FIFO
		port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF | LPI2C_MSR_FEF; // clear flags
		//printf("Clear TX Fifo %lx %lx\n", port->MSR, port->MFSR);
	}
	// TODO: is this correct if the prior use didn't send stop?
	//port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF; // clear flags
	port->MSR = status;

	//printf("MSR=%lX, MFSR=%lX\n", status, port->MFSR);
	//elapsedMillis timeout=0;

	while (1) {
		// transmit stuff, if we haven't already
		if (i <= len) {
			uint32_t fifo_used = port->MFSR & 0x07; // pg 2914
			//if (fifo_used < 4) printf("t=%ld\n", fifo_used);
			while (fifo_used < 4) {
				if (i == 0) {
					//printf("start %x\n", txBuffer[0]);
					port->MTDR = LPI2C_MTDR_CMD_START | txBuffer[0];
					i = 1;
				} else if (i < len) {
					port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | txBuffer[i++];
				} else {
					if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP;
					i++;
					break;
				}
				fifo_used = fifo_used + 1;
			}
		}
		// monitor status
		status = port->MSR; // pg 2899 & 2892
		if (status & LPI2C_MSR_ALF) {
			//printf("arbitration lost\n");
			return 4; // we lost bus arbitration to another master
		}
		if (status & LPI2C_MSR_NDF) {
			//printf("NACK, f=%d, i=%d\n", port->MFSR & 0x07, i);
			// TODO: check that hardware really sends stop automatically
			port->MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF;  // clear the FIFO
			// TODO: is always sending a stop the right way to recover?
			port->MTDR = LPI2C_MTDR_CMD_STOP;
			return 2; // NACK for address
			//return 3; // NACK for data TODO: how to discern addr from data?
		}
		//if (status & LPI2C_MSR_PLTF) {
			//printf("bus stuck - what to do?\n");
			//return 4;
		//}

		//if (timeout > 100) {
			//printf("status = %x\n", status);
			//timeout = 0;
		//}

		if (sendStop) {
			if (status & LPI2C_MSR_SDF) {
				// master automatically sends stop condition on some
				// types of errors, so this flag only means success
				// when all comments in fifo have been fully used
				uint32_t fifo = port->MFSR & 0x07;
				if (fifo == 0) return 0;
			}
		} else {
			uint32_t fifo_used = port->MFSR & 0x07; // pg 2914
			if (fifo_used == 0) {
				//digitalWriteFast(15, HIGH);
				//delayMicroseconds(2);
				//digitalWriteFast(15, LOW);
				// TODO: this returns before the last data transmits!
				// Should verify every byte ACKs, arbitration not lost
				//printf("fifo empty, msr=%x\n", status);
				return 0;
			}
		}
	}
}

uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
{
	uint32_t cmd=0, status, fifo;

	// wait while bus is busy
	//printf("\nrequestFrom %x %x %x\n", address, length, sendStop);
	while (1) {
		status = port->MSR; // pg 2899 & 2892
		if (!(status & LPI2C_MSR_BBF)) break; // bus is available
		if (status & LPI2C_MSR_MBF) break; // we already have bus control
		// TODO: timeout...
	}
	//printf("idle2, msr=%x\n", status);

	// TODO: is this correct if the prior use didn't send stop?
	port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF | LPI2C_MSR_FEF; // clear flags

	//printf("MSR=%lX, MCR:%lx, MFSR=%lX\n", status, port->MCR, port->MFSR);

	// Wonder if MFSR we should maybe clear it?
	if ( port->MFSR & 0x7) {
		port->MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF;  // clear the FIFO
		port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF | LPI2C_MSR_FEF; // clear flags
		//printf("Clear TX Fifo %lx %lx\n", port->MSR, port->MFSR);
	}
	address = (address & 0x7F) << 1;
	if (length < 1) length = 1;
	if (length > 255) length = 255;
	rxBufferIndex = 0;
	rxBufferLength = 0;

	//elapsedMillis timeout=0;

	while (1) {
		// transmit stuff, if we haven't already
		if (cmd < 3) {
			fifo = port->MFSR & 0x07; // pg 2914
			//if (fifo < 4) printf("t=%ld\n", fifo);
			while (fifo < 4 && cmd < 3) {
				if (cmd == 0) {
					port->MTDR = LPI2C_MTDR_CMD_START | 1 | address;
				} else if (cmd == 1) {
					// causes bus stuck... need way to recover
					//port->MTDR = LPI2C_MTDR_CMD_START | (length - 1);
					port->MTDR = LPI2C_MTDR_CMD_RECEIVE | (length - 1);
				} else {
					if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP;
				}
				cmd++;
				fifo = fifo + 1;
			}
		}
		// receive stuff
		if (rxBufferLength < sizeof(rxBuffer)) {
			fifo = (port->MFSR >> 16) & 0x07;
			//if (fifo > 0) printf("r=%ld\n", fifo);
			while (fifo > 0 && rxBufferLength < sizeof(rxBuffer)) {
				rxBuffer[rxBufferLength++] = port->MRDR;
				fifo = fifo - 1;
			}
		}
		// monitor status
		status = port->MSR; // pg 2899 & 2892
		if (status & LPI2C_MSR_ALF) {
			//printf("arbitration lost\n");
			break;
		}
		if (status & LPI2C_MSR_NDF) {
			//printf("got NACK\n");
			// TODO: how to make sure stop is sent?
			break;
		}

		//if (timeout > 250) {
			//printf("Status = %x\n", status);
			//timeout = 0;
		//}

		if (rxBufferLength >= length && cmd >= 3) break;
	}
	//digitalWriteFast(15, HIGH);
	//delayMicroseconds(2);
	//digitalWriteFast(15, LOW);
	return rxBufferLength;
}
 
@KurtE @PaullStoffregen

Sorry - been repairing holes in walls today and grouting tile. Anyway I tested your changes with the BNO055 and the propshield with the MPL3115 that I was having a problem with.

The fix you put in place works with the BNO055 as well as fixing the issue with MPL3115.

Also tested i2cscanner and that works with issue as well.
 
FWIW, I notice the mbed lib for BNO055 has a much longer delay after issuing reset
Code:
void BNO055::reset(){
//Perform a power-on-reset
    readchar(BNO055_SYS_TRIGGER_ADDR);
    rx = rx | 0x20;
    writechar(BNO055_SYS_TRIGGER_ADDR,rx);
//Wait for the system to come back up again (datasheet says 650ms)
    wait_ms(675);
}

EDIT: As per datasheet, I changed delay after reset in Adafruit_BNO055.cpp to 700 ms, and BNO055 examples worked on Teensy 4.
Code:
...
  /* Reset */
  write8(BNO055_SYS_TRIGGER_ADDR, 0x20);
  /* Delay incrased to 30ms due to power issues https://tinyurl.com/y375z699 */
  delay(700);
  while (read8(BNO055_CHIP_ID_ADDR) != BNO055_ID) {
...
As noted, examples work on T3* with delay(30)
 
Last edited:
Status
Not open for further replies.
Back
Top