Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 20 of 20

Thread: Teensy 4.0 and BNO08x on SPI2 hangs

  1. #1
    Junior Member
    Join Date
    Jan 2020
    Posts
    1

    Teensy 4.0 and BNO08x on SPI2 hangs

    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/59942...l=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/59942...PI-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/SP.../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
    Click image for larger version. 

Name:	SPI2_initfailed_5bytes_comments.jpg 
Views:	34 
Size:	66.2 KB 
ID:	22800

    SPI1 good initialization (as a comparison)
    Click image for larger version. 

Name:	SPI1_goodInit_comments.jpg 
Views:	33 
Size:	90.2 KB 
ID:	22801

    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

  2. #2
    Junior Member
    Join Date
    May 2021
    Posts
    9

    SPI2 problems at 150MHz, but not 600MHz, Teensy 4.0, Teensyduino 1.5.3

    I believe I have a similar issue, configuring and reading data from a PAA5100-JE optical flow sensor. On SPI0, I can choose any clock speed from 600MHz down to 150MHz (but not 24MHz). However, using SPI2 (soldered to the tiny pads underneath), I can only get the code working at 600MHz. A slower clock speed ends up in an hang during sensor configuration, but not always at the same line of code.

    I have tried different SPI clock speeds, from 100KHz to 2MHz. I have also tried different delays between CS and data transfers in the SPI initialisation sequence, also to no avail. Incidentally, I see the same behavior from the PWM3901, a chip in the same family. https://shop.pimoroni.com/?q=optical+flow

    My suspicion is that there is something different in the delay behavior or SPI clock between SPI0 and SPI2 on Teensy 4.0.

    Appreciate any pointers.


    Code:
    #include <Arduino.h>
    #include <PAA5100.h>
    
    const uint8_t R5_PIN_SPI_CS1 = 36;
    
    PAA5100 flowSensor1 = PAA5100(&SPI, R5_PIN_SPI_CS1);  // works at all speeds, 600MHz down to 150MHz.
    //PAA5100 flowSensor1 = PAA5100(&SPI2, R5_PIN_SPI_CS1); // only works at 600MHz.
    
    void setup() {
        
        Serial.begin(115200);
        Serial.println("Hello, world of OF");
        flowSensor1.begin();
    }
    
    void loop() {
      delay(1000);
      int16_t dxi, dyi;
      uint8_t squalFlow;
      flowSensor1.getMotion(&dxi, &dyi, &squalFlow);
      Serial.print("Sensor1: dX = ");
      Serial.print(dxi);
      Serial.print(", dY = ");
      Serial.print(dyi);
      Serial.print(", squal = ");
      Serial.println(squalFlow);
    
    }

    PAA5100.h

    Code:
    #ifndef __PAA5100_H__
    #define __PAA5100_H__
    
    #include "Arduino.h"
    #include <SPI.h>
    //#include <stdint.h>
    
    class PAA5100 {
    public:
      PAA5100(SPIClass* bus, uint8_t cspin);
      boolean begin(void);
      void disable();
      void enable();
    
      void readMotionCount(int16_t *deltaX, int16_t *deltaY);
      void readSignalQuality(uint8_t *squal);
        
      void getMotion(int16_t *deltaX, int16_t *deltaY, uint8_t *squal);
      void getMotionSlow(int16_t *deltaX, int16_t *deltaY, uint8_t *squal);
    
    private:
      uint8_t _cs;
      bool enabled = false;
        
      bool validateChip();
      SPISettings paa5100SPISettning = SPISettings(100000, MSBFIRST, SPI_MODE3);
      
      void registerWrite(uint8_t reg, uint8_t value);
      uint8_t registerRead(uint8_t reg);
      uint8_t  registerReadInternal(uint8_t reg);
        
      void initRegistersPAA5100JE(void);
      SPIClass* spi;
        
    };
    
    #endif //__PAA5100_H__
    PAA5100.cpp

    Code:
    #include "PAA5100.h"
    
    #define DEBUGPAA5100 1
    
    PAA5100::PAA5100(SPIClass* bus, uint8_t cspin)
    {
        spi = bus;
        _cs = cspin;
        pinMode(_cs, OUTPUT);
        digitalWriteFast(_cs, HIGH);
    }
    
    void PAA5100::enable() {
        enabled = true;
    }
    
    void PAA5100::disable() {
        enabled = false;
        digitalWriteFast(_cs, HIGH);
    }
    
    boolean PAA5100::begin(void) {
      spi->begin();
      spi->beginTransaction(paa5100SPISettning);
    
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 0");
    #endif
    
      // Make sure the SPI bus is reset
      digitalWriteFast(_cs, LOW);
      delay(1);
      digitalWriteFast(_cs, HIGH);
      spi->endTransaction();
        
      // Power on reset
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 02");
    #endif
      delay(1);
      registerWrite(0x3A, 0x5A);
      delay(5);
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 03");
    #endif
        
       // Test the SPI communication, checking chipId and inverse chipId
       if (validateChip()) {
            registerRead(0x02);
            registerRead(0x03);
            registerRead(0x04);
            registerRead(0x05);
            registerRead(0x06);
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 3");
    #endif
            delay(1);
            initRegistersPAA5100JE();
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 4");
    #endif
    
        }
        else return false;
        
      enable();
      return true;
    }
    
    bool PAA5100::validateChip() {
        
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 1");
    #endif
        
        uint8_t chipId = registerRead(0x00);
        uint8_t dIpihc = registerRead(0x5F);
    
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 2");
    #endif
        
        if (chipId != 0x49 && dIpihc != 0xB8) {
            Serial.print("Optical flow sensor initialization error: chip ID =");
            Serial.print(chipId);
            Serial.print(", dIpihc ID =");
            Serial.println(dIpihc);
            return false;
        }
        else {
            return true;
        }
    }
    
    // Functional access
    
    void PAA5100::readMotionCount(int16_t *deltaX, int16_t *deltaY)
    {
      registerRead(0x02);
      *deltaX = ((int16_t)registerRead(0x04) << 8) | registerRead(0x03);
      *deltaY = ((int16_t)registerRead(0x06) << 8) | registerRead(0x05);
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 5");
    #endif
    }
    
    void PAA5100::readSignalQuality(uint8_t *squal)
    {
      *squal = (uint8_t)registerRead(0x07);
    }
    
    void PAA5100::getMotionSlow(int16_t *deltaX, int16_t *deltaY, uint8_t *squal) {
        registerRead(0x02);
        *deltaX = ((int16_t)registerRead(0x04) << 8) | registerRead(0x03);
        *deltaY = ((int16_t)registerRead(0x06) << 8) | registerRead(0x05);
        *squal = (uint8_t)registerRead(0x07);
    }
    
    void PAA5100::getMotion(int16_t *deltaX, int16_t *deltaY, uint8_t *squal) {
        if (enabled) {
            spi->beginTransaction(paa5100SPISettning);
            digitalWriteFast(_cs, LOW);
            //delayMicroseconds(2);
            delayNanoseconds(200);
            
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 6");
    #endif
    
            registerReadInternal(0x02);
            *deltaX = ((int16_t)registerReadInternal(0x04) << 8) | registerReadInternal(0x03);
            *deltaY = ((int16_t)registerReadInternal(0x06) << 8) | registerReadInternal(0x05);
            *squal = (uint8_t)registerReadInternal(0x07);
            //delayMicroseconds(2);
            delayNanoseconds(200);
            
    #ifdef DEBUGPAA5100
        Serial.println("Debug point 7");
    #endif
    
            digitalWriteFast(_cs, HIGH);
            spi->endTransaction();
        }
        else {
            *deltaX = 0;
            *deltaY = 0;
            *squal = 0;
        }
    }
    
    // Low level register access
    void PAA5100::registerWrite(uint8_t reg, uint8_t value) {
      reg |= 0x80u;
    
      spi->beginTransaction(paa5100SPISettning);
      digitalWriteFast(_cs, LOW);
      delayMicroseconds(2);
    #ifdef DEBUGPAA5100
        Serial.println("Debug point registerWrite 1");
    #endif
      spi->transfer(reg);
    #ifdef DEBUGPAA5100
        Serial.println("Debug point registerWrite 2");
    #endif
      spi->transfer(value);
    #ifdef DEBUGPAA5100
        Serial.println("Debug point registerWrite 3");
    #endif
      //delayMicroseconds(2);
      delayNanoseconds(200);
      digitalWriteFast(_cs, HIGH);
      spi->endTransaction();
    #ifdef DEBUGPAA5100
        Serial.println("Debug point registerWrite 4");
    #endif
    }
    
    uint8_t PAA5100::registerReadInternal(uint8_t reg) {
        reg &= ~0x80u;
        spi->transfer(reg);
        uint8_t value = spi->transfer(0);
        return value;
    }
    
    uint8_t PAA5100::registerRead(uint8_t reg) {
      reg &= ~0x80u;
    
      spi->beginTransaction(paa5100SPISettning);
      digitalWriteFast(_cs, LOW);
      delayNanoseconds(200);
      //delayMicroseconds(2);
      spi->transfer(reg);
      uint8_t value = spi->transfer(0);
      //delayMicroseconds(2);
      delayNanoseconds(200);
      digitalWriteFast(_cs, HIGH);
    
      spi->endTransaction();
      return value;
    }
    
    void PAA5100::initRegistersPAA5100JE()
    {
        registerWrite(0x7f, 0x00);
        registerWrite(0x55, 0x01);
        registerWrite(0x50, 0x07);
        registerWrite(0x7f, 0x0e);
        registerWrite(0x43, 0x10);
        
        if(registerRead(0x67) & 0b10000000) registerWrite(0x48, 0x04);
        else registerWrite(0x48, 0x02);
        
        registerWrite(0x7f, 0x00);
        registerWrite(0x51, 0x7b);
        registerWrite(0x50, 0x00);
        registerWrite(0x55, 0x00);
        registerWrite(0x7f, 0x0e);
        
        
        if(registerRead(0x73) == 0x00)  {
            uint8_t c1 = registerRead(0x70);
            uint8_t c2 = registerRead(0x71);
            if(c1 <= 28) c1 += 14;
            if(c1 > 28) c1 += 11;
            c1 = max(0,min(0x3F, c1));
            c2 = (c2 * 45);
            
            registerWrite(0x7f, 0x00);
            registerWrite(0x61, 0xad);
            registerWrite(0x51, 0x70);
            registerWrite(0x7f, 0x0e);
            
            registerWrite(0x70, c1);
            registerWrite(0x71, c2);
        }
        
        
        registerWrite(0x7f, 0x00);
        registerWrite(0x61, 0xad);
        registerWrite(0x7f, 0x03);
        registerWrite(0x40, 0x00);
        registerWrite(0x7f, 0x05);
        registerWrite(0x41, 0xb3);
        registerWrite(0x43, 0xf1);
        registerWrite(0x45, 0x14);
        registerWrite(0x5f, 0x34);
        registerWrite(0x7b, 0x08);
        registerWrite(0x5e, 0x34);
        registerWrite(0x5b, 0x11);
        registerWrite(0x6d, 0x11);
        registerWrite(0x45, 0x17);
        registerWrite(0x70, 0xe5);
        registerWrite(0x71, 0xe5);
        registerWrite(0x7f, 0x06);
        registerWrite(0x44, 0x1b);
        registerWrite(0x40, 0xbf);
        registerWrite(0x4e, 0x3f);
        registerWrite(0x7f, 0x08);
        registerWrite(0x66, 0x44);
        registerWrite(0x65, 0x20);
        registerWrite(0x6a, 0x3a);
        registerWrite(0x61, 0x05);
        registerWrite(0x62, 0x05);
        registerWrite(0x7f, 0x09);
        registerWrite(0x4f, 0xaf);
        registerWrite(0x5f, 0x40);
        registerWrite(0x48, 0x80);
        registerWrite(0x49, 0x80);
        registerWrite(0x57, 0x77);
        registerWrite(0x60, 0x78);
        registerWrite(0x61, 0x78);
        registerWrite(0x62, 0x08);
        registerWrite(0x63, 0x50);
        registerWrite(0x7f, 0x0a);
        registerWrite(0x45, 0x60);
        registerWrite(0x7f, 0x00);
        registerWrite(0x4d, 0x11);
        registerWrite(0x55, 0x80);
        registerWrite(0x74, 0x21);
        registerWrite(0x75, 0x1f);
        registerWrite(0x4a, 0x78);
        registerWrite(0x4b, 0x78);
        registerWrite(0x44, 0x08);
        registerWrite(0x45, 0x50);
        registerWrite(0x64, 0xff);
        registerWrite(0x65, 0x1f);
        registerWrite(0x7f, 0x14);
        registerWrite(0x65, 0x67);
        registerWrite(0x66, 0x08);
        registerWrite(0x63, 0x70);
        registerWrite(0x6f, 0x1c);
        registerWrite(0x7f, 0x15);
        registerWrite(0x48, 0x48);
        registerWrite(0x7f, 0x07);
        registerWrite(0x41, 0x0d);
        registerWrite(0x43, 0x14);
        registerWrite(0x4b, 0x0e);
        registerWrite(0x45, 0x0f);
        registerWrite(0x44, 0x42);
        registerWrite(0x4c, 0x80);
        registerWrite(0x7f, 0x10);
        registerWrite(0x5b, 0x02);
        registerWrite(0x7f, 0x07);
        registerWrite(0x40, 0x41);
    
        delay(10);
        registerWrite(0x7f, 0x00);
        registerWrite(0x32, 0x00);
        registerWrite(0x7f, 0x07);
        registerWrite(0x40, 0x40);
        registerWrite(0x7f, 0x06);
        registerWrite(0x68, 0xf0);
        registerWrite(0x69, 0x00);
        registerWrite(0x7f, 0x0d);
        registerWrite(0x48, 0xc0);
        registerWrite(0x6f, 0xd5);
        registerWrite(0x7f, 0x00);
        registerWrite(0x5b, 0xa0);
        registerWrite(0x4e, 0xa8);
        registerWrite(0x5a, 0x90);
        registerWrite(0x40, 0x80);
        registerWrite(0x73, 0x1f);
    
        delay(10);
        registerWrite(0x73, 0x00);
    }

  3. #3
    Junior Member
    Join Date
    May 2021
    Posts
    9

    SPI2 problems at 150MHz, but not 600MHz, Teensy 4.0, Teensyduino 1.5.3

    Simpler code to replicate. At 150MHz, Teensy hangs on first transfer. In setup(), at line registerWrite(0x3A, 0x5A);

    Code:
    #include <Arduino.h>
    #include <SPI.h>
    
    SPISettings paa5100SPISetting = SPISettings(100000, MSBFIRST, SPI_MODE3);
    const uint8_t R5_PIN_SPI_CS1 = 36;
    
    void setup() {
        
        Serial.begin(115200);
        Serial.println("Hello, world of OF");
        
        pinMode(R5_PIN_SPI_CS1, OUTPUT);
        digitalWriteFast(R5_PIN_SPI_CS1, HIGH);
        delay(50);
        SPI2.begin();
    
        SPI2.beginTransaction(paa5100SPISetting);
        digitalWriteFast(R5_PIN_SPI_CS1, LOW);
        delay(1);
        digitalWriteFast(R5_PIN_SPI_CS1, HIGH);
        SPI2.endTransaction();
        delay(1);
        registerWrite(0x3A, 0x5A);
        delay(5);
        Serial.println("Init done");
        validateChip();
    }
    
    
    
    void loop() {
      delay(2000);
      int16_t x, y;
      readMotionCount(&x, &y);
      Serial.print("dX = ");
      Serial.print(x);
      Serial.print(", dY = ");
      Serial.println(y);
    }
    
    void readMotionCount(int16_t *deltaX, int16_t *deltaY)
    {
      registerRead(0x02);
      *deltaX = ((int16_t)registerRead(0x04) << 8) | registerRead(0x03);
      *deltaY = ((int16_t)registerRead(0x06) << 8) | registerRead(0x05);
    }
    
    bool validateChip() {
        uint8_t chipId = registerRead(0x00);
        Serial.println("Read 0x00");
        uint8_t dIpihc = registerRead(0x5F);
        Serial.println("Read 0x55");
    
        if (chipId != 0x49 && dIpihc != 0xB8) {
            Serial.print("Optical flow sensor initialization error: chip ID =");
            Serial.print(chipId);
            Serial.print(", dIpihc ID =");
            Serial.println(dIpihc);
            return false;
        }
        else {
            Serial.println("Chip validated OK");
            return true;
        }
    }
    
    void registerWrite(uint8_t reg, uint8_t value) {
      reg |= 0x80u;
      SPI2.beginTransaction(paa5100SPISetting);
      digitalWriteFast(R5_PIN_SPI_CS1, LOW);
      Serial.println("Write - CS");
      delayMicroseconds(2);
      Serial.println("Write - trf2 pre");
      SPI2.transfer(reg);
      Serial.println("Write - trf1");
      SPI2.transfer(value);
      Serial.println("Write - trf2");
      delayMicroseconds(2);
      digitalWriteFast(R5_PIN_SPI_CS1, HIGH);
      SPI2.endTransaction();
    }
    
    uint8_t registerRead(uint8_t reg) {
      reg &= ~0x80u;
    
      SPI2.beginTransaction(paa5100SPISetting);
      digitalWriteFast(R5_PIN_SPI_CS1, LOW);
      Serial.println("Read - CS");
      delayMicroseconds(2);
      SPI2.transfer(reg);
      Serial.println("Read - trf1");
      uint8_t value = SPI2.transfer(0);
      Serial.println("Read - trf2");
      delayMicroseconds(2);
      digitalWriteFast(R5_PIN_SPI_CS1, HIGH);
      SPI2.endTransaction();
      return value;
    }

  4. #4
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    9,117
    Sorry, I am not seeing anything obvious in my first look through. For example I did not see anywhere where you still had a hard coded reference to the main SPI object or any reference
    to internal registers.

    And the only really main differences between SPI and SPI2 is
    SPI uses the hardware LPSPI4 and the SPI2 object uses the hardware LPSPI1
    And of course changes for different set of PINS...

    The only other things I noticed is that your choosen CS pin is also actually a hardware CS pin for SPi2... but I am pretty sure you don't use it that way.

    Also that your constructor for the object: does hardware configuration: pinMode(_cs, OUTPUT); digitalWriteFast(_cs, HIGH);
    In this case not sure digitalWriteFast is much/any faster than digitalWrite as the pin number is not a constant, but a member variable... Could be wrong.
    But main thing is I typically try to avoid touching the hardware during constructors as I am never fully sure when those calls will be called versus when the system has fully initialized the underlying hardware...

    So long shot, try moving those to the begin method to see if anything changes...

    Also in cases like this I would always check to make sure you have Pull up registers on things like MISO pin and maybe SCK...

  5. #5
    Junior Member
    Join Date
    May 2021
    Posts
    9
    Thanks for looking at this...

    Since SPI0 works as expected, I have now switched to just SPI2 for testing..
    - Now testing with the second set of code, where hardware config is in begin(), so initialization sequence should be ok
    - I moved the CS pin to Pin 9. Just to eliminate things. No change in behavior
    - put 18K pullups on MISO & SCK. No change in behavior
    - what I notice is that at 150mHz, Teensy hangs in the first transfer() call. At higher clock speeds, it seems to get further, hanging 1-2 calls later. Only at 600MHz does it run properly. Also works ok at 720MHz.
    Last edited by rohitas; 05-29-2021 at 02:28 PM.

  6. #6
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,030
    @guihome
    Out of curiosity how are you getting access to SPI2 on the Teensy 4.0 since they are associated with the SD card pins on the underside of the board and not brought out to the edge like on the Teensy 4.1? Maybe something with your wiring to SPI2?

  7. #7
    Junior Member
    Join Date
    May 2021
    Posts
    9
    Well, I soldered wires to pins on the underside. They look ok enough, even if the soldering was a bit tough. Plus they work just fine at 600Mhz..

  8. #8
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,030
    Quote Originally Posted by rohitas View Post
    Well, I soldered wires to pins on the underside. They look ok enough, even if the soldering was a bit tough. Plus they work just fine at 600Mhz..
    Sorry for the late response but I had to ask. Since not planning on soldering those little wires (I did that once to get access to the FLASH pins on the under side so..) but tomorrow I have an adapter that I can slip into the SD card socket to do some debugging. But that will be tomorrow. As you said not sure if its a pin configuration issue or a clocking issue.

    Just to double check you check SPI or SPI1 at 150Mhz as well?

  9. #9
    Junior Member
    Join Date
    May 2021
    Posts
    9
    Quote Originally Posted by mjs513 View Post
    Just to double check you check SPI or SPI1 at 150Mhz as well?
    SPI works at 150MHz. Have not tested SPI1.

  10. #10
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,030
    @rohitas
    Well using a SparkFun microSD Sniffer I hooked up the Sparkfun BNO080 and using a slightly modified sketch you posted - using SPI2 as default and CS as pin 36:
    Code:
    #include <SPI.h>  // include the new SPI library:
    #include <SparkFun_BNO080_Arduino_Library.h>
    
    BNO080 myIMU;
    
    #define EXT_USES_SPI2
             
    #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;
    byte imuWAKPin = 9;
    byte imuINTPin = 8;
    byte imuRSTPin = 7;
    
    // 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"));
    }
    I can confirm that at any T4 clock speed less than 600Mhz it hangs after it does some output - here is the sermon data at 150Mhz which will coresspond to the LA trace I will post:
    Code:
    SPI Wait
    Header: 14 00 02 00 Body: F1 00 84 00 00 00 01 00 00 00 00 00 00 00 00 00 Length:20 Channel:Control
    SPI Wait
    SPI Wait
    Header: 14 00 02 01 Body: F8 04 03 02 98 A4 98 00 72 01 00 00 07 00 00 00 Length:20 Channel:Control
    SW Version Major: 0x3 SW Version Minor: 0x2 SW Part Number: 0x98A498 SW Build Number: 0x172 SW Version Patch: 0x7
    start IMU requested
    SPI Wait
    SPI Wait
    SPI Wait
    Header: 15 00 02 05 Body: FC 02 00 00 00 20 4E 00 00 00 00 00 00 00 00 00 00 Length:21 Channel:Control
    Header: 15 00 02 06 Body: FC 05 00 00 00 20 4E 00 00 00 00 00 00 00 00 00 00 Length:21 Channel:Control
    Header: 15 00 02 07 Body: FC 04 00 00 00 20 4E 00 00 00 00 00 00 00 00 00 00 Length:21 Channel:Control
    Header: 13 00 03 00 Body: FB 15 00 00 00 02 00 00 00 FF FF 01 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 01 Body: FB 19 00 00 00 05 00 00 00 1E 00 0D 00 5E E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 02 Body: FB 24 00 00 00 04 00 03 00 00 00 00 00 00 00 Length:19 Channel:Sensor-report
    acc :0.00,0.00,0.00,0.00,High
    gyro:-0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 03 Body: FB 17 00 00 00 02 01 00 00 01 00 00 00 01 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 04 Body: FB 1B 00 00 00 05 01 00 00 1F 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 05 Body: FB 26 00 00 00 04 01 03 00 00 00 00 00 0A 00 Length:19 Channel:Sensor-report
    acc :0.00,0.00,0.04,0.04,High
    gyro:0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 06 Body: FB 17 00 00 00 02 02 00 00 FF FF 00 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 07 Body: FB 1B 00 00 00 05 02 00 00 1F 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 08 Body: FB 2B 00 00 00 04 02 03 00 00 00 00 00 0A 00 Length:19 Channel:Sensor-report
    acc :0.00,0.00,0.04,0.04,High
    gyro:-0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 09 Body: FB 17 00 00 00 02 03 00 00 FE FF FF FF FF FF Length:19 Channel:Sensor-report
    Header: 17 00 03 0A Body: FB 1B 00 00 00 05 03 00 00 1E 00 0E 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 0B Body: FB 26 00 00 00 04 03 03 00 00 00 0A 00 0A 00 Length:19 Channel:Sensor-report
    acc :0.00,0.04,0.04,0.04,High
    gyro:-0.00,-0.00,-0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 0C Body: FB 17 00 00 00 02 04 00 00 00 00 FE FF 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 0D Body: FB 1B 00 00 00 05 04 00 00 1E 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 0E Body: FB 26 00 00 00 04 04 03 00 00 00 0A 00 FE FF Length:19 Channel:Sensor-report
    acc :0.00,0.04,-0.01,-0.01,High
    gyro:0.00,-0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 0F Body: FB 17 00 00 00 02 05 00 00 FF FF 00 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 10 Body: FB 1B 00 00 00 05 05 00 00 1E 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 11 Body: FB 26 00 00 00 04 05 03 00 00 00 00 00 FE FF Length:19 Channel:Sensor-report
    acc :0.00,0.00,-0.01,-0.01,High
    gyro:-0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 12 Body: FB 17 00 00 00 02 06 00 00 FF FF 00 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 13 Body: FB 1B 00 00 00 05 06 00 00 1E 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 14 Body: FB 2F 00 00 00 04 06 03 00 00 00 00 00 08 00 Length:19 Channel:Sensor-report
    acc :0.00,0.00,0.03,0.03,High
    gyro:-0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 15 Body: FB 17 00 00 00 02 07 00 00 00 00 FF FF FF FF Length:19 Channel:Sensor-report
    Header: 17 00 03 16 Body: FB 1D 00 00 00 05 07 00 00 1E 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 17 Body: FB 28 00 00 00 04 07 03 00 F6 FF 00 00 FE FF Length:19 Channel:Sensor-report
    acc :-0.04,0.00,-0.01,-0.01,High
    gyro:0.00,-0.00,-0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 18 Body: FB 17 00 00 00 02 08 00 00 01 00 01 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 19 Body: FB 1B 00 00 00 05 08 00 00 1E 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 1A Body: FB 26 00 00 00 04 08 03 00 F6 FF FE FF FE FF Length:19 Channel:Sensor-report
    acc :-0.04,-0.01,-0.01,-0.01,High
    gyro:0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 1B Body: FB 17 00 00 00 02 09 00 00 01 00 01 00 FF FF Length:19 Channel:Sensor-report
    Header: 17 00 03 1C Body: FB 1B 00 00 00 05 09 00 00 1E 00 0D 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 1D Body: FB 26 00 00 00 04 09 03 00 00 00 FE FF FE FF Length:19 Channel:Sensor-report
    acc :0.00,-0.01,-0.01,-0.01,High
    gyro:0.00,0.00,-0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 1E Body: FB 19 00 00 00 02 0A 00 00 FF FF 01 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 1F Body: FB 1F 00 00 00 05 0A 00 00 1E 00 0E 00 5E E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 20 Body: FB 2F 00 00 00 04 0A 03 00 F6 FF FE FF 08 00 Length:19 Channel:Sensor-report
    acc :-0.04,-0.01,0.03,0.03,High
    gyro:-0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 21 Body: FB 17 00 00 00 02 0B 00 00 01 00 FF FF 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 22 Body: FB 1B 00 00 00 05 0B 00 00 1F 00 0D 00 5E E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 23 Body: FB 26 00 00 00 04 0B 03 00 02 00 FE FF 08 00 Length:19 Channel:Sensor-report
    acc :0.01,-0.01,0.03,0.03,High
    gyro:0.00,-0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 24 Body: FB 19 00 00 00 02 0C 00 00 01 00 01 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 25 Body: FB 1D 00 00 00 05 0C 00 00 1F 00 0E 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 26 Body: FB 28 00 00 00 04 0C 03 00 02 00 FE FF 08 00 Length:19 Channel:Sensor-report
    acc :0.01,-0.01,0.03,0.03,High
    gyro:0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 27 Body: FB 15 00 00 00 02 0D 00 00 00 00 00 00 FF FF Length:19 Channel:Sensor-report
    Header: 17 00 03 28 Body: FB 1B 00 00 00 05 0D 00 00 1F 00 0E 00 5E E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 29 Body: FB 26 00 00 00 04 0D 03 00 02 00 FE FF FC FF Length:19 Channel:Sensor-report
    acc :0.01,-0.01,-0.02,-0.02,High
    gyro:0.00,0.00,-0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 2A Body: FB 1B 00 00 00 02 0E 00 00 01 00 00 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 2B Body: FB 20 00 00 00 05 0E 00 00 1F 00 0E 00 5E E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 2C Body: FB 2F 00 00 00 04 0E 03 00 02 00 08 00 06 00 Length:19 Channel:Sensor-report
    acc :0.01,0.03,0.02,0.02,High
    gyro:0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 2D Body: FB 19 00 00 00 02 0F 00 00 00 00 01 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 2E Body: FB 1D 00 00 00 05 0F 00 00 1F 00 0E 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 2F Body: FB 28 00 00 00 04 0F 03 00 00 00 FE FF FA FF Length:19 Channel:Sensor-report
    acc :0.00,-0.01,-0.02,-0.02,High
    gyro:0.00,0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 30 Body: FB 17 00 00 00 02 10 00 00 00 00 FF FF FF FF Length:19 Channel:Sensor-report
    Header: 17 00 03 31 Body: FB 1B 00 00 00 05 10 00 00 1F 00 0E 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 32 Body: FB 26 00 00 00 04 10 03 00 00 00 FE FF 04 00 Length:19 Channel:Sensor-report
    acc :0.00,-0.01,0.02,0.02,High
    gyro:0.00,-0.00,-0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 33 Body: FB 19 00 00 00 02 11 00 00 FF FF FF FF 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 34 Body: FB 1D 00 00 00 05 11 00 00 1F 00 0E 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    Header: 13 00 03 35 Body: FB 28 00 00 00 04 11 03 00 00 00 FE FF 04 00 Length:19 Channel:Sensor-report
    acc :0.00,-0.01,0.02,0.02,High
    gyro:-0.00,-0.00,0.00,Unreliable
    quat:0.00,0.00,-0.49,0.87,Unreliable
    Header: 13 00 03 36 Body: FB 1B 00 00 00 02 12 00 00 FF FF 00 00 00 00 Length:19 Channel:Sensor-report
    Header: 17 00 03 37 Body: FB 20 00 00 00 05 12 00 00 1F 00 0E 00 5F E0 A3 37 44 32 Length:23 Channel:Sensor-report
    stops at this point. The LA bears it out:
    Click image for larger version. 

Name:	Capture.jpg 
Views:	17 
Size:	29.9 KB 
ID:	24946

    Why this is happening I can't say, I can look but not sure I will find the cause but who knows. First step is see if its SPI2 or somthing with the BNO080.

  11. #11
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,796
    I am just gonna throw this here since it is similar to my experience in CAN with Teensy 4.0 quite a few months back when I installed it in my car. It is connected to 2 busses, 125kbps, and 500kbps. Think of them as different SPI bitrates on a different SPI port... Did you experience a hard lockup? I did. At first I thought it was wrong bitrate for the car, then realized, if that was true, the BCAN didn't crash or light the dash like a christmas tree.... Then I see the loop() didn't work and teensy required button to program.. It turned out that CAN2(125kbps) didnt like a osc clock at 24MHz at that rate (125kbps). When I switched the peripheral clock to 60MHz it was running great after, and still is, 24/7 since... I havn't tried to change port for testing as maybe that is CAN2 hardware related but can't confirm that and I don't want to rewire my setup either, but maybe the clock settings used by the SPI bus devices may be something to look at? Did you also try SPI2 with 600MHz cpu to see if that works as the clock gate is based off that?

    SPI2 problems at 150MHz, but not 600MHz, Teensy 4.0, Teensyduino 1.5.3
    Just read that it works at 600MHz, I would check the SPI clock gate at this point and check how the SPI bitrate is calculated off it and if it can be changed. When I added clock support for CAN I allowed it to not only change the clock but re-calculate the bitrate off the new setting. I don't know if SPI sets up the clock but the calculation of speed has to be based off the current one (or if changed) based on cpu clock of 150MHz

  12. #12
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    9,117
    I know I have some BNO080 around in my electronics hoarding mess here :lol: But may take awhile to do enough of an archeological dig to find one.

    The interesting thing is I don't know of any fundamental difference between SPI and SPI2 other than which LPSPI object is used and obviously which IO pins.

    So throwing up darts that if I were to set it up that I might try to look at include:

    a) Do the pulse widths look the same from SPI and SPI2? Both at 600mhz and 150MHZ? They should as they both use same settings in the clock tree.

    b) Does startup code do anything different on these pins as they are SD cards? don't think so.

    c) again back to clock speed: SPI we initialize the clock to use settings:

    Code:
    void SPIClass::begin()
    {
    
    	// CBCMR[LPSPI_CLK_SEL] - PLL2 = 528 MHz
    	// CBCMR[LPSPI_PODF] - div4 = 132 MHz
    
    
    	hardware().clock_gate_register &= ~hardware().clock_gate_mask;
    
    	CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK)) |
    		CCM_CBCMR_LPSPI_PODF(2) | CCM_CBCMR_LPSPI_CLK_SEL(1); // pg 714
    //		CCM_CBCMR_LPSPI_PODF(6) | CCM_CBCMR_LPSPI_CLK_SEL(2); // pg 714
    So we are using CCM_CBCMR_LPSPI_CLK_SEL(1) which is: PLL3 PFD0
    And CCM_CBCMR_LPSPI_PODF(2)

    So this is a clock speed of: 720000000/3 = 240mhz - wondering if having SPI clock speed faster than CPU could be an issue?
    Maybe puts the timing right on the edge of something. Again no idea...
    But wonder if maybe one changes: these settings to something slower will it work?
    Like earlier we had: the commented out one translates to:
    528000000/7 = 75.428mhz? Why this setting not sure.
    But might try something like: CCM_CBCMR_LPSPI_PODF(5) | CCM_CBCMR_LPSPI_CLK_SEL(1); // pg 714
    720000000/6= 120mhz and see what happens?

    d) Interrupts? I don't see anywhere we use interrupts in SPI? so don't think so, but???

  13. #13
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    9,117
    Follow on to previous post, in case I was not very clear (likely)

    In the code like: try:
    Code:
    #ifdef EXT_USES_SPI2
      Serial.println("setting up SPI2");
      //SPI2.setMOSI(imuCOPIPin);
      //SPI2.setMISO(imuCIPOPin);
      //SPI2.setSCK(imuSCKPin);
      // initialize SPI2:
      SPI2.begin();
      CCM_CBCMR = (CCM_CBCMR & ~(CCM_CBCMR_LPSPI_PODF_MASK | CCM_CBCMR_LPSPI_CLK_SEL_MASK)) |
    		CCM_CBCMR_LPSPI_PODF(5) | CCM_CBCMR_LPSPI_CLK_SEL(1); // pg 714
    #endif
    The SPI.beginTransaction code is setup to look st the CCM_CBCMR register and compute the underlying SPI speed that is then used to set the other registers.

    OOPS - actually that may not work, as the BNO080::beginSPI(
    call does it's own call: _spiPort->begin(); //Turn on SPI hardware
    Which will reset it... And then goes on to use it which then probably fails.

    Wonder if maybe SPI should be setup that if begin is called and end has not been called that some things are not reiniitialized?

  14. #14
    Junior Member
    Join Date
    May 2021
    Posts
    9
    ok, so I added the change suggested by @KurtE after SPI2.begin() and, yes, indeed I got it to work at 150mHz!

    Even works at 24MHz, something that didn't work on SPI0. (NB: I am using a PMW3901 target, not the BNO080)

  15. #15
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,030
    @tonton81 and @KurtE

    Was thinking that it could the clock settings as well.

    @KurtE - yep understood what you saying, I think, thanks for code snippet made it easier since I am feeling a bit under the weather today

    Anyway I tried it with one setup using that Ultimate board that you screw down the T4 but after after the clock change still seemed to hang so decided to take the setup and move it to the original PJRC Breakout for the T4.0:
    Click image for larger version. 

Name:	IMG-0378.png 
Views:	14 
Size:	564.8 KB 
ID:	24947

    but had to change the pins to:
    Code:
    //GPIO pins for SPI2 on teensy4.0
    const byte imuCSPin = 36;
    byte imuWAKPin = 0;
    byte imuINTPin = 7;
    byte imuRSTPin = 1;
    So retested SPI2 with and without your clock change and surprisingly (maybe not so much) BNO080 data started streaming without an issue. So went back and retested on that other board and it failed so must be something with that other board.

    Now for the fun of it I moved the whole setup to T4.1 (cspin = 44) and it worked at 600 and 150Mhz no issues.

  16. #16
    Junior Member
    Join Date
    May 2021
    Posts
    9
    @mjs513 I didnt fully catch your last post. Did you mean to say that you got one of your BNO080s to work as-is at 150MHz on T4.0, and that the problem was in one of the test boards? Or were there 2 separate issues?

    Out of curiosity, are there any pullups on MISO on the setup you have?

    In my project (not the debug set up I describe in this thread), I have 2 identical sensors on SPI2. No pullups. In this 2-sensor case, the fix suggested by KurtE did not do the trick (could well be something else also, it was just a quick test I ran). It did work in the simpler setup with one PMW3901 - where I do have pullups on MISO & SCK.

  17. #17
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    7,030
    Quote Originally Posted by rohitas View Post
    @mjs513 I didnt fully catch your last post. Did you mean to say that you got one of your BNO080s to work as-is at 150MHz on T4.0, and that the problem was in one of the test boards? Or were there 2 separate issues?

    Out of curiosity, are there any pullups on MISO on the setup you have?

    In my project (not the debug set up I describe in this thread), I have 2 identical sensors on SPI2. No pullups. In this 2-sensor case, the fix suggested by KurtE did not do the trick (could well be something else also, it was just a quick test I ran). It did work in the simpler setup with one PMW3901 - where I do have pullups on MISO & SCK.
    That is correct. The problem was an issue with the breakout board I was using so I switch to this board":https://www.pjrc.com/breakout-board-for-teensy-4-0/ and it worked both at 600Mhz and 150Mhz. As far I can see there are no pullups on the breakout board and I did not add any as you can see from the picture.

    Just a quick question, since you have 2 same sensors on SPI2 did you remember to change the address of the second one and use a different chip select pin. You might want to check the wiring. I can not test a dual sensor but you may just want to test with one sensor attached as a double check. Just as a note, on the problem breakout board it worked at 600Mhz and not at 150Mhz. On the problem breakout I think the connection between the T4 and board is a problem.

  18. #18
    Junior Member
    Join Date
    May 2021
    Posts
    9
    Yes, two different chip selects. I control them both from the same place in the codebase, so shouldn't be a bus conflict between them either. I will do some more playing around with the full project set-up over the next days. Removing one sensor etc, adding pullups etc. Maybe I can also try with some delays between calls to 2 sensors in case that is messing something up.

    Still surprised why something should work at a higher clock speed and not a lower one? If anything, one would assume the opposite. And why would @KurtE's suggested fix work on the same hardware..

    I get the same problem with 2 different breakouts from Pixart - the PMW3901 and the PAA5100JE..

  19. #19
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,796
    Code:
    Still surprised why something should work at a higher clock speed and not a lower one?
    all the gate clocks can be affected by cpu speed changes, even peripherals. Usually lowering their gate clock allows the bus (in this case, SPI) to function although possibly lowering their max supported communication speed.

    if you're designing something that includes dynamic cpu speed or throttling, you need to make the necessary hardware adjust to the current clock so it functions at that speed

  20. #20
    Junior Member
    Join Date
    May 2021
    Posts
    9
    @tonton81 - Thanks! Makes sense.

    I got errors when debugging yesterday in my project as a subsequent call on SPI ( an SPI0.begin() for the other bus) re-initalized the gate frequency.

    I have modified a local copy of SPI.cpp and reduced clock gate frequency to 120MHz. I get ok behavior in all configurations - 2 sensors and everything! So that was most likely it.

    Thanks @KurtE @mjs513 and @tonton81 for the help, sincerely appreciated!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •