Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 3 1 2 3 LastLast
Results 1 to 25 of 59

Thread: Teensy 4.1 and 2 x MAX31855 thermocouples SPI problem

Hybrid View

  1. #1

    Teensy 4.1 and 2 x MAX31855 thermocouples SPI problem

    Hello everyone.
    I have a Teensy 4.1 connected to an 4.2" oled and a few sensors. Among the sensors I want to connect to the SPI bus two MAX31855 thermocouples for measuring temperature.
    I have designed a PCB on which all the parts fit. When I solder just one of the MAX31855 ICs everything works great. The temperature is read and displayed on the oled without any problems.
    But when I solder both the MAX31855 ICs on the PCB, the SPI bus (I *think* it is the SPI) is having some weird issues. The oled begins to display glitches (random lines or dots on the screen, the data displayed begins to move around) and even sometimes the SPI bus stops working (the oled is all black and the SCK pin 13 on the Teensy stops blinking). I think the SPI bus is somehow affected because I also have a NRF24L01+ module connected to SPI and when the glitches appear the module stops working.

    Here is what I tested so far:
    -The glitches appear only when both the MAX31855 ICs are soldered on the PCB
    -It is not a PCB issue. (Both the ICs work just fine when soldered just one at a time in either of the PCB footprints.)
    -Both the CS pins of the MAX31855 ICs have separate pull-up resistors.
    -Software is not the issue because the glitches appear even when the Teensy is coded just to turn on the oled and display something, without any code/library for the MAX31855 IC. And the temperature is shown correctly when only one of the ICs is soldered.

    If you need to see the layout of the PCB you can find a copy of my project here.

    Could anyone tell me why this happens? What could I do in order to be able to use both the MAX31855 ICs?

    Thank you very much for your input.

  2. #2
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Sounds indeed like a collision on the SPI bus.
    Are you sure you drive both CS-t1 and CS-t2 individually in software?
    If you have a 2-channel oscilloscope you could check both these CS's for overlap.

    Paul

  3. #3
    Quote Originally Posted by PaulS View Post
    Sounds indeed like a collision on the SPI bus.
    Are you sure you drive both CS-t1 and CS-t2 individually in software?
    If you have a 2-channel oscilloscope you could check both these CS's for overlap.

    Paul
    I am pretty sure the CS-t1 and CS-t2 are handled properly. I say this because the glitches appear even if the software for the second MAX31855 IC is all commented out (the second IC is just physically soldered to the PCB without being used in any way)
    I am sorry but I do not have an oscilloscope.
    I am using the Adafruit MAX31855 library if this is of any help. But again, the problem appears even if no software is written for the second MAX31855 IC (just the CS pin digitalWritten HIGH).

    What else could it be? I am running out of ideas on how to fix this.

    Thank you.

  4. #4
    Senior Member
    Join Date
    Dec 2014
    Posts
    310
    Can you verify with a DMM (preferably an oscilloscope) that the CS lines stay high? This certainly sounds like bus collision!
    The only other hardware issue I can think of, is that the MAX31855 isn't tri-stating the SPI lines (ie, it's pulling the lines high or low). With only the one IC, you get away with it, but with two, the problem is bad enough to cause other issues.
    Do you have access to an oscilloscope?

    Can you please provide the code that replicates the issue?

  5. #5
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    There maybe an issue with the Adafruit MAX31855 library, see this page.
    Maxim's MAX13855 FAQ clearly states the MAX31855 uses SPI Mode 1, while the library defaults to using SPI Mode 0.
    The Adafruit MAX31855 library relies on the Adafruit Bus IO Library.
    In Adafruit_SPIDevice.cpp you can see how to set SPI_MODE1. Line 12 states that it defaults to SPI Mode 0.

    Since I don't know your code you have to fiddle in this SPI_Mode1 parameter somewhere yourself.

    Hope this helps because I'm running out of options as well.

    Paul

  6. #6
    Senior Member
    Join Date
    Jul 2020
    Posts
    398
    Quote Originally Posted by PaulS View Post
    There maybe an issue with the Adafruit MAX31855 library, see this page.
    Maxim's MAX13855 FAQ clearly states the MAX31855 uses SPI Mode 1, while the library defaults to using SPI Mode 0.
    The problem is a lot of chips out there are not really SPI compliant, they look a bit like SPI. This one clocks out the
    first bit on CS falling edge, for instance, so you always have to be careful to check the datasheet timing diagrams
    against the code you use looking for problems. This chip for instance doesn't always use a multiple of 8 clocks...

  7. #7
    Thank you all very much for your replies.
    After spending much of today trying to debug this, I noticed something.
    First of all, here is my code: (I know it is quite long)

    Code:
    /*
      31.07.2020
    */
    
    #include <Audio.h>
    #include <SPI.h>
    #include <nRF24L01.h>
    #include <RF24.h>
    #include <Wire.h>
    #include <U8g2lib.h>
    #include <tvg.h>       // an image in hex format
    #include <EEPROM.h>
    #include <NMEAGPS.h> // for the NMEA GPS sentences pharsing
    #include <ResponsiveAnalogRead.h> // the library for smooth analog reads
    #include <Adafruit_MAX31855.h> // for temparature read
    
    /*
      Make a ResponsiveAnalogRead object, pass in the pin, and either true or false depending on if you want sleep enabled
      Enabling sleep will cause values to take less time to stop changing and potentially stop changing more abruptly,
      where as disabling sleep will cause values to ease into their correct position smoothly and with slightly greater accuracy
    */
    ResponsiveAnalogRead BRAKE(A0, true);
    ResponsiveAnalogRead BATTERYRELAY(A1, true);
    ResponsiveAnalogRead BATTERY(A8, true);
    ResponsiveAnalogRead VOLUME(A12, true);
    ResponsiveAnalogRead STEERING(A16, true);
    ResponsiveAnalogRead ACCELERATION(A17, true);
    
    /* ========= */
    /* NRF24L01+ */
    /* ========= */
    RF24 radio(24, 25);       // CE and CSN pins for the NRF24L01+
    const uint64_t pipeaddress = 0xFA51AA55AFLL; // NRF pipe address must be the same for transmitter and receiver
    bool wireless = true;   // to know if the data should be sent to a wireless device HIGH=Yes, LOW=No
    int NRFfail = 0;       // number of failed NRF ack receives. Used to know when to display the WiFi sign
    byte NRFfailRate = 10;// how many failed ack receives untill the WiFi sign stops showing
    byte ackMsg;
    
    /* ====== */
    /* AUDIO  */
    /* ====== */
    #define audiobuffersize 128 // one block in audio library has 128 values of 2 bytes
    // GUItool: begin automatically generated code
    AudioInputI2S            i2s1;
    AudioPlayQueue           queue2;
    AudioMixer4              mixer2;
    AudioMixer4              mixer1;
    AudioOutputI2S           i2s2;
    AudioRecordQueue         queue1;
    AudioConnection          patchCord1(i2s1, 0, mixer1, 0);
    AudioConnection          patchCord2(i2s1, 1, mixer1, 1);
    AudioConnection          patchCord3(queue2, 0, mixer2, 0);
    AudioConnection          patchCord4(mixer2, 0, i2s2, 0);
    AudioConnection          patchCord5(mixer2, 0, i2s2, 1);
    AudioConnection          patchCord6(mixer1, queue1);
    AudioControlSGTL5000     sgtl5000_1;
    // GUItool: end automatically generated code
    
    uint8_t bufr[audiobuffersize * 2]; // buffer to hold 256 bytes of audio data
    uint8_t bufcount = 0;             // received nrf24l01+ packet counter
    bool setupR = true, setupT = true, setupN = true; // used to run the setup code only once
    byte error = 0;                 // used to calculate the number of errors received when transmitting audio
    byte maxErrors = 2;            // the number of errors that show that the audio receiving has ended
    unsigned long lastError = 0;  // last time 50 ms have passed since the last Audio Receive
    
    /* ========= */
    /* VARIABLES */
    /* ========= */
    unsigned int accValue = 0, brkValue = 0, zeroAccValue = 0, zeroBrkValue = 0, fullAccValue = 0, fullBrkValue = 0, fullLeftValue = 0, fullRightValue = 0;
    byte leds = 0;                    // Variable to hold the pattern of which LEDs are currently turn ed on or off for RPM
    byte rpmCount = 0, spdCount = 0; // Variable used in the average of the interval between pulses for RPM and RPMW calculation
    unsigned long interval = 0, intervalCount = 0, intervalSpd = 0, intervalCountSpd = 0, lastPulseTime = 0, lastPulseTimeSpd = 0, intervalAvg = 0, intervalSpdAvg = 0; // used for the RPM and SPD calculation
    float nr = 0.0526657824;       // for 11" wheel (rear) // number for the rpmW to speed calculation. Formula: wheelDiameter(m)/2*0.10472*18/5 for km/h
    // float nr = 0.047877984;    // for 10" wheel (front)
    float rpmW = 0;              // used in speed calculations
    
    /* ===== */
    /* GEARS */
    /* ===== */
    bool currentstateGP, currentstateGM;                 // The current state of the gear+, gear-, and  sensors
    bool prevstateGP = HIGH, prevstateGM = HIGH;        // The state of gear+, gear-, and lap sensors in previous scan
    unsigned long lastGearPlus = 0, lastGearMinus = 0; // for used for activating the relays for changing gears
    byte gearImpuls = 50;        // how long the gear change relay stays on (the time neded to actualy change the gear)
    byte gearImpulsReturn = 10; // TESTING - for stopping the gear shift motor from turning too much when shifting gears. 
    bool geaP = false, geaM = false;
    
    /* ======= */
    /* LAPTIME */
    /* ======= */
    unsigned long lastLap = 0, bestLap = 599990; // Variables for the last and best lap
    unsigned long lapMillis = 0;                // How long has it been since the last time the lap has started
    int bestLapReset = 0, bestLapLastReset = 0;// used to reset the stored best lap
    byte sectors = 1;                         // the number of split/start/finish lines
    byte line = 0;                           // the number of times you passed over the split/start/finish lines
    bool bestLapFlag = false;               // used to know when one lap is finished to calculate the bestLap
    bool startLap = false;                 // used to know when a lap was started
    bool firstLap = true;                 // used to not record the seconds from starting the device untill the first magentic line is corossed - first las is started
    
    /* ======= */
    /* MPU6050 */
    /* ======= */
    byte x = 0;                          // used as a counter for the average of MPU readings
    float rawX = 0, rawY = 0;           // the float where all the MPU readings are stored then divided by the number of entries (x);
    int16_t acc_x, acc_y, acc_z;
    
    /* =================== */
    /* SERIAL TRANSMISSION */
    /* =================== */
    unsigned long lastTransmit = 0; // the last time the $RC2 string was transmitted via serial
    byte transmitRate = 50;        // transmit the $RC2 string every 50 milliseconds
    String data;                  // this is the string that is going to be sent to the phone
    
    /* === */
    /* GPS */
    /* === */
    NMEAGPS gps;
    gps_fix fix;  // the structure that holds all the parsed pieces
    /* see https://github.com/SlashDevin/NeoGPS/blob/master/extras/doc/Data%20Model.md for all fix members that can be accesed */
    String GpsNmea1, GpsNmea2, GpsNmea1Buf, GpsNmea2Buf, GPScounter; // strings to hold the NMEA buffer and sentences
    bool nmea = true;                                               // flag to know when to write to which NMEA sentence string
    
    /* ==== */
    /* OLED */
    /* ==== */
    U8G2_SSD1306_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R2, /* ss=*/ 4, /* dc=*/ 3, /* reset=*/ 2);
    unsigned long lastUpdateOled = 0;
    byte updateRateOled = 100; // update the display once every 100 milliseconds
    
    /* === */
    /* BPM */
    /* === */
    int UpperThreshold = 518, LowerThreshold = 490, reading = 0;
    bool IgnoreReading = false, FirstPulseDetected = false;
    unsigned long FirstPulseTime = 0, SecondPulseTime = 0, PulseInterval = 0;
    
    /* ================= */
    /* dataNRF STRUCTURE */
    /* ================= */
    struct transmission {
      float avgXx, avgYy, speed, BPM, lapTime;    // 4 bytes
      byte acceleration, brake, gear, SETUP = 0; // 1 byte
      short int rpm, str;                       // 2 bytes
    }; transmission dataNRF;                   // 28 bytes structure
    
    /* ============= */
    /* BUTTON STATES */
    /* ============= */
    bool currentstateBLUE;
    bool currentstateGREEN;
    bool currentstateTALK;
    bool prevstateBLUE = LOW;
    bool prevstateGREEN = LOW;
    bool prevstateTALK = LOW;
    
    /* ============= */
    /* BATTERY LEVEL */
    /* ============= */
    int lastMillisSec = 0;    // last time the battery level was taken
    boolean startBat = true; // update the battery level only once when the Teensy starts. Every 5 seconds after that. 
    
    /* =========== */
    /* TEMPERATURE */
    /* =========== */
    Adafruit_MAX31855 thermocouple1(16);                 // initialize the MAX31855 Thermocouple 1
    Adafruit_MAX31855 thermocouple2(17);                // initialize the MAX31855 Thermocouple 2
    unsigned long lastTemp1Read = 0, lastTemp2Read = 0;// to know when the last temperature read was made for both thermocouples
    double temp1, temp2;                              // variables to hold the temperatures
    /* thermocouple1.readCelsius() // thermocouple2.readCelsius() */
    
    /* ======= */
    /* TESTING */
    /* ======= */
    bool go = true, goS = false, goG = false;
    unsigned long lastGear = 0;
    unsigned long startLoop, endLoop, showTime, startRPM, endRPM, startSPD, endSPD; // for calculating the time it takes for 1 loop of the program
    /*==================================================================================================*/
    /*===                                                                                            ===*/
    /*==================================================================================================*/
    
    
    void setup() {
      pinMode(2, OUTPUT);                              // Reset pin for the 2.42 inch Oled
      pinMode(3, OUTPUT);                             // DC pin Oled
      pinMode(4, OUTPUT);                            // CS Oled
      pinMode(5, OUTPUT);                           // DS shift register (Steering wheel Oled) DATA
      pinMode(6, OUTPUT);                          // ST-CP shift register (Steering wheel Oled) LATCH
      pinMode(9, INPUT);                          // Lap
      pinMode(10, OUTPUT);                       // SH-CP shift register (Steering wheel Oled) CLOCK
      pinMode(16, OUTPUT);                      // CS for Temperature sensor 1
      digitalWrite(16, HIGH);                  // do not read temperature now 
      pinMode(17, OUTPUT);                    // CS for Temperature sensor 2
      digitalWrite(17, HIGH);                // do not read temperature now
      pinMode(27, INPUT);                   // Button GREEN - Right (Steering wheel Oled)
      pinMode(28, INPUT);                  // Button Talk (Steering wheel Oled)
      pinMode(29, INPUT);                 // Button BLUE - Left (Steering wheel Oled)
      pinMode(30, OUTPUT);               // Gear relay -
      pinMode(31, OUTPUT);              // Transistor for Relay Ground
      pinMode(32, OUTPUT);             // Gear relay +
      pinMode(33, INPUT);             // RPM
      pinMode(36, INPUT);            // SPD
      pinMode(37, INPUT);           // Gear - button
      pinMode(38, INPUT);          // Gear + button
      //pinMode(A0, INPUT);       // Brk
      //pinMode(A1, INPUT);      // Relay Battery level
      //pinMode(A8, INPUT);     // Battery level
      //pinMode(A12, INPUT);   // Vol
      //pinMode(A15, INPUT);  // HeartRate
      //pinMode(A16, INPUT); // Steering angle
      //pinMode(A17, INPUT);// Acc
    
      Serial.begin(115200);              // initialize the USB Serial port
      Serial1.begin(115200);            // initialize the Serial port to transmit the Bluetooth data
      Serial8.begin(115200);           // initialize the Serial port to receive GPS data
    
      delay(50);
      SPI.begin();                   // initialize the SPI port
    
      u8g2.begin();                // initialize the Oled
      u8g2.setFlipMode(true);     // flip the image on the Oled
    
      Wire.begin();             // initialize the i2c port
      Wire.setClock(400000);   // set the i2c to 400 KHz
    
      leds = B00000000;      // turn  off all the leds on the steering wheel
      updateShiftRegister();// update the LEDs on the steering wheel. (turn  them off)
    
      Wire.beginTransmission(0x68);      // Start communicating with the MPU
      Wire.write(0x6B);                 // Start writing to this register (PWR_MGMT_1)
      Wire.write(0x00);                // Set register 0x6B to zero (wakes up the MPU)
      Wire.endTransmission();         // Terminate the connection
      delay(50);
      Wire.beginTransmission(0x68); // Start communicating with the MPU
      Wire.write(0x1C);            // Start writing to this register (ACCEL_CONFIG)
      Wire.write(0x00);           // Set register 0x1C to 0 (sets the sensitivity of the accelerometer to 2g)
      //Wire.write(0x01);        // Set register 0x1C to 1 (sets the sensitivity of the accelerometer to 4g)
      //Wire.write(0x10);       // Set register 0x1C to 2 (sets the sensitivity of the accelerometer to 8g)
      //Wire.write(0x11);      // Set register 0x1C to 3 (sets the sensitivity of the accelerometer to 16g)
      Wire.endTransmission(); // Terminate the connection
    
      AudioMemory(64);      // Give the Audio Library some memory to work with
      sgtl5000_1.enable(); // Enable the SGTL5000
      
      radio.begin();     // Initialize and configure the NRF24L01+ module
      delay(50);
    
      /* Attach interrupts for the RPM, SPEED and LAP sensors */
      attachInterrupt(digitalPinToInterrupt(33), &ignitionIsr, FALLING);
      attachInterrupt(digitalPinToInterrupt(36), &wheelRpm, FALLING);
      attachInterrupt(digitalPinToInterrupt(9), &lap, FALLING);
      
    
      //EEPROM.get(24, bestLap);// read the best lap from EEPROM to show on the Oled
    
      u8g2.clearBuffer();                // Clear the oled buffer
      u8g2.drawXBM(0, 0, 128, 64, tvg); // The TvG logo
      u8g2.sendBuffer();               // Send the TvG image to the screen
      delay(2000);
      u8g2.clearBuffer();            // Clear the Oled buffer so that the next data can be written in
      
      if (digitalReadFast(27)) {               // if the GREEN button is pressed while powering on
        radio.begin();                        // initialize the NRF module
        delay(50);
        radio.setPALevel(RF24_PA_MAX);      // set the NRF module in the maximum transmission/receiving power
        radio.setDataRate(RF24_250KBPS);   // set the lowest data rate (best for max distance)
        radio.setAutoAck(true);           // enable auto acknowledgement
        radio.setRetries(3, 5);          // set just 3 retries so time is not wasted on resends
        radio.enableAckPayload();       // enable the ack payload
        radio.stopListening();         // start transmitting data
        delay(50);
        radio.openWritingPipe(pipeaddress);      //open the pipe for transmitting data
    
        dataNRF.gear = 11;                     // tell the wireless device that the main boart is in SETUP mode
        sendData();                           // send the dataNRF.gear value
        sendData();                          // send the dataNRF.gear a second time just in case the first time failed
        u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
        u8g2.setCursor(4, 40);
        u8g2.print(F(">SETUP<"));
        u8g2.sendBuffer();
        u8g2.clearBuffer();
        delay(2000);
    
        dataNRF.gear = 12;// used to know what to display on the wireless device
        sendData();      // send the dataNRF.gear value
        sendData();     // send the dataNRF.gear a second time just in case the first time failed
        u8g2.sendBuffer();
        u8g2.clearBuffer();
        delay(3000);
    
        //ACCELERATION.update();                   // update the Acc analog value in the ResponsiveAnalogRead library
        //BRAKE.update();                         // update the Brk analog value in the ResponsiveAnalogRead library
        //EEPROM.put(0, ACCELERATION.getValue());// put the analog value in the EEPROM for released ACC
        //EEPROM.put(4, BRAKE.getValue());      // put the analog value in the EEPROM for released BRK
        delay(50);
    
        dataNRF.gear = 13;// used to know what to display on the wireless device
        sendData();      // send the dataNRF.gear value
        sendData();     // send the dataNRF.gear a second time just in case the first time failed
        u8g2.drawBox(0, 0, 130, 20);
        u8g2.setDrawColor(0);                   // Black font on white background
        u8g2.setFont(u8g2_font_ncenB18_tf);    // 18 pixels high font
        u8g2.setCursor(15, 19);
        u8g2.print(F(">Press<"));
        u8g2.setDrawColor(1);               // White font on black background
        u8g2.setCursor(12, 39);
        u8g2.setFont(u8g2_font_lubB14_tf);// 15 pixels high font
        u8g2.print(F("Acc & Brk"));
        u8g2.setCursor(30, 59);
        u8g2.print(F("pedals"));
        u8g2.sendBuffer();
        u8g2.clearBuffer();
        delay(3000);
    
        //ACCELERATION.update();                   // update the Acc analog value in the ResponsiveAnalogRead library
        //BRAKE.update();                         // update the Brk analog value in the ResponsiveAnalogRead library
        //EEPROM.put(8, ACCELERATION.getValue());// put the analog value in the EEPROM for pressed ACC
        //EEPROM.put(12, BRAKE.getValue());     // put the analog value in the EEPROM for pressed BRK
        delay(50);
    
        dataNRF.gear = 14;// used to know what to display on the wireless device
        sendData();      // send the dataNRF.gear value
        sendData();     // send the dataNRF.gear a second time just in case the first time failed
        u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
        u8g2.setCursor(15, 30);
        u8g2.print(F("Release"));
        u8g2.setCursor(25, 50);
        u8g2.print(F("pedals"));
        u8g2.sendBuffer();
        u8g2.clearBuffer();
        delay(2000);
    
        dataNRF.gear = 15;// used to know what to display on the wireless device
        sendData();      // send the dataNRF.gear value
        sendData();     // send the dataNRF.gear a second time just in case the first time failed
        u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
        u8g2.setCursor(10, 25);
        u8g2.print(F("Steering"));
        u8g2.setCursor(10, 50);
        u8g2.print(F("MAX LE"));
        u8g2.sendBuffer();
        u8g2.clearBuffer();
        delay(3000);
    
        //STEERING.update();                   // update the STR analog value in the ResponsiveAnalogRead library
        //EEPROM.put(16, STEERING.getValue());// put the analog value in the EEPROM for max left STR
        delay(50);
    
        dataNRF.gear = 16;// used to know what to display on the wireless device
        sendData();      // send the dataNRF.gear value
        sendData();     // send the dataNRF.gear a second time just in case the first time failed
        u8g2.setFont(u8g2_font_ncenB18_tf); // 18 pixels high font
        u8g2.setCursor(10, 25);
        u8g2.print(F("Steering"));
        u8g2.setCursor(11, 50);
        u8g2.print(F("MAX RI"));
        u8g2.sendBuffer();
        u8g2.clearBuffer();
        delay(3000);
    
        //STEERING.update();                   // update the STR analog value in the ResponsiveAnalogRead library
        //EEPROM.put(20, STEERING.getValue());// put the analog value in the EEPROM for max right STR
        delay(50);
    
        dataNRF.gear = 17;// used to know what to display on the wireless device
        sendData();      // send the dataNRF.gear value
        sendData();     // send the dataNRF.gear a second time just in case the first time failed
        u8g2.setCursor(8, 40);
        u8g2.print(F(">DONE<"));
        u8g2.sendBuffer();
        u8g2.clearBuffer();
        delay(2000);
        dataNRF.gear = 0; // tell the wireless device to enter normal mode
        sendData();      // send the dataNRF.gear value
        sendData();     // send the dataNRF.gear a second time just in case the first time failed
    
      } else { /* end of TvG KDL setup */
        /* read the stored values for the position of the pedals */
        /*EEPROM.get(0, zeroAccValue);
          EEPROM.get(4, zeroBrkValue);
          EEPROM.get(8, fullAccValue);
          EEPROM.get(12, fullBrkValue);
          EEPROM.get(16, fullLeftValue);
          EEPROM.get(20, fullRightValue);
        */
      }
      zeroAccValue = 517;   //TESTING
      fullAccValue = 785;  //TESTING
      zeroBrkValue = 527; //TESTING
      fullBrkValue = 785;//TESTING
    } /* end of Setup function */
    
    void loop() {
      startLoop = micros(); //TESTING
      currentstateTALK = digitalRead(28); // see if the Talk Button is pressed
      /* ========================================== */
      /* CODE for AUDIO TRANSMITTING and  RECEIVING */
      /* ========================================== */
      if (ackMsg == 1) {                                // if the Receiver transmits Audio Data
        if (setupR) {                                  // setup the NRF to receive (just once)
          detachInterrupt(digitalPinToInterrupt(33)); // disable the interupt for RPM
          detachInterrupt(digitalPinToInterrupt(36));// disable the interupt for SPD
          leds = B00000000;                         // turn off the LEDs on the steering wheel
          updateShiftRegister();                   // turn off the LEDs on the steering wheel
          u8g2.clearBuffer();
          u8g2.setFont(u8g2_font_crox4hb_tf);    // 14 pixels high font
          u8g2.setCursor(60, 40);
          u8g2.print("R");                     // display R to know the device is receiving Audio
          u8g2.sendBuffer();                  // send the buffer to the display
          u8g2.clearBuffer();                // clear the buffer
          /* code for setting up the NRF for audio receiving */
          radio.begin();                   // reinitialize the NRF module so that the settings reset to default
          delay(50);
          radio.setPayloadSize(32);      // this is the maximum payload size for a packet transfer of nrf24
          radio.setAutoAck(false);      // no Ack
          radio.disableCRC();          // no CRC
          radio.setPALevel(RF24_PA_MAX);          // set the NRF module in the maximum transmission/receiving power
          radio.setDataRate(RF24_2MBPS);         // set the maximum data rate
          radio.openReadingPipe(0, pipeaddress);// open the pipe for receiving Audio
          delay(50);
          radio.startListening();
          /* done setting up the NRF for audio receiving */
          /* audio settings */
          VOLUME.update(); // update the reading fot the volume analog read pin
          sgtl5000_1.volume(VOLUME.getValue() / 1023.0/*0.4*/); // set the headphone volume from 0.0 to 1.0
          setupR = false;        // so that the setup is only done once
          setupT = true;        // perform the transmit setup next time you press the TRANSMIT the button
          setupN = true;       // perform the NORMAL setup after transmitting/receiving
        }
        /* code for the actual audio receiving */
        if (radio.available()) {
          error = 0;                                // reset the error count so the program knows when too many errors are present
          if ((bufcount >= 0) && (bufcount < 8)) { // get 8 packets a 32 byte audio data
            radio.read(&bufr[bufcount * 32], 32); // get 32 byte audio packet data
            if (bufcount == 7) {                 // test if all 8 packets received
              bufcount = 0;                     // reset the packets received count
              int16_t *p = queue2.getBuffer();
              memcpy(p, &bufr[0], (audiobuffersize * 2));
              queue2.playBuffer();
            } else {
              bufcount++;
            }
          }
        }/* end of code for the actual audio receiving */
         /* code for exiting the Audio Receiver mode */
        if (!radio.available()) {           // if the radio signal is not available
          if (millis() - lastError > 50) { // every 50 milliseconds
            error += 1;                   // increment the number of errors received
            lastError = millis();        // reset the last time an error was logged
          }
          if (error > maxErrors) {     // if the number of errors is bigger than maxErrors it means that probably the receiving of audio stopped
            ackMsg = 0;               // exit receiving audio mode
          }/* end of code for exiting the Audio Receiver mode */
        }
        /* end of code for Receiving Audio */
      } else if (prevstateTALK != currentstateTALK && currentstateTALK == HIGH) { // if the Talk button is pressed and data should be sent to a wireless device
        if (setupT) {                  // setup the NRF to transmit - just once
          detachInterrupt(digitalPinToInterrupt(33)); // disable the interupt for RPM
          detachInterrupt(digitalPinToInterrupt(36));// disable the interupt for SPD
          leds = B00000000;         // turn off the LEDs on the steering wheel
          updateShiftRegister();   // turn off the LEDs on the steering wheel
          u8g2.clearBuffer();     // clear the buffer
          u8g2.setFont(u8g2_font_crox4hb_tf); // 14 pixel high font
          u8g2.setCursor(60, 40);
          u8g2.print("T");     // display T to know the device is receiving Audio
          u8g2.sendBuffer();  // send the buffer to the display
          dataNRF.SETUP = 1; // tell the Receiver that it is time to receive audio data
          sendData();       // send the data containing the SETUP instruction to the receiver using the current NRF settings
          /* setup the NRF for audio transmission */
          radio.begin();  // reinitialize the NRF module so that the settings reset to default
          delay(50);
          radio.setPayloadSize(32); //this is the maximum payload size for a packet transfer of nrf24
          radio.setAutoAck(false); // no Ack
          radio.disableCRC();     // no CRC
          radio.setPALevel(RF24_PA_MAX);       // set the NRF module in the maximum transmission/receiving power
          radio.setDataRate(RF24_2MBPS);      // set the maximum data rate
          radio.openWritingPipe(pipeaddress);// open the pipe for transmitting Audio
          delay(50);
          radio.stopListening();           // start transmitting Audio data
          /* done setting up the NRF for audio receiving */
          /* audio settings */
          sgtl5000_1.inputSelect(AUDIO_INPUT_MIC); //which input to use (MICROPHONE)
          sgtl5000_1.adcHighPassFilterDisable();
          queue1.begin();  // initialize the queue in which to put the Audio data
          setupT = false; // perform the transmit setup only once
          setupR = true; // perform the receive setup next time the conditions are met
          setupN = true;// perform the normal setup next time the conditions are met
        }
        /* code for the actual audio transmitting */
        Serial.println("BUTON");
        if (queue1.available()) {
          memcpy(bufr, queue1.readBuffer(), audiobuffersize * 2); // copy 256 byte audio data from audio library buffer to bufr
          queue1.freeBuffer();
          for (int i = 0; i < 8; i++) { // send audio data in 8 packages a 32 byte to the FIFO buffers
            radio.writeFast(&bufr[i * 32], 32);
          }
        }
        /* end of code for the actual audio transmitting */
      } else {
        if (setupN) {                              // if the TALK button is not pressed and the Receiver is not transmitting Audio
          attachInterrupt(digitalPinToInterrupt(33), &ignitionIsr, FALLING);// enalbe the interrupt for RPM
          attachInterrupt(digitalPinToInterrupt(36), &wheelRpm, FALLING);  // enalbe the interrupt for SPD
          dataNRF.SETUP = 0;                    // tell the Receiver that no more audio data will be transmitted
          error = 0;                           // reset the number of Audio receive errors
          radio.begin();                      // reinitialize the NRF module so that the settings reset to default
          delay(50);
          radio.setPALevel(RF24_PA_MAX);    // set the NRF module in the maximum transmission/receiving power
          radio.setDataRate(RF24_250KBPS); // set the lowest data rate (best for max distance)
          radio.setAutoAck(true);         // enable auto acknowledgement
          radio.setRetries(3, 5);        // set just 3 retries so time is not wasted on resends
          radio.enableAckPayload();     // enable the ack payload
          radio.stopListening();       // start transmitting data
          delay(50);
          radio.openWritingPipe(pipeaddress); //open the pipe for transmitting data
          setupN = false;           // perform the normal operation setup only once
          setupT = true;           // perform the transmit setup next time the conditions are met
          setupR = true;          // perform the receive setup next time the conditions are met
        }
        prevstateTALK = currentstateTALK;
    
        /* ==================================================================================== */
        /* ==================================================================================== */
        /*                             Beginning of the normal LOOP                             */
        /* ==================================================================================== */
        /* ==================================================================================== */
    
    
        /* ======================== */
        /* CALCULATE the HEART RATE */
        /* ======================== */
        bpm();  
        
        
        /* ====================== */
        /* CALCULATE the G-forces */
        /* ====================== */
        gforce(); 
    
    
        /* ========================= */
        /*   PHARSE THE GPS DATA     */
        /* ========================= */
        gps_data();
    
    
        /* ================================ */
        /* CALCULATE the ACC and BRK values */
        /* ================================ */
        accBrk();
        
            
        /* ======================= */
        /* READ the STEERING ANGLE */
        /* ======================= */
        steering();
    
        
        /* ===================== */
        /* READ the TEMPERATURES */
        /* ===================== */
          
        if (millis() - lastTemp1Read > 2000){ // read the temperature on thermocouple 1 every 2 seconds
          temp1 = thermocouple1.readCelsius();
          lastTemp1Read = millis();
        }
        
        if (millis() - lastTemp2Read > 3000){ // read the temperature on thermocouple 2 every 3 seconds
          temp2 = thermocouple2.readCelsius();
          lastTemp2Read = millis();
        }
        
        
        /* ====================== */
        /* CALCULATE THE BEST LAP */
        /* ====================== */
        
        if (bestLapFlag) {                          // if a lap was finished and the best lap has not been calculated yet
          if (lastLap > 1 && lastLap <= bestLap) { // if the last lap wan not 1 second and was equal or faster than the best lap
            bestLap = lastLap;                    // store the last lap as beeing the best  lap
            //EEPROM.put(24, bestLap);           // store the best lap in EEPROM for later use
          }
          bestLapFlag = false;                 // reset the flag that was placed when a lap was finished so we can calculate the next best lap
        }
    
    
        /* ========================= */
        /* CODE FOR THE BLUE BUTTON  */
        /* ========================= */
        /*currentstateBLUE = digitalReadFast(29);// read the current button state (pressed or not / HIGH or LOW)
        if (prevstateBLUE != currentstateBLUE && currentstateBLUE == HIGH ) {// if the GREEN button is pressed
          if (startLap = false){
            
            startLap = true;
          } else if (startLap = true){
            bestLapFlag = true;
          }
        }
        prevstateBLUE = currentstateBLUE;
        */
    
    
        /* ========================= */
        /* CODE FOR THE GREEN BUTTON */
        /* ========================= */
        currentstateGREEN = digitalReadFast(27);// read the current button state (pressed or not / HIGH or LOW)
        if (prevstateGREEN != currentstateGREEN && currentstateGREEN == HIGH ) {// if the GREEN button is pressed
          if (wireless) {
            wireless = LOW;                // there is no wireless device to transmit/receive to/from
          } else {
            wireless = HIGH;             // there is a wireless device to transmit/receive to/from
          }
        }
        prevstateGREEN = currentstateGREEN;
        
        if (digitalReadFast(27)){
          bestLapReset = millis() - bestLapLastReset; // increment the bestLapReset value while the GREEN button is pressed
          if (bestLapReset > 5000){   // if the GREEN button is pressed for more than 5 seconds
            bestLap = 599990;        // reset the best lap to 9:59.99
          //EEPROM.put(24, bestLap);// reset the best Lap stored in EEPROM
          }
        } else {
          bestLapReset = 0;            // reset the bestLapReset value when the GREEN button is not pressed
          bestLapLastReset = millis();// reset the time the button was not pressed
        }
    
    
        /* ==================== */
        /* CALCULATIONS FOR RPM */
        /* ==================== */
        /* calculate the average interval between sparks every 10 sparks to calculate the rpm */
        if (rpmCount >= 10) {
          intervalAvg = intervalCount / rpmCount; /* =====!!!!! WARNING !!!!!===== probable error in calculation because the time is calculated every 10 impulses. It should be 1.*/
          dataNRF.rpm = 60000000 / (intervalAvg * 1); // 1 = number of impulses per rotation
          intervalCount = 0;
          rpmCount = 0;
        }
        /*
        if ((micros() - lastPulseTime) > 500000) {        // if more than 0.5 sec has passed since the last engine revolution the engine is probably stopped so rpm=0
          dataNRF.rpm = 0;
        }*/
    
    
        /* ====================== */
        /* CALCULATIONS FOR SPEED */
        /* ====================== */
        /* calculate the average interval between wheel rotations every 5 wheel rotations to calculate the speed */
        if (spdCount >= 5) {
          intervalSpdAvg = intervalCountSpd / spdCount;
          rpmW = 60000000 / intervalSpdAvg;
          dataNRF.speed = nr * rpmW;
          intervalCountSpd = 0;
          spdCount = 0;
        }
        /*
        if ((micros() - lastPulseTimeSpd) > 1500000) { // if more than 1.5 sec has passed since the last wheel revolution reset the speed to 0
          dataNRF.speed = 0;
        rpmW = 0;
        }*/
    
    
        /* ======================== */
        /* CALCULATIONS FOR LAPTIME */
        /* ======================== */
        if (startLap){ // calculate the current laptime only if you started a lap - passed over at least one magnetic strip
          dataNRF.lapTime = millis() - lapMillis; // update every loop how many milliseconds have passed in this lap - for live LapTime display
        }
    
    
        /* ======================= */
        /*          GEAR +         */
        /* ======================= */
        currentstateGP = digitalReadFast(38); // Read hall sensor state (Gear +)
        if (prevstateGP != currentstateGP) { // If there is change in input
          if (currentstateGP == LOW ) {     // If input changes from HIGH to LOW
            dataNRF.gear += 1;             // Increment the Gear number
            if (dataNRF.gear > 6) {       // if you are in 6th gear and trigger the gear+ sensor the display remains 6
              dataNRF.gear = 6;
            }
            digitalWriteFast(32, LOW); // activate the relay to change the gear up
            lastGearPlus = millis();
            geaP = true;
          }
          prevstateGP = currentstateGP;
        }
        if (millis() - lastGearPlus >= gearImpuls) {
          digitalWriteFast(32, HIGH); // after <gearImpuls> milliseconds turn the Gear+ relay off
          delay(10);
          if (geaP){
            digitalWriteFast(30, LOW);
            delay(20);
            digitalWriteFast(30, HIGH);
            geaP = false;
          }
        }
    
    
    
        /* ======================= */
        /*          GEAR -         */
        /* ======================= */
        currentstateGM = digitalReadFast(37);  // Read hall sensor state (Gear -)
        if (prevstateGM != currentstateGM) {  // If there is change in input
          if (currentstateGM == LOW ) {      // If input only changes from HIGH to LOW
            dataNRF.gear -= 1;              // Decrement the Gear number
            if (dataNRF.gear > 10 || dataNRF.gear == 0) {  // if you are in 1st gear and trigger the gear- sensor the display remains 1
              dataNRF.gear = 1;
            }
            digitalWriteFast(30, LOW); // activate the relay to change the gear down
            lastGearMinus = millis();
            geaM = true;
          }
          prevstateGM = currentstateGM;
        }
        if (millis() - lastGearMinus >= gearImpuls) {
          digitalWriteFast(30, HIGH); // after <gearImpuls> milliseconds turn the Gear- relay off
          delay(10);
          if (geaM){
          digitalWriteFast(32, LOW);
          delay(20);
          digitalWriteFast(32, HIGH);
          geaM = false;
          }
        }
        /*
        if (dataNRF.rpm == 0 && dataNRF.speed == 0) { // if the engine is stopped and you are not moving, probably the kart is stopped so gear = 0
          dataNRF.gear = 0;
        }
        */
    
    
        /* ================================= */
        /*    UPDATE THE DATA ON THE OLED    */
        /* ================================= */
        if (millis() - lastUpdateOled >= updateRateOled) {
          oled();
          lastUpdateOled = millis();
        }
    
    
        /* ================================== */
        /* DATA TRANSMIT TO BLUETOOTH AND NRF */
        /* ================================== */
        if (millis() - lastTransmit >= transmitRate) {
          avgGforce();                      // calculate the average of the g-forces
          constructString();               // construct the string needed for RaceChrono
          if (wireless) {                 // if data should be sent to a wireless device
            sendData();                  // transmit the data to the wireless device using the NRF module
          }
          Serial1.println(data);       // print the data to serial (to the Bluetooth device)
          Serial1.print(GpsNmea1);    // print the first NMEA sentence to serial
          Serial1.print(GpsNmea2);   // print the second NMEA sentence to serial
          //testData();
          rpmLights();             // calculate how many leds to turn on the steering wheel based on the RPM
          lastTransmit = millis();// reset the time when the last $RC2 string was transmitted
          /*
          if (count == 65535) {  // Needed only when not using the GPS 
            count = 0;          // reset the counter variable when it reaches 65535 (maximum an int can hold)
          }
          else {
            count += 1;      // increment the count variable
          }*/
        }
      }
    }
    
    /* ==================================================================================== */
    /* ==================================================================================== */
    /*                             End of the normal LOOP                                   */
    /* ==================================================================================== */
    /* ==================================================================================== */
    
    void testData() { // TESTING
      if (dataNRF.rpm <= 1000) {go = true;}
      if (dataNRF.rpm >= 12500) {go = false;}
      if (go) {dataNRF.rpm += 900;}
      if (!go) {dataNRF.rpm -= 1000;}
      
      if (dataNRF.speed <= 3.2) {goS = true;}
      if (dataNRF.speed >= 141.5) {goS = false;}
      if (goS) {dataNRF.speed += 3.2;}
      if (!goS) {dataNRF.speed -= 3.2;}
    
      if (millis() - lastGear >= 1000) {
        if (dataNRF.gear <= 1) {goG = true;}
        if (dataNRF.gear >= 6) {goG = false;}
        if (goG) {dataNRF.gear += 1;}
        if (!goG) {dataNRF.gear -= 1;}
        lastGear = millis();
      }
    
      dataNRF.BPM += 1;
      if (dataNRF.BPM >= 180) {
        dataNRF.BPM = 1;
      }
    }
    
    
    
    /* ========================================================================================= */
    /* SEND DATA WITH NRF24L01+ */
    /* ======================== */
    void sendData() {
      if (radio.write(&dataNRF, sizeof(dataNRF))) {
        if (radio.isAckPayloadAvailable()) {   // if the Receiver transmitted the ackMsg
          radio.read(&ackMsg, sizeof(ackMsg));// read the ackMsg
          NRFfail = 0;
        } else {
          NRFfail += 1;
        }
        /* display the WiFi sign on the top right corner */
        if (NRFfail < NRFfailRate) { // if there are no more that <NRFfailRate> failed ack receives, display the WiFi sign
          u8g2.drawLine(119, 4, 121, 2);
          u8g2.drawLine(121, 2, 125, 2);
          u8g2.drawLine(125, 2, 127, 4);
          u8g2.drawLine(121, 5, 122, 4);
          u8g2.drawLine(122, 4, 124, 4);
          u8g2.drawLine(124, 4, 125, 5);
          u8g2.drawPixel(123, 6); // the pixel at the bottom of the signal indicator
        }
      }
    }
    
    
    
    /* ========================================================================================= */
    /* OLED DISPLAY */
    /* ============ */
    void oled() {
    
      /* Values for the analogRead(A1) depending on voltage
         5V - 240
        6.6V - 320 minimum for operating the gear shift relays
         9V - 450
        12V - 620
      */
      /* update the battery level once when the Teensy starts */
      if (startBat == true) {
        BATTERY.update();      // update the value read from pin A10
        BATTERYRELAY.update();// update the analog read value for relay battery
        startBat = false;    // reset the flag so the battery level is updated only once every 5 seconds (below)
      }
      
      if (millis() - lastMillisSec > 5000) { // update the battery level indicator every 5 seconds
        BATTERY.update();       // update the analog read value for battery
        BATTERYRELAY.update(); // update the analog read value for relay battery
        lastMillisSec = millis();
      } 
      
      /* battery full/empty frames */
      if (BATTERY.getValue() > 100){ // only show battery level if battery plugged in
        u8g2.drawBox(/*x*/(map (BATTERY.getValue(),      240, 620, 22,  3)), /*y*/ 2, /*length*/ (/*remaining pixels outside the battery frame*/ 22 - (map (BATTERY.getValue(),      240, 620, 22,  3))), /*height*/ 4); // used to draw the rectangle that fills the battery :: battery full in 20 minutes @ USB
      }
      if (BATTERYRELAY.getValue() > 100){ // only show battery level if battery plugged in
        u8g2.drawBox(/*x*/(map (BATTERYRELAY.getValue(), 240, 620, 56, 37)), /*y*/ 2, /*length*/ (/*remaining pixels outside the battery frame*/ 56 - (map (BATTERYRELAY.getValue(), 240, 620, 56, 37))), /*height*/ 4); // used to draw the rectangle that fills the battery for Relay board
      }
      /*MAIN BATTERY LEVEL INDICATOR*/
      u8g2.drawFrame(2, 1, 21, 6);                  // empty battery frame
      u8g2.drawVLine(1, 2, 4);                     // the tip of the battery frame
      if (BATTERYRELAY.getValue() < 250) {
        u8g2.setFont (u8g2_font_courR08_tf);     // 6 pixels high font
        u8g2.drawStr(58, 6, "X");               // display text indicating that gears will not change (voltage under 5V at the gear change relays)
      } else {
        u8g2.setCursor(58, 6);                // FOR TESTING
        u8g2.print(BATTERYRELAY.getValue());// FOR TESTING
      }/*MAIN BATTERY LEVEL INDICATOR*/
    
      /*RELAY BATTERY LEVEL INDICATOR*/
      u8g2.drawFrame(36, 1, 21, 6);               // empty relay battery frame
      u8g2.drawVLine(36, 2, 4);                  // the tip of the relay battery frame
      if (BATTERY.getValue() < 250) {
        u8g2.setFont (u8g2_font_courR08_tf);   // 6 pixels high font
        u8g2.drawStr(25, 7, "X");             // display text indicating low main PCB battery
      } else {
        u8g2.setFont (u8g2_font_courR08_tf);// FOR TESTING 6 pixels high font
        u8g2.setCursor(25, 7);             // FOR TESTING
        BATTERY.update();                 // update the analog read value for battery
        u8g2.print(BATTERY.getValue());  // FOR TENTING
      }/*RELAY BATTERY LEVEL INDICATOR*/
    
      /* if there is no wireless device to transmit/receive to/from, display an X instead of the Wifi signal */
      if (!wireless) {
        u8g2.setFont (u8g2_font_courR08_tf);// 6 pixels high font
        u8g2.drawStr(122, 6, "X");         // display the X that indicates there is no wireless device
      }
    
      /* ----- */
      /* FRAME */
      /* ----- */
      /* draw the horizontal and vertical lines on the display */
      u8g2.drawHLine(0, 47, 127);
      u8g2.drawVLine(93, 0,  42);
    
      /* ------- */
      /* LAPTIME */
      /* ------- */
      /*CURRENT LAP*/
      u8g2.setFont(u8g2_font_crox4hb_tf);            // 14 pixels high font
      u8g2.setCursor(0, 25);
      u8g2.print("C ");                            // display the C as in CURRENT lap
      u8g2.print((int)dataNRF.lapTime / 60000);       // display the minutes
      u8g2.setCursor(32, 25);
      u8g2.print(":");                         // display the ":" between the minutes and seconds
      if (((int) dataNRF.lapTime % 60000) < 10000) {// if less than 10 seconds should be displayed
        u8g2.setCursor(39, 25);
        u8g2.print("0");                    //add a "0" in front of the seconds so it shows "X:0X.XX"
        u8g2.setCursor(50, 25);
        u8g2.print((int)dataNRF.lapTime % 60000 / 1000.0);   // display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
      } 
      if (((int)dataNRF.lapTime % 60000) >= 10000){  // if there are more than 10 seconds to be displayed
        u8g2.setCursor(39, 25);
        u8g2.print((int)dataNRF.lapTime % 60000 / 1000.0);// display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
    
      }
      /*LAST LAP*/
      u8g2.setCursor(0, 43);
      u8g2.print("L ");                    // display the L as in LAST lap
      u8g2.setCursor(20, 43);
      u8g2.print(lastLap / 60000);       // display the full minutes
      u8g2.setCursor(32, 43);
      u8g2.print(":");                 // diaplay the ":" between the minutes and seconds
      if ((lastLap % 60000) < 10000) {// if less than 10 seconds should be displayed
        u8g2.setCursor(39, 43);
        u8g2.print("0");            //add a "0" in front of the seconds so it shows "0x"
        u8g2.setCursor(50, 43);
        u8g2.print(lastLap % 60000 / 1000.0);  // display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
      } else {
        u8g2.setCursor(39, 43);
        u8g2.print(lastLap % 60000 / 1000.0);// display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
      }
      /*BEST LAP*/
      u8g2.setCursor(0, 64);
      u8g2.print("B ");                      // display the B as in BEST lap
      u8g2.setCursor(20, 64);
      u8g2.print(bestLap / 60000);         // display the full minutes
      u8g2.setCursor(32, 64);
      u8g2.print(":");                   // diaplay the ":" between the minutes and seconds
      if ((bestLap % 60000) < 10000.0) {// if less than 10 seconds should be displayed
        u8g2.setCursor(39, 64);
        u8g2.print("0");              //add a "0" in front of the seconds so it shows "0x"
        u8g2.setCursor(50, 64);
        u8g2.print(bestLap % 60000 / 1000.0);  // display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
      } else {
        u8g2.setCursor(39, 64);
        u8g2.print(bestLap % 60000 / 1000.0);// display the seconds and milliseconds. (Milliseconds recorded divided by 1000 milliseconds/second)
      }
    
      
      /*TEMPERATURE*/
      u8g2.setFont (u8g2_font_courR08_tf);// 6 pixels high font
      u8g2.setCursor(95, 51);
      u8g2.print(temp1, 1);
      u8g2.setCursor(95, 64);
      u8g2.print(temp2, 1);
    
    
    
      /* ----- */
      /* SPEED */
      /* ----- */
      //u8g2.setFont(u8g2_font_crox4hb_tf);// 14 pixels high font
      /*if (dataNRF.speed < 10.0) {
        u8g2.setCursor(37, 60);        //move the start point of the text based on the number of digits displayed so that it gives the impression that the text is right aligned
        u8g2.print(dataNRF.speed, 1);
        }
        if (dataNRF.speed >= 10.0 && dataNRF.speed <= 99.9) {
        u8g2.setCursor(26, 60);    //move the start point of the text based on the number of digits displayed so that it gives the impression that the text is right aligned
        u8g2.print(dataNRF.speed, 1);
        }
        if (dataNRF.speed > 99.9) {
        u8g2.setCursor(15, 60); //move the start point of the text based on the number of digits displayed so that it gives the impression that the text is right aligned
        u8g2.print(dataNRF.speed, 1);
        }
    
        u8g2.setCursor(80, 60);
        u8g2.print(F("Km/h"));
      */
    
      /* ---- */
      /* GEAR */
      /* ---- */
      u8g2.setFont(u8g2_font_fub35_tn);// 35 pixels high font
      u8g2.setCursor(95, 43);
      u8g2.print(dataNRF.gear);      // display the current gear
      u8g2.sendBuffer();            // send the buffer to the display
      u8g2.clearBuffer();          // clear the buffer
    }
    
    
    
    /* ========================================================================================= */
    /* CALCULATE NMEA CHECKSUM */
    /* ======================= */
    char checkSum(String chars) {
      char check = 0;
      for (int c = 0; c < chars.length(); c++) {
        check = char(check ^ chars.charAt(c));
      }
      return check;
    }
    
    
    
    /* ========================================================================================= */
    /* CALCULATE LAPTIME */
    /* ================= */
    void lap() {
      if (sectors == 1) {                     // if the track has only 1 magnetic strip/sector
        if (firstLap){                       // if this is the begining of the first lap
          lapMillis = millis();             // reset the time recorded from when the device was started
          firstLap = false;                // do this only once when the first lap is started
        } else {
          lastLap = millis() - lapMillis;// store the last lap
          lapMillis = millis();         // reset the last time the sensor was triggered
        }
        startLap = true;              // tell the microcontroller that a lap was started. Start recording time.
        bestLapFlag = true;          // used to know when a lap is finished to calculate the best lap and not waste time in the interrupt routine
      }
      if (sectors > 1) {                        // if the track has more than 1 magnetic strips/sectors 
        line += 1;                             // A split line was crossed
        if (firstLap){                        // if this is the begining of the first lap
          lapMillis = millis();              // reset the time recorded from when the device was started
          firstLap = false;                 // do this only once when the first lap is started
        } 
        if (line == (sectors + 1)) {      // If enough split lines have been crossed
          lastLap = millis() - lapMillis;// store the last lap
          lapMillis = millis();         // Reset the last time that the start/finish line was crossed
          line = 0;                    // Reset the split lines
          startLap = true;            // tell the microcontroller that a lap was started. Start recording time.
          bestLapFlag = true;        // used to know when a lap is finished to calculate the best lap and not waste time in the interrupt routine
        }
      }
    }
    
    
    
    /* ========================================================================================= */
    /* CALCULATE RPM */
    /* ============= */
    void ignitionIsr() {
      startRPM = micros(); //TESTING
      interval = micros() - lastPulseTime;
      lastPulseTime = micros();
      rpmCount += 1;
      intervalCount += interval;
      endRPM = micros(); //TESTING
    }
    
    
    
    /* ========================================================================================= */
    /* CALCULATE SPEED */
    /* =============== */
    void wheelRpm() {
      startSPD = micros(); //TESTING
      intervalSpd = micros() - lastPulseTimeSpd;
      lastPulseTimeSpd = micros();
      spdCount += 1;
      intervalCountSpd += intervalSpd;
      endSPD = micros(); //TESTING
    }
    
    
    
    /* ========================================================================================= */
    /* CONSTRUCT the $RC2 STRING */
    /* ========================= */
    void constructString() {
      String buffer = "RC2," + GPScounter + ",," + String (dataNRF.avgXx, 1) + ',' + String (dataNRF.avgYy, 1) + ",," + dataNRF.rpm + ',' + dataNRF.gear + ',' +  dataNRF.brake + ',' + dataNRF.acceleration + ',' + String(lastLap / 1000.0) + ',' + String(dataNRF.speed, 1) + ',' + String(dataNRF.BPM) + ',' + dataNRF.str + ",,"; // construct the $RC2 string using the variables and taking into account the format RaceChrono asks for
    //String buffer = "RC2,," + String(count) + ',' + String (dataNRF.avgXx, 1) + ',' + String (dataNRF.avgYy, 1) + ",," + dataNRF.rpm + ',' + dataNRF.gear + ',' +  dataNRF.brake + ',' + dataNRF.acceleration + ',' + String(lastLap / 1000.0) + ',' + String(dataNRF.speed, 1) + ',' + String(dataNRF.BPM) + ',' + dataNRF.str + ",,"; // construct the $RC2 string using the variables and taking into account the format RaceChrono asks for
      String checksum = String (checkSum(buffer), HEX);// calculate the checksum of the RC2 string
      char crc = checkSum (buffer);
      data = "$" + buffer + "*";
      if (crc < 16) {                               // if the HEX value of the checksum is only one character, add "0" in front
        data = data + "0" + checksum;
      } else {
        data = data + checksum;
      }
    }
    
    
    
    /* ========================================================================================= */
    /* RPM LEDs */
    /* ======== */
    void rpmLights() {
      if (dataNRF.rpm < 5000                        ) {leds = B00000000;}
      if (dataNRF.rpm > 5000  && dataNRF.rpm < 6000 ) {leds = B10000000;}
      if (dataNRF.rpm > 6000  && dataNRF.rpm < 7000 ) {leds = B11000000;}
      if (dataNRF.rpm > 7000  && dataNRF.rpm < 8000 ) {leds = B11100000;}
      if (dataNRF.rpm > 8000  && dataNRF.rpm < 9000 ) {leds = B01110000;}
      if (dataNRF.rpm > 9000  && dataNRF.rpm < 10000) {leds = B00111000;}
      if (dataNRF.rpm > 10000 && dataNRF.rpm < 11000) {leds = B00011100;}
      if (dataNRF.rpm > 11000 && dataNRF.rpm < 12000) {leds = B00001110;}
      if (dataNRF.rpm > 12000                       ) {leds = B00000111;}
      updateShiftRegister(); //update the shift register to light up the corresponding LEDs
    }
    
    
    
    /* ========================================================================================= */
    /* UPDATE SHIFT REGISTER */
    /* ===================== */
    void updateShiftRegister() {
      digitalWriteFast(6, LOW);        // (latchPin(ST), LOW);
      shiftOut(5, 10, LSBFIRST, leds);// (dataPin(DS), clockPin(SH), LSBFIRST, leds)
      digitalWriteFast(6, HIGH);     // (latchPin(ST), HIGH);
    }
    
    
    
    /* ========================================================================================= */
    /* CALCULATE THE BPM */
    /* ================= */
    void bpm() {
      reading = analogRead(A15);
      if (reading > UpperThreshold && IgnoreReading == false) { // Heart beat leading edge detected
        if (FirstPulseDetected == false) {
          FirstPulseTime = millis();
          FirstPulseDetected = true;
        } else {
          SecondPulseTime = millis();
          PulseInterval = SecondPulseTime - FirstPulseTime;
          FirstPulseTime = SecondPulseTime;
        }
        IgnoreReading = true;
      }
      if (reading < LowerThreshold && IgnoreReading == true) { // Heart beat trailing edge detected
        IgnoreReading = false;
      }
      dataNRF.BPM = round((1 / PulseInterval) * 60 * 1000);
    }
    
    
    /* ========================================================================================= */
    /* PHARSE THE GPS DATA */
    /* =================== */
    void gps_data(){
      while (Serial8.available()) {// if receiving data from GPS
        char c = Serial8.read();
        if (c == '\n') {         // if the received character is the endline (\n or \r)
          if (nmea) {           // if the characters received have been appended to nmea string
            nmea = false;      // turn off the nmea flag so that the next characters are stored in the nmea2 string
          }
          if (!nmea) {       // if the characters received have been appended to nmea2 string
            nmea = true;    // turn off the nmea2 flag so that the next characters are stored in the nmea string
          }
        }
    
        if (nmea)  {
          GpsNmea1Buf += c; // add characters received in Serial7 to the NMEA 1 buffer
        }
        if (!nmea) {
          GpsNmea2Buf += c; // add characters received in Serial7 to the NMEA 2 buffer
        }
    
        gps.handle(c);  // parse the GPS data in the NeoGPS library
    
        // Did 'handle' finish making a new fix structure?
        if (gps.available() && (c == 0x0A)) { // wait for last LF char
          fix = gps.read();          // yes, a fix structure is ready (10Hz)
          GpsNmea1 = GpsNmea1Buf;   // put the contents of the nmea buffer1 in the GPSNmea1 string that will be printed to serial
          GpsNmea1Buf = "";        // empty the NMEA 1 buffer
          GpsNmea2 = GpsNmea2Buf; // put the contents of the nmea buffer2 in the GPSNmea2 string that will be printed to serial
          GpsNmea2Buf = "";      // empty the NMEA 2 buffer
          GPScounter = fix.dateTime.hours + fix.dateTime.minutes + fix.dateTime.seconds + '.' + fix.dateTime_cs;
        }
      }
    }
    
       
    /* ========================================================================================= */
    /* CALCULATE ACC and BRK VALUES */
    /* ============================ */
    void accBrk(){
      ACCELERATION.update();                // update the ACC analog value to be smoothed out
      BRAKE.update();                      // update the BRK analog value to be smoothed out
      accValue = ACCELERATION.getValue(); // used instead of the analogRead() function. returns much more stable readings.
      brkValue = BRAKE.getValue();       // used instead of the analogRead() function. returns much more stable readings.
      dataNRF.acceleration = ((accValue - zeroAccValue) * 100L) / (fullAccValue - zeroAccValue); //calculates the percentage the acc pedal is pressed
      dataNRF.brake = ((brkValue - zeroBrkValue) * 100L) / (fullBrkValue - zeroBrkValue);       //calculates the percentage the brk pedal is pressed
    }
    
    
    /* ========================================================================================= */
    /* READ the STEERING ANGLE */
    /* ======================= */
    void steering(){
      STEERING.update();
      dataNRF.str = STEERING.getValue();
    }
    /* ========================================================================================= */
    /* READ RAW MPU6050 DATA */
    /* ===================== */
    void gforce() {
      Wire.beginTransmission(0x68); // start communicating with the MPU
      Wire.write(0x3B);            // set byte 0x3B to indicate start register
      Wire.endTransmission();     // terminate the connection
      Wire.requestFrom(0x68, 6); // request 6 bytes from MPU
      acc_x = Wire.read() << 8 | Wire.read();    // Shift high byte left and add low and high byte to acc_x
      acc_y = Wire.read() << 8 | Wire.read();   // Shift high byte left and add low and high byte to acc_y
      acc_z = Wire.read() << 8 | Wire.read();  // Shift high byte left and add low and high byte to acc_z
      rawX += acc_x;
      rawY += acc_y;
      x += 1;
      
      /*
      acc_x = (int16_t)(Wire.read() << 8 | Wire.read()) / 16384.0;
      acc_y = (int16_t)(Wire.read() << 8 | Wire.read()) / 16384.0;
      acc_z = (int16_t)(Wire.read() << 8 | Wire.read()) / 16384.0;
      */
    }
    
    
    
    /* ========================================================================================= */
    /* AVERAGE THE MPU6050 DATA */
    /* ======================== */
    void avgGforce() {
      /* 2g sensitivity */
      dataNRF.avgXx = (rawX / x) * 0.061 / 1000;
      dataNRF.avgYy = (rawY / x) * 0.061 / 1000;
    
      /* 4g sensitivity */
      //dataNRF.avgXx = (rawX/x) * 0.122 / 1000;
      //dataNRF.avgYy = (rawY/x) * 0.122 / 1000;
      
      /* 8g sensitivity */
      //dataNRF.avgXx = (rawX / x) * 0.244 / 1000;
      //dataNRF.avgYy = (rawY / x) * 0.244 / 1000;
    
      /* 16g sensitivity */
      //dataNRF.avgXx = (rawX/x) * 0.732 / 1000;
      //dataNRF.avgYy = (rawY/x) * 0.732 / 1000;
      x = 0; // reset the counter for the average of MPU
      rawX = 0;
      rawY = 0;
    }
    If I comment out the following two lines of code from the Audio portion, the SPI bus works well.

    Code:
    AudioInputI2S            i2s1;
    Code:
    AudioOutputI2S           i2s2;
    I will check the SPI mode mentioned by PaulS and also if I use any of the i2s pins for the MAX31855 ICs.

    What could the problem be since commenting out the two lines above eliminates the problem? Obviously I need the i2s functionality in the code so I have to find a way to make it work without commenting out the two lines of code from the Audio library.

    Thank you very much.

  8. #8
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Quote Originally Posted by guzu View Post
    If I comment out the following two lines of code from the Audio portion, the SPI bus works well.
    Just checking: do you mean that SPI is now working well with 2 populated MAX13855's?

    Paul

  9. #9
    Quote Originally Posted by PaulS View Post
    Just checking: do you mean that SPI is now working well with 2 populated MAX31855's?

    Paul
    Yes. If I do not comment out the two lines of code in post #6, the oled and NRF24 modules (both connected to the SPI bus) do not work as expected. A lot of noise is displayed on the oled, the NRF24 module works intermittently, and sometimes the SPI bus just stops working (the display turns black, the led on pin 13 of the Teensy (SCK) stops blinking, and data is no longer transmitted with the NRF module)

    If I solder just one MAX31855 IC on the PCB everything works fine.
    If I solder both MAX31855 ICs on the PCB and comment out the two lines of code in post #6 everything works fine.

    Could it be something related to the audio and MAX31855 libraries?

  10. #10
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Quote Originally Posted by guzu View Post
    Could it be something related to the audio and MAX31855 libraries?
    Yep, that's my guess as well. Not sure why though. I may look into the Adafruit MAX31855 library and underlying libraries later today.

    Paul

  11. #11
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Looked into the Adafruit MAX31855 library and underlying libraries but did not spot a problem.
    So I decided to hook up a logic analyzer and check for collisions on the SPI bus:

    Click image for larger version. 

Name:	logicanalyzer0.jpg 
Views:	15 
Size:	83.5 KB 
ID:	21332

    Took the long code from your message #6, downloaded the required libraries, commented out the TVG logo stuff, added a while(!serial) to have time to arm the logic analyzer, and added intialization for pin 25 [CS for nRF24L01]. Left the AudioInputI2S and AudioOutputI2S in. Modified code is attached below.
    Then ran the logic analyzer:

    Click image for larger version. 

Name:	logicanalyzer1.png 
Views:	14 
Size:	34.9 KB 
ID:	21333

    I have zoomed in on every CS [legend on the left of the image]: no collisions!
    Here is a zoomed-in snap at around 2.2secs where you can see all four CS's active after eachother.:

    Click image for larger version. 

Name:	logicanalyzer2.png 
Views:	13 
Size:	31.7 KB 
ID:	21334

    MISO is obviously not showing activity since I did not connect any peripherals.

    Not sure what to do next...
    I will leave the logic analyzer setup on my desk, so if you want me do more measurements let me know.
    [you may want to purchase this logic analyzer, it helped me a lot in debugging]

    Paul
    Attached Files Attached Files

  12. #12
    Senior Member
    Join Date
    Jul 2020
    Posts
    398
    Quote Originally Posted by PaulS View Post
    Not sure what to do next...
    I will leave the logic analyzer setup on my desk, so if you want me do more measurements let me know.
    Can you put a 'scope on the SPI bus lines? A logic analyzer won't show things like bad voltages due to colliding outputs,
    or bad crosstalk / ringing...

  13. #13
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Quote Originally Posted by MarkT View Post
    Can you put a 'scope on the SPI bus lines? A logic analyzer won't show things like bad voltages due to colliding outputs,
    or bad crosstalk / ringing...
    Are you asking me? I don't have the peripherals that output data on the MISO line, just the bare Teensy 4.1.
    The OP indicated that he does not have a scope at his disposal.

    Paul

  14. #14
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Just found out that if you download and install the DSview software, you can then open the attached .DSL file [zipped] below and look & zoom into the captured waveforms yourself!

    Paul
    Attached Files Attached Files

  15. #15
    Thank you very much PaulS for taking the time to test my code.
    It is very weird indeed because I tried just soldering the two MAX31855 ICs and powering the PCB without any code to initialize or use the ICs. The problem is still present.
    So I think that it has something to do with the Audio library maybe?

    Could anyone tell me what the two lines of code in post #6 do exactly? Is there any change done to the way Teensy uses it's pins when these lines of code are compiled?

    I triple checked my PCB (the connections, footprints and soldering) and I could not find anything wrong with it. In fact, the Teensy can read the temperature from the MAX31855 ICs, display it and transmit it using the NRF module (until the SPI bus stops working).

    I have no idea on what to check next. But I am now inclining to think that this is a physical problem either with one of the MAX31855 ICs or with something else, since the problem is dependent on both the ICs being soldered on the PCB.
    If anyone has any other ideas on what I could do, please tell me.

    Quote Originally Posted by PaulS View Post
    Just found out that if you download and install the DSview software, you can then open the attached .DSL file [zipped] below and look & zoom into the captured waveforms yourself!

    Paul
    Thank you very much. I will try it.

  16. #16
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    As far as I understand those 2 lines instantiate 2 audio objects that you can use for audio input and output. It will probably incorporate a whole bunch of software under the hood. But I'm not familiar with the inner works of the audio library - I just use it...
    Those 2 objects should not interfere with the SPI bus though.

    By the way: if I only comment out those 2 lines, compilation will throw and error: 'i2s1' was not declared in this scope.

    Paul

  17. #17
    Quote Originally Posted by PaulS View Post
    As far as I understand those 2 lines instantiate 2 audio objects that you can use for audio input and output. It will probably incorporate a whole bunch of software under the hood. But I'm not familiar with the inner works of the audio library - I just use it...
    Those 2 objects should not interfere with the SPI bus though.

    By the way: if I only comment out those 2 lines, compilation will throw and error: 'i2s1' was not declared in this scope.

    Paul
    You get that error while compiling because the i2s1 and i2s2 objects are used a little down the road in the code.
    Commenting these other 4 lines will allow you to compile (but the Audio portion of the code will not work).

    Code:
    // GUItool: begin automatically generated code
    AudioInputI2S            i2s1;
    AudioPlayQueue           queue2;
    AudioMixer4              mixer2;
    AudioMixer4              mixer1;
    AudioOutputI2S           i2s2;
    AudioRecordQueue         queue1;
    AudioConnection          patchCord1(i2s1, 0, mixer1, 0);
    AudioConnection          patchCord2(i2s1, 1, mixer1, 1);
    AudioConnection          patchCord3(queue2, 0, mixer2, 0);
    AudioConnection          patchCord4(mixer2, 0, i2s2, 0);
    AudioConnection          patchCord5(mixer2, 0, i2s2, 1);
    AudioConnection          patchCord6(mixer1, queue1);
    AudioControlSGTL5000     sgtl5000_1;
    // GUItool: end automatically generated code

  18. #18
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Just checking that we are on the same page... I also assumed that those 4 lines had to be commented out as well.
    Anyway, no (obvious) changes to the waveforms after compiling, uploading and running with the 6 lines commented out.

    Paul

  19. #19
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    @ Guzu: did you (re)check all the wiring from connector U6 to the off-board components? I see the SSOLED, SCK and MOSI signals going off-board. If one of those signals short to a neighboring signal or crosstalk is happening, than it could corrupt the SPI bus.
    Another idea is to only connect the OLED display [so no other external parts] to connector U6 and check for SPI functionality.

    Paul

  20. #20
    Quote Originally Posted by PaulS View Post
    @ Guzu: did you (re)check all the wiring from connector U6 to the off-board components? I see the SSOLED, SCK and MOSI signals going off-board. If one of those signals short to a neighboring signal or crosstalk is happening, than it could corrupt the SPI bus.
    Another idea is to only connect the OLED display [so no other external parts] to connector U6 and check for SPI functionality.

    Paul
    I will disconnect everything else but the oled tomorrow and see if this changes anything.
    The SSOLED, SCK and MOSI going out go to the oled. At the oled side there are two RJ45 connectors so I think there is not a problem there with crosstalk.

  21. #21
    I finally got the time to do some more testing.
    This is what I know so far (on top of what I already mentioned in the last posts):

    • If I disconnect everything from the U6 connector (including the Oled) the problem is still present. (I can see this by the way the SCK led blinks erratically)
    • If I leave everything connected (including the oled) and disconnect just the NRF24 module, everything works


    What could the problem be?

  22. #22
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    Quote Originally Posted by guzu View Post
    [*]If I leave everything connected (including the oled) and disconnect just the NRF24 module, everything works
    Just checking again: "everything" means [1] both MAX13855's work and [2] audio input/output works?

    I guess we now have to dig into the nRF24 module and related firmware.

    Paul

  23. #23

    Talking

    Quote Originally Posted by PaulS View Post
    Just checking again: "everything" means [1] both MAX13855's work and [2] audio input/output works?

    I guess we now have to dig into the nRF24 module and related firmware.

    Paul
    So after a few more tests I noticed that even if I unplug the NRF24 module from the PCB the problem is still present. A lot less noise on the screen and a lot less frequent, but I can see that it is not gone. When I `hot plug` the NRF24 module on the PCB while the Teensy is running, a lot of noise appears on the oled. When I remove it, a lot less noise on the oled.
    I tried removing all the code for the NRF24 module and it did not solve the problem.

    As far as I can see, the problem is with the physical presence of the NRF24 module and both the MAX31855 ICs on the PCB. I am inclined to think that this is not a software issue but then again, removing the 2 lines of code in post #6 solves the problem. Only removing both lines of code in post #6 solves the problem. Removing just one of them does nothing. So I don't know where to go next

    Could it be that I need some pull down resistors for the SCK, MOSI and MISO lines?

  24. #24
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    298
    I guess it's time now to borrow an oscilloscope somewhere and check the SPI lines and DC voltages on the different parts for analog phenomena.
    Looking at the schematic again: what is the powersupply for all 3V3 parts? Is it Q1? Or is it the Teensy?
    I would focus on the power supplies now. Are the AMS1117's running hot?

    Paul

  25. #25
    Quote Originally Posted by PaulS View Post
    Looking at the schematic again: what is the powersupply for all 3V3 parts? Is it Q1? Or is it the Teensy?
    I would focus on the power supplies now. Are the AMS1117's running hot?

    Paul
    The power supply for the 3V3 parts is Q1. It is a LDO capable of supplying up to 1A of power. This LDO in not getting hot at all. It is just warm.
    The Q2 5V LDO is getting hot only when I connect a battery with higher voltage (over 11V) which I think is normal given that the 5V LDO is capable of handling max 16V on the Vin.
    I ran some checks with the power. I don't think this is the problem since I powered the Teensy with just a couple of modules connected (way less power that the LDOs can provide) and I still got jitters on the SPI devices.

    PaulS considering that this is taking a bit too much of your (and my) limited time and I do not have an oscilloscope to test further, whenever you get bored of fed up with troubleshooting feel free to tell me to just desolder one of the MAX31855 ICs and read just one temperature.

Posting Permissions

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