Hi,
After reading a lot of threads on SPI for teensy 4.0, BNO08x issues on i2c (fixed now) on teensy 4.0, SPI considerations (pull up cs, reflection, sck buffers if many spi devices), I think I am facing a tiny different issue that was not in the forum yet, hence a new thread.
I am using a Teensy 4.0@150 Mhz and a GY-BNO08X break out board.
with arduino-1.8.13 + teensyduino 1.53
latest SparkFun_BNO080_Arduino_Library (to use the new getReadings API)
using SPI communication for the BNO + interrupts to know when new data is available
Until now I had no issues running the BNO08x board on the main SPI port (or module) I will name it SPI0 to clarify the writing, but I wanted to change to another SPI port for instance SPI1 or SPI2. (the reason are related to free the LED pin 13 used for SCK0) and to add a set of 5 ADC on a second SPI port and avoiding sharing the bus with the IMU)
I managed to get the BNO08x work with SPI1 with all the default pins, at a speed of 3 MHz
however I am facing issues when I want to use SPI2.
The SparkFun_BNO080_Arduino_Library hangs after 5 bytes transferred as can be seen in the screenshot of the logic analyzer or in the additional printouts I put in the sparkfun lib.
The screenshot shows valid transfers of 5 bytes on SPI2 that are identical to the same 5 first bytes when used on SPI1, which means I did not mix up the lines when I hooked up the IMU to SPI2
The problem is reproducible, meaning, it is not a random glitch on the clock, that stop transfer at a random time. it is always after 5 bytes.
Reading so many possible causes, I tried a lot.
* I took the latest SPI.cpp/SPI.h from github (it added transfer16 and transfer32 for teensy4 from what I had before) => no change
* I verified and re-verified my wires, redid the soldering to ensure they are okay (it is tiny at those pads...) => no change
* had a colleague test on his Teensy4.0 with his BNO08x exact same issue, hands at the same point (although he did not have the analyzer to check it is exactly hanging at the same 5 bytes)
* I added a 47 Ohms "source" resistor in series on SCK2 at its pad (pin 37) and at the MOSI2 pad (pin 35) to avoid reflections => no change, but kept them
* added a 2.2 kOhms pull up on the CS2 line (pin 36) => no change, but kept it
* I tried to modify the driver strength (as suggested there https://forum.pjrc.com/threads/5994...PI-peripherals?p=232814&viewfull=1#post232814)
- IOMUXC_PAD_DSE(2) IOMUXC_PAD_SPEED (1) or IOMUXC_PAD_DSE(3) IOMUXC_PAD_SPEED (3) changed everywhere in SPI.cpp made the number of byte exchanged go from 5 to 1 and then the device freezes on SPI2 AND on SPI1
- IOMUXC_PAD_DSE(6) IOMUXC_PAD_SPEED (2) worked for SPI1 but made SPI2 block after 1 byte
- and of course the default DSE(7) SPEED(2) was working for SPI1 and 5 bytes transferred for SPI2
* I looked on fifo buffer issues as in the i2c here (https://forum.pjrc.com/threads/5994...to-hang-die-when-connected-to-SPI-peripherals) => but seems the sparkfun lib uses bare 8bit transfers not the fifo one
* Something is strange on the rxISR for SPI2, maybe a typo/bug in the SPI lib https://github.com/PaulStoffregen/SPI/blob/master/SPI.cpp#L1608 should'nt it read read _spi_dma_rxISR2 not _spi_dma_rxISR1 (same at line L1620) => did not change anything if I changed it to _spi_dma_rxISR2 as I don't use dma.
running out of ideas right now.
Did any of the experts in this forum test BNO08x on SPI2 on Teensy4.0 ?
SPI2 only 5 bytes logic analyzer
SPI1 good initialization (as a comparison)
my program (change the #define at the top to use either SPI1 or SPI2)
thanks in advance for any advice. No urgency at all, and I am ready to test a lot to debug this.
We are currently going to use SPI0 + SPI1 but would prefer to use SPI1 and SPI2 and free the LED that was used in the past on Teensy 3.2 and our users liked being able to tell the status with the LED (was blinking differently in different mode of operation
best
Guillaume
After reading a lot of threads on SPI for teensy 4.0, BNO08x issues on i2c (fixed now) on teensy 4.0, SPI considerations (pull up cs, reflection, sck buffers if many spi devices), I think I am facing a tiny different issue that was not in the forum yet, hence a new thread.
I am using a Teensy 4.0@150 Mhz and a GY-BNO08X break out board.
with arduino-1.8.13 + teensyduino 1.53
latest SparkFun_BNO080_Arduino_Library (to use the new getReadings API)
using SPI communication for the BNO + interrupts to know when new data is available
Until now I had no issues running the BNO08x board on the main SPI port (or module) I will name it SPI0 to clarify the writing, but I wanted to change to another SPI port for instance SPI1 or SPI2. (the reason are related to free the LED pin 13 used for SCK0) and to add a set of 5 ADC on a second SPI port and avoiding sharing the bus with the IMU)
I managed to get the BNO08x work with SPI1 with all the default pins, at a speed of 3 MHz
however I am facing issues when I want to use SPI2.
The SparkFun_BNO080_Arduino_Library hangs after 5 bytes transferred as can be seen in the screenshot of the logic analyzer or in the additional printouts I put in the sparkfun lib.
The screenshot shows valid transfers of 5 bytes on SPI2 that are identical to the same 5 first bytes when used on SPI1, which means I did not mix up the lines when I hooked up the IMU to SPI2
The problem is reproducible, meaning, it is not a random glitch on the clock, that stop transfer at a random time. it is always after 5 bytes.
Reading so many possible causes, I tried a lot.
* I took the latest SPI.cpp/SPI.h from github (it added transfer16 and transfer32 for teensy4 from what I had before) => no change
* I verified and re-verified my wires, redid the soldering to ensure they are okay (it is tiny at those pads...) => no change
* had a colleague test on his Teensy4.0 with his BNO08x exact same issue, hands at the same point (although he did not have the analyzer to check it is exactly hanging at the same 5 bytes)
* I added a 47 Ohms "source" resistor in series on SCK2 at its pad (pin 37) and at the MOSI2 pad (pin 35) to avoid reflections => no change, but kept them
* added a 2.2 kOhms pull up on the CS2 line (pin 36) => no change, but kept it
* I tried to modify the driver strength (as suggested there https://forum.pjrc.com/threads/5994...PI-peripherals?p=232814&viewfull=1#post232814)
- IOMUXC_PAD_DSE(2) IOMUXC_PAD_SPEED (1) or IOMUXC_PAD_DSE(3) IOMUXC_PAD_SPEED (3) changed everywhere in SPI.cpp made the number of byte exchanged go from 5 to 1 and then the device freezes on SPI2 AND on SPI1
- IOMUXC_PAD_DSE(6) IOMUXC_PAD_SPEED (2) worked for SPI1 but made SPI2 block after 1 byte
- and of course the default DSE(7) SPEED(2) was working for SPI1 and 5 bytes transferred for SPI2
* I looked on fifo buffer issues as in the i2c here (https://forum.pjrc.com/threads/5994...to-hang-die-when-connected-to-SPI-peripherals) => but seems the sparkfun lib uses bare 8bit transfers not the fifo one
* Something is strange on the rxISR for SPI2, maybe a typo/bug in the SPI lib https://github.com/PaulStoffregen/SPI/blob/master/SPI.cpp#L1608 should'nt it read read _spi_dma_rxISR2 not _spi_dma_rxISR1 (same at line L1620) => did not change anything if I changed it to _spi_dma_rxISR2 as I don't use dma.
running out of ideas right now.
Did any of the experts in this forum test BNO08x on SPI2 on Teensy4.0 ?
SPI2 only 5 bytes logic analyzer
SPI1 good initialization (as a comparison)
my program (change the #define at the top to use either SPI1 or SPI2)
Code:
#include <SPI.h> // include the new SPI library:
#include <SparkFun_BNO080_Arduino_Library.h>
BNO080 myIMU;
#define EXT_USES_SPI1
#define IMU_MASK_ALLNEWDATA 0x07 // 0x07
#define IMU_MASK_ACC 0x01
#define IMU_MASK_GYRO 0x02
#define IMU_MASK_QUAT 0x04
#ifdef EXT_USES_SPI1
//GPIO pins for SPI1 on teensy4.0
const byte imuCSPin = 0;
const byte imuWAKPin = 24; //PS0
const byte imuINTPin = 25; //INT
const byte imuRSTPin = 2; //RST
// SPI1 on Teensy 4.0 uses COPI Pin = 26 CIPO Pin = 1, SCK Pin = 27
const byte imuCOPIPin = 26;
const byte imuCIPOPin = 1;
const byte imuSCKPin = 27;
#endif
#ifdef EXT_USES_SPI2
//GPIO pins for SPI2 on teensy4.0
const byte imuCSPin = 36;
const byte imuWAKPin = 23; //PS0
const byte imuINTPin = 17; //INT
const byte imuRSTPin = 22; //RST
// SPI2 on Teensy 4.0 uses COPI Pin = 35 CIPO Pin = 34, SCK Pin = 37
const byte imuCOPIPin = 35;
const byte imuCIPOPin = 34;
const byte imuSCKPin = 37;
#endif
bool imu_initialized = false;
// internal copies of the IMU data to sync them and send when all are new
float ax, ay, az, gx, gy, gz, qx, qy, qz, qw; // (qx, qy, qz, qw = to i,j,k, real)
// indicators of new data availability
volatile byte newQuat = 0;
volatile byte newLinAcc = 0;
volatile byte newGyro = 0;
byte new_imu_reports = 0;
void setup() {
// initialize serial communication at 115200 bits per second:
Serial.begin(115200);
Serial.setTimeout(500); //timeout of 500 ms
while (!Serial) {
; // wait for serial port to connect. Needed for native USB
}
myIMU.enableDebugging(Serial); //Pipe debug messages to Serial port
// set up the SPI pins utilized on Teensy 4.0
#ifdef EXT_USES_SPI1
Serial.println("setting up SPI1");
SPI1.setMOSI(imuCOPIPin);
SPI1.setMISO(imuCIPOPin);
SPI1.setSCK(imuSCKPin);
// initialize SPI1:
SPI1.begin();
#endif
#ifdef EXT_USES_SPI2
Serial.println("setting up SPI2");
SPI2.setMOSI(imuCOPIPin);
SPI2.setMISO(imuCIPOPin);
SPI2.setSCK(imuSCKPin);
// initialize SPI2:
SPI2.begin();
#endif
Serial.println("initializing IMU");
//Setup BNO080 to use SPI interface with default SPI port and max BNO080 clk speed of 3MHz
#ifdef EXT_USES_SPI1
imu_initialized = myIMU.beginSPI(imuCSPin, imuWAKPin, imuINTPin, imuRSTPin, 3000000, SPI1);
#endif
#ifdef EXT_USES_SPI2
imu_initialized = myIMU.beginSPI(imuCSPin, imuWAKPin, imuINTPin, imuRSTPin, 3000000, SPI2);
#endif
Serial.println("start IMU requested");
// Default periodicity (IMU_REFRESH_PERIOD ms)
if (imu_initialized)
{
myIMU.enableLinearAccelerometer(20); // m/s^2 no gravity
myIMU.enableRotationVector(20); // quat
myIMU.enableGyro(20); // rad/s
}
else
Serial.println("failed to initialize IMU");
// prepare interrupt on falling edge (= signal of new data available)
attachInterrupt(digitalPinToInterrupt(imuINTPin), imu_interrupt_handler, FALLING);
interrupts();
// no code below this line in the setup
}
bool processIMU()
{
byte linAccuracy = 0;
float quatRadianAccuracy = 0;
byte quatAccuracy = 0;
byte gyroAccuracy = 0;
if(newLinAcc) {
myIMU.getLinAccel(ax, ay, az, linAccuracy);
newLinAcc = 0; // mark data as read
new_imu_reports |= IMU_MASK_ACC;
}
if(newQuat) {
myIMU.getQuat(qx, qy, qz, qw, quatRadianAccuracy, quatAccuracy);
newQuat = 0; // mark data as read
new_imu_reports |= IMU_MASK_QUAT;
}
if(newGyro) {
myIMU.getGyro(gx, gy, gz, gyroAccuracy);
newGyro = 0; // mark data as read
new_imu_reports |= IMU_MASK_GYRO;
}
// only publish when all imu data were acquired new
if ((new_imu_reports & IMU_MASK_ALLNEWDATA) == IMU_MASK_ALLNEWDATA)
{
new_imu_reports = 0;
Serial.print(F("acc :"));
Serial.print(ax, 2);
Serial.print(F(","));
Serial.print(ay, 2);
Serial.print(F(","));
Serial.print(az, 2);
Serial.print(F(","));
Serial.print(az, 2);
Serial.print(F(","));
printAccuracyLevel(linAccuracy);
Serial.print(F("gyro:"));
Serial.print(gx, 2);
Serial.print(F(","));
Serial.print(gy, 2);
Serial.print(F(","));
Serial.print(gz, 2);
Serial.print(F(","));
printAccuracyLevel(gyroAccuracy);
Serial.print(F("quat:"));
Serial.print(qx, 2);
Serial.print(F(","));
Serial.print(qy, 2);
Serial.print(F(","));
Serial.print(qz, 2);
Serial.print(F(","));
Serial.print(qw, 2);
Serial.print(F(","));
printAccuracyLevel(quatAccuracy);
}
else
{
if(new_imu_reports != 0x0)
{
}
return false;
}
return true;
}
void loop() {
processIMU();
delay(5);
}
void imu_interrupt_handler()
{
//Look for reports from the IMU
switch (myIMU.getReadings())
{
case SENSOR_REPORTID_LINEAR_ACCELERATION: {
newLinAcc = 1;
}
break;
case SENSOR_REPORTID_GYROSCOPE: {
newGyro = 1;
}
break;
case SENSOR_REPORTID_ROTATION_VECTOR:
case SENSOR_REPORTID_GAME_ROTATION_VECTOR: {
newQuat = 1;
}
break;
case 0:
// no data
break;
default:
// Unhandled Input Report
break;
}
}
//Given an accuracy number, print what it means
void printAccuracyLevel(byte accuracyNumber)
{
if (accuracyNumber == 0) Serial.println(F("Unreliable"));
else if (accuracyNumber == 1) Serial.println(F("Low"));
else if (accuracyNumber == 2) Serial.println(F("Medium"));
else if (accuracyNumber == 3) Serial.println(F("High"));
}
thanks in advance for any advice. No urgency at all, and I am ready to test a lot to debug this.
We are currently going to use SPI0 + SPI1 but would prefer to use SPI1 and SPI2 and free the LED that was used in the past on Teensy 3.2 and our users liked being able to tell the status with the LED (was blinking differently in different mode of operation
best
Guillaume