(INVSTATE) Instruction makes illegal use of EPSR

anbolge

Member
Hi everyone

I am Running a desk clock basd on Teensy 4.1. The clock is working flowleslly for 29 days straight, however, when the life time reaches exactly 30 days +/- a few hours the hardware reboots. I orignially thought that maybe the reason was the the use of SD card for logging - so i disabled it, than i thought maybe it is a power issue, so i upgraded the power path and also included the capacitors, however today it has restarted again :(

I run Basic CrashReport and got the following error:

18:51:36.169 -> CrashReport:
18:51:36.169 -> A problem occurred at (system time) 15:6:0
18:51:36.169 -> Code was executing from address 0x1500
18:51:36.169 -> CFSR: 20000
18:51:36.169 -> (INVSTATE) Instruction makes illegal use of EPSR)
18:51:36.169 -> Temperature inside the chip was 59.67 °C
18:51:36.169 -> Startup CPU clock speed is 720MHz

Since the life time is the same (it happened to me already 4 times) and because there is an error report - it seems that the issue is not in the hardward but in the code. However, i am not really sure how to interpret the data.

Andrey
 
Are you using the processor's RTC? How are you updating your clock? It's impossible to say what might be wrong unless you share details (code).
 
I am using external temperature controlled 10MHZ oscilator, for which I count pulses via HZ() interrupt. And since my target was to get under 1 sec a year, i also have external GPS module, that submits PPS signal twice a second via Control() interrupt. I than comare resullts of my count vs GPS to see how much of a drift there is. The code is big and not really very professional, as i am not developer.
Code:
#include <TinyGPSPlus.h>
#include <SoftwareSerial.h>
#include <EEPROM.h>
#include <TimeLib.h>            //this is needed to read internal time
#include <Wire.h>               //this is needed for light sensor
#include "Adafruit_VEML7700.h"  //this is needed for light sensor
static const int RXPin = 1, TXPin = 0;  //GPS - Rx wire on GPS to 1, Tx to 0
const int buttonPin1 = 24, buttonPin2 = 25;  // push button 1 is to allign, 2 for resetting OCXO
const int buttonPin3 = 9, buttonPin4 = 10;   //
const byte Main_Pin = 34;              //OCXO 5MHz
const byte Control_Pin = 22;           //NEO PPS pin 2x per second
const int ledPin = 13;                 // led on the arduino itself
SoftwareSerial DisplaySerial(28, 29);  // RX, TX
Adafruit_VEML7700 sensor = Adafruit_VEML7700();
static const uint32_t GPSBaud = 9600;
long TicsPerMinute = 300000540;
volatile boolean gps_start = 1;  //is used to show when GPS has been initialized, i.e. location was fixed
volatile boolean pps_start = 1;  //this is needed when pps signal was not avilable from the start, thus additional 2 minutes of allignemnt is needed
volatile boolean allign = 0;     // 1 - match time and 0 - not
volatile boolean allign2 = 0;
volatile boolean pps_live = 0;  // 1 - match time and 0 - not
int Time_Zone = 2;              //delta to be added to UTC time received from GPS: 1=winter and 2=summer
int o_Time_Zone = 2;
long startSeconds;      // execute update time every second, when startSeconds change
long TotalSeconds = 0;  //counting uninterrupted days of work via GPS
int buttonState1 = 0, buttonState2 = 0, buttonState3 = 0, buttonState4 = 0;
int Prev_buttonState1 = 0, Prev_buttonState2 = 0, Prev_buttonState3 = 0, Prev_buttonState4 = 0;
int Pushed_button1 = 0, Pushed_button2 = 0, Pushed_button4 = 0;
long sec_buttonState1 = 0, sec_buttonState2 = 0, sec_buttonState4 = 0;
int Hour, Hours, Minutes, Seconds, xMinutes = 99;
int Brightness = 3;     //bright
int min_to_ignore = 3;  // 0 - bright outside; 999 - dark
int Prev_is_night_state = 0;
int mario_i = 1, mario_x = -33;
int allign2_count, allign2_delta;
int b = 100, b0 = 100;  //brightness in nextion format
//int light_data;
//uint16_t lux; //brightness from sensor
char Satellites[3];
float forecasted_dev_in_sec;
char log_filename[40];

volatile long HZCount = 0;                                                 // use volatile for shared variables
volatile long HZCopy, HZTotal, HZStart, TicsPerSecond, TicsPerHalfSecond;  // holds a copy of the count
volatile long oSeconds;
long oDays, oHours = 0, oMinutes = 0, oTotalSeconds2, oTotalSeconds1, oTotalSeconds3, oTotalSeconds4, TicsPerDay, TicsPerYear, GPSCopy, GPSTotal;  //o is for ocxo from start
volatile long i, j, J, i_check, j_check;
long currHours, currMinutes, pps_error, pps_shift, pps_i;  // ocxo alligned time
TinyGPSPlus gps;                      // The TinyGPSPlus object
SoftwareSerial ss(TXPin, RXPin);      // The serial connection to the GPS device
TinyGPSCustom sats(gps, "GPGSV", 3);  //GPGSV - is for GPS satellites only, number of sats (3rd value in the line)

void setup() {
  Serial.begin(9600);
  DisplaySerial.begin(9600);
  ss.begin(GPSBaud);
  Serial.println(F("OCXO + Satellite Clock. Andrey Bolger"));

  pinMode(ledPin, OUTPUT);            // initialize Led
  pinMode(buttonPin1, INPUT_PULLUP);  // allign time like from the start
  pinMode(buttonPin2, INPUT_PULLUP);  // reset counts only : button 1 for resetting OCXO count and times
  pinMode(buttonPin3, INPUT_PULLUP);  // brightness
  pinMode(buttonPin4, INPUT_PULLUP);  // fine tune: perform 1 hour delta calc
  //pinMode(LDIO, INPUT);
  pinMode(Main_Pin, INPUT_PULLUP);       //ocxo setup
  pinMode(Control_Pin, INPUT_PULLDOWN);  //seconds pin, changed to down as signal was not reliable
  attachInterrupt(digitalPinToInterrupt(Main_Pin), HZ, RISING);
  attachInterrupt(digitalPinToInterrupt(Control_Pin), Control, RISING);
  digitalToggleFast(digitalPinToInterrupt(Main_Pin));
  digitalToggleFast(digitalPinToInterrupt(Control_Pin));
  TicsPerSecond = TicsPerMinute / 60;
  TicsPerHalfSecond = TicsPerMinute / 120;


  NVIC_SET_PRIORITY(IRQ_GPIO6789, 9);
  if (!sensor.begin()) {
    Serial.println("Error reading VEML7700");
  }
}
void HZ() {
  HZCount = HZCount + 1;
}
void Control() {
  //is triggered 2 times a second
  //PPS signal may be not updated, i.e. value of J may not be set to value of j, bacuse it only happens in the first half seconds
  //and if GPS PPS signal is not synced it only sends signal once a second, which could easily fall in the second half of a second
  if ((oSeconds == 0) and (HZCount < (TicsPerHalfSecond))) {  // this section triggered only once a minute for first tic
    HZCopy = HZTotal;
    HZTotal = HZCount;
    i++;  // this variable is not get resetteded, however since it is long it will take forever to get it to overflow
    // i - is the count of uninterrupted minutes when we receive a pps signal on a first half of a zero second
    J = j;  // we need to copy it here, since j updating is way too fast for the program to catch up reliably
    j = 0;  // J is the count of PPS per minute, j is a variable that makes that count
  }
  j++;
}
void loop() {
  String Line5;
  //long xSeconds;
  Buttons();
  //ocxo processing
  OCXO_time();
  //gps module processing
  while (ss.available() > 0) {
    if (gps.encode(ss.read())) {
      if (gps_start == 1) {
        if (Satellites != sats.value()) {
          Line5 = "GPS signal detected, connecting to settelites, current number: " + String(sats.value());
          Serial.println(Line5);
          char temp[16];
          sprintf(temp, "%s", sats.value());
          DisplaySerial.print(F("t4.txt=\"GPS signal detected, sats: "));
          DisplaySerial.print(temp);
          DisplaySerial.print(F("\""));
          DisplaySerial.print(F("\xFF\xFF\xFF"));
        }
      }
      if (gps.time.second() != startSeconds) {                // execute update time every second, when startSeconds change
        if ((gps_start == 1) and (atoi(sats.value()) > 6)) {  //==3 satellites is not enought for accurate timing, changed to 5 or more
          //Serial.println("xdx");
          gps_start = 0;
          allign = 1;
        }
        GPS_time();
        startSeconds = Seconds;
      }
    }
  }
}
void OCXO_time() {
  String Line6;
  if (HZCount > TicsPerMinute) {
    HZCount = 0;  //we can not hold tics for more than 1 minuter
    //workout minutes first
    oMinutes++;
    if (min_to_ignore > 0) {
      min_to_ignore--;
      //i_check ++; //bring up to speed value during warm up time
    }
    if (oMinutes > 59) {
      oMinutes = 0;
      oHours++;
      if (oHours > 23) {
        oHours = oHours - 24;
        oDays++;
        TicsPerDay = 0;
      }
    }
    currMinutes++;
    if (currMinutes > 59) {
      currMinutes = 0;
      currHours++;

      //  Serial.println("befor time zone check");
      if (o_Time_Zone != Time_Zone) {  //adjust summer and winter time
        currHours = currHours - o_Time_Zone + Time_Zone;
        o_Time_Zone = Time_Zone;
        //    Serial.println("see if check worked out");
      }
      //Serial.println(oHours);



      if (currHours > 23) currHours = 0;
      mario_x = -33;
      mario_i = 0;
    }

    //OCXO_Total_Time_Output();
  }
  //work on seconds
  oSeconds = HZCount / TicsPerSecond;

  if ((oSeconds != oTotalSeconds2) and (oSeconds < 60)) {  //for very short time it could be equal to 60 but we ignore it
    oTotalSeconds2 = oSeconds;
    oTotalSeconds3 = HZTotal - HZCopy;
    if ((oTotalSeconds3 < 800) and (oTotalSeconds3 > -800) and (min_to_ignore == 1) and (oTotalSeconds2 == 1)) {  //macro adjustment at the start
      TicsPerMinute = TicsPerMinute + oTotalSeconds3;
      TicsPerSecond = TicsPerMinute / 60;
      TicsPerHalfSecond = TicsPerMinute / 120;
      Line6 = "Delta tics added to adjust standard frq: " + String(oTotalSeconds3) + " hzcount: " + String(HZTotal) + " hzcopy: " + String(HZCopy);
      Serial.println(Line6);
      oMinutes = -1;
      oDays = 0;
      oHours = 0;
      //HZStart = HZTotal; not used it seems
      if ((pps_start == 1) and (oTotalSeconds3 != 0)) pps_start = 0;  //this is needed when pps signal is there from the start
                                                                      //delta to do
                                                                      //  Serial.println(oTotalSeconds2);
    }
    if ((pps_start == 1) and (i > 0) and (J > 118) and (J < 122)) {  //if accuracy of pps from GPS is not there, thus additional 2 minutes of allignemnt is added by setting allign value to 1
      Serial.println("PPS signal detected with 120bpm, OCXO fine tuning will start from the next minute");
      allign = 1;
      pps_start = 0;
    }
    /*
    if ((min_to_ignore == 0) and (oTotalSeconds2 == 1) and (i > 1)) { 
      //logic to ignore deviations (HZTotal - HZCopy) if there is no pps, when operation is stable
      //Serial.print(i);
      //Serial.println("-if");
      if ((J > 118) and (J < 122)) {
        //pps signal is locked
        //pps_start=0;
        //Serial.println("PPS is live");  //currently i decided not to use it and stuck with signal once a sec
      } */
    if (((i - i_check) >= 1) and (oTotalSeconds2 == 1) and (oTotalSeconds3 < 200) and (oTotalSeconds3 > -200) and (min_to_ignore == 0)) {  //OLD : i changed it to when i is only changing, pps_live simply means Control procedure is working once a minute
                                                                                                                                           //new: once a minute (oTotalSeconds2 on a first sec) check if count has changed - if yes, we have a PPS signal, if no, we have not received a PPS signal this minute
      //this is just for reporting purposes to know if gps is live or not
      i_check = i;
      //Serial.println("we get signal once a sec");
      pps_live = 1;
    } else if (((i - i_check) < 1) and (oTotalSeconds2 == 1)) {
      //Serial.print("we DO NOT get signal once a sec");
      //Serial.print(i); Serial.print(":");
      //Serial.println(i_check);
      pps_live = 0;        // see if above, only gets updated when i>1 and min_to_ignore=0
      HZCopy = HZTotal;    //no signal, thus we need to reset deviations and store old value of deviation
      oTotalSeconds3 = 0;  //reset current min delta
      i = 0;               //start count of minutes from the start, i - is the count of uninterrupted minutes when we receive a pps signal on a first half of a zero second
      i_check = 0;         //reset this so that next minute we can check the result again
      J = 0;               //reset pps, not necessary, but helps getting cleaner data
    }
    //}
    if ((oTotalSeconds3 < 800) and (oTotalSeconds3 > -800) and (min_to_ignore == 0) and (oTotalSeconds2 == 1)) {
      //the reason here to exclude deviation of over 800 is because they are typically happen not because of the shift in timing of the crystal, but rather because gps PPS signal somehow shifts (for example when TX pin is taken out occasionaly it could result in PPS signal shift in a few thousands )
      TicsPerDay = TicsPerDay + HZTotal - HZCopy;
      TicsPerYear = TicsPerYear + HZTotal - HZCopy;
      //  Serial.println(oTotalSeconds2);
    }
    //edge cases when tics move out of current range to the right (i assume max deviation of 300 tics per minute here)
    else if ((oTotalSeconds3 < (-TicsPerHalfSecond + 300)) and (oTotalSeconds3 >= (-TicsPerHalfSecond)) and (HZTotal < 300) and (min_to_ignore == 0) and (oTotalSeconds2 == 1)) {  //ingnore deviations of over 800 as unrealistic
      //here internal watch moves faster, i.e. for each second tic it takes more tics than in TicsPerHalfSecond
      TicsPerDay = TicsPerDay + TicsPerHalfSecond + HZTotal - HZCopy;
      TicsPerYear = TicsPerYear + TicsPerHalfSecond + HZTotal - HZCopy;
      oTotalSeconds3 = TicsPerHalfSecond + oTotalSeconds3;
      Serial.println("Lucky you, seconds shifted Right");
    } else if ((oTotalSeconds3 > (TicsPerHalfSecond - 300)) and (oTotalSeconds3 <= TicsPerHalfSecond) and (HZCopy < 300) and (min_to_ignore == 0) and (oTotalSeconds2 == 1)) {  //ingnore deviations of over 800 as unrealistic
      TicsPerDay = TicsPerDay + HZTotal - HZCopy - TicsPerHalfSecond;
      TicsPerYear = TicsPerYear + HZTotal - HZCopy - TicsPerHalfSecond;
      oTotalSeconds3 = oTotalSeconds3 - TicsPerHalfSecond;
      Serial.println("Lucky you, seconds shifted Left");                           //internal watch moves slower
    } else if ((min_to_ignore == 0) and (oTotalSeconds2 == 1) and (pps_i != i)) {  //it looks like the shift happends whem pps_live == 0
      //we are outseide of deviation range, which is mosty due to shift in PPS signal;
      //pps_i is needed to ignore situation when Control procedure for Seconds and HZCount is not fullfiled, thus HZTotal and HZCopy not being actualized
      pps_shift = pps_shift + HZTotal - HZCopy;
      pps_error++;
      pps_i = i;
    }
    if ((oTotalSeconds2 == 1) and (allign2 == 1)) {
      if ((pps_live == 0) or (min_to_ignore > 0) or (oTotalSeconds3 > 200) or (oTotalSeconds3 < -200)) {
        //restart delta count if pps signal interrupted, or we have not alligned the clockes or drift in the clock is outside 200 tics
        allign2_count = 0;
        allign2_delta = 0;
      } else {
        allign2_count++;
        allign2_delta += oTotalSeconds3;
        if (allign2_count == 80) {
          allign2 = 0;
          allign2_count = 0;
          TicsPerMinute += allign2_delta / 80;
          Line6 = "Delta tics added to adjust standard frq: " + String(allign2_delta / 80);
          Serial.println(Line6);
        }
      }
    }
    if (gps_start == 0) {
      if (oTotalSeconds2 == 1) {
        OCXO_Serial_Output();  //WORKING
        DisplayPPS();
      }
      mario_i++;
      if ((oTotalSeconds2 == 2)) {
        DisplayDelta();
        DisplayLifeDelta();
        //DisplayBrightness();
      }
      if ((oTotalSeconds2 == 3)) {
        DisplayLifeTime();
        DisplayGraph(oTotalSeconds3);
      }
      DisplayTime();
      DisplayMario();
    }
  }
}

void OCXO_Serial_Output() {
  String Line3;
  char logdata[500];
  forecasted_dev_in_sec = TicsPerYear * ((365 * 24 * 60) / (oDays * 24 * 60 + oHours * 60 + oMinutes));
  forecasted_dev_in_sec = forecasted_dev_in_sec / 5000000;

  Line3 = "PPS_live " + String(pps_live) + " OCXO time HH:MM:SS " + String(currHours) + ":" + String(currMinutes) + ":" + String(oSeconds)
          + " pps_e:pps_s:i " + String(pps_error) + ":" + String(pps_shift) + ":" + String(i) + " min_to_ignore:a2_cnt " + String(min_to_ignore) + ":" + String(allign2_count) + " PPS: " + String(J)
          + " last:curr min tics: " + String(HZCopy) + ":" + String(HZTotal) + " delta per min: " + String(oTotalSeconds3) + " delta per day:year "
          + String(TicsPerDay) + ":" + String(TicsPerYear) + " life time DD:HH:MM " + String(oDays) + ":" + String(oHours) + ":" + String(oMinutes) + " annual accuracy in Sec:" + String(forecasted_dev_in_sec, 4);
  if (pps_live == 0) Line3 = Line3 + " approximate!";
}

void OCXO_Total_Time_Output() {
  //debuggin print out
  String Line4;
  //Line4 = "OCXO Days in operation "+ String(oDays) + " online time "  + String(oHours) + ":"+ String(oMinutes) + ":"+ String(oSeconds)+ " deviation per minute: "+ String(HZCopy)+ " per day: "+ String(HZTotal);
  Line4 = " HZ:" + String(HZCount) + " i:" + String(i) + " a:" + String(allign) + " copy: " + String(HZCopy) + " total: " + String(HZTotal);
  Serial.println(Line4);
}
void GPS_Serial_Output() {
  String Line1, Line_Bckp_Ovf;  //line 1 standard length with sats 69 and line 2 is 59 with 1 years of data
  Line1 = "GPS sats: " + String(sats.value());
  Line1 = Line1 + " Location: ";
  if (gps.location.isValid()) {
    Line1 = Line1 + String(gps.location.lat(), 6) + "," + String(gps.location.lng(), 6);  //sizeof(gps.location.lat()) somehow return 4
  } else {
    Line1 = Line1 + "INVALID";
  }
  Line1 = Line1 + " Date/Time: ";
  if (gps.date.isValid()) {
    Line1 = Line1 + String(gps.date.day()) + ":" + String(gps.date.month()) + ":" + String(gps.date.year());
  } else {
    Line1 = Line1 + "INVALID";
  }
  Line1 = Line1 + "/";
  if (gps.time.isValid()) {
    if ((gps.time.hour() + Time_Zone) >= 24) {
      Line1 = Line1 + "0";
      Line1 = Line1 + String(gps.time.hour() + Time_Zone - 24) + ":";
    } else {
      if ((gps.time.hour() + Time_Zone) < 10) Line1 = Line1 + "0";
      Line1 = Line1 + String(gps.time.hour() + Time_Zone) + ":";
    }
    if (gps.time.minute() < 10) Line1 = Line1 + "0";
    Line1 = Line1 + String(gps.time.minute()) + ":";
    if (gps.time.second() < 10) Line1 = Line1 + "0";
    Line1 = Line1 + String(gps.time.second());
  } else {
    Line1 = Line1 + "INVALID";
  }
  Serial.println(Line1);
}
void GPS_Total_Time_Output() {
  String Line2, Line_Bckp_Ovf;  //line 1 standard length with sats 69 and line 2 is 59 with 1 years of data

  unsigned long lDays = TotalSeconds / 60 / 60 / 24;
  unsigned long lHours = (TotalSeconds - (lDays * 60 * 60 * 24)) / 60 / 60;
  unsigned long lMinutes = (TotalSeconds - (lDays * 60 * 60 * 24) - (lHours * 60 * 60)) / 60;
  unsigned long lSeconds = TotalSeconds - lDays * 60 * 60 * 24 - lHours * 60 * 60 - lMinutes * 60;
  Line2 = "GPS uninterrupted work: " + String(lDays) + " Days " + String(lHours) + " Hours " + String(lMinutes) + " Minutes " + String(lSeconds) + " Seconds";
  Serial.println(Line2);
}
void GPS_time() {
  String Line1, Line2, Line_Bckp_Ovf;                                  //line 1 standard length with sats 69 and line 2 is 59 with 1 years of data
                                                                       //xminutes is used to display time additional time extra for when display is refreshed, in this case it will be equal to time
  if ((Hours != gps.time.hour()) or (Minutes != gps.time.minute())) {  //or (xMinutes == gps.time.minute())) {
    Hours = gps.time.hour();
    DST();
    Hour = gps.time.hour() + Time_Zone;  //hour is in local time zone
    if (Hour >= 24) Hour = Hour - 24;
    Minutes = gps.time.minute();
    //GPS_Total_Time_Output(); //WORKING
    //xMinutes = 99;
  }
  if (Seconds != gps.time.second()) {

    TotalSeconds++;
    Seconds = gps.time.second();
    if (allign == 1) {
      HZCount = TicsPerSecond * Seconds + TicsPerSecond / 4;  //i added small delta for allignment, because the update time on display is a bit lagging, or programming logic is lagging
      currMinutes = Minutes;
      DST();
      allign2 = 1;
      allign2_count = 0;
      allign2_delta = 0;
      o_Time_Zone = Time_Zone;
      currHours = Hours + o_Time_Zone;  //we have to do it here, because we do not know what will trigger first GPS or OCXO
      if (currHours > 23) currHours -= 24;
      mario_x = (((480 + 33) * currMinutes) / 60) - 33;
      mario_i = 1;
      allign = 0;
      min_to_ignore = 3;
      TicsPerDay = 0;  //this is needed because 1. seconds synch moment is shifting and thus old timing valus become irrelevant 2. because new time and new seconds sync is made new start of accuracy is needed
      TicsPerYear = 0;
      pps_error = 0;
      pps_shift = 0;
      i = 0;
      j = 0;
      J = 0;
      //soring last date of allignment - not really needed
      EEPROM.write(0, highByte(gps.date.year()));
      EEPROM.write(1, lowByte(gps.date.year()));
      EEPROM.write(2, highByte(gps.date.month()));
      EEPROM.write(3, lowByte(gps.date.month()));
      EEPROM.write(4, highByte(gps.date.day()));
      EEPROM.write(5, lowByte(gps.date.day()));
    }
  }
}

void DST() {
  int dayOfMonth = gps.date.day();
  int Month = gps.date.month();
  int maxWeekDay;
  int y = gps.date.year() - 2000;  // Get year from RTC and subtract 2000
  int x = (y + y / 4 + 2) % 7;     // in reality formula should be be y + y/4 + 3 + 6 (where 3 is the month (same number for march and november) and 6 is for century, but because  9 %7 = 2%7 we have here 2
  if ((35 - x) > 31) {
    maxWeekDay = 28;
  } else {
    maxWeekDay = 35;
  }
  if ((Month == 3) && ((dayOfMonth == (maxWeekDay - x)) && (Hours >= 2))) { Time_Zone = 2; }  //31
  if ((Month == 3) && (dayOfMonth > (maxWeekDay - x))) { Time_Zone = 2; }
  if ((Month == 3) && (dayOfMonth < (maxWeekDay - x))) { Time_Zone = 1; }
  //Last Sunday of Nov @ 2:00 AM
  if ((Month == 10) && (dayOfMonth == (31 - x)) && Hours >= 2) { Time_Zone = 1; }  //27
  if ((Month == 10) && (dayOfMonth > (31 - x))) { Time_Zone = 1; }
  if ((Month == 10) && (dayOfMonth < (31 - x))) { Time_Zone = 2; }
  if ((Month == 11) || (Month == 12) || (Month == 1) || (Month == 2)) { Time_Zone = 1; }
  if ((Month == 4) || (Month == 5) || (Month == 6) || (Month == 7) || (Month == 8) || (Month == 9)) { Time_Zone = 2; }
  //Serial.println(x);
}

void Buttons() {
  // read the state of the pushbutton value:
  // buttons in the order on the board
  buttonState3 = digitalRead(buttonPin3);  //Brightness
  buttonState4 = digitalRead(buttonPin4);  //Fine tune - 1 hour allignment delta calc
  buttonState1 = digitalRead(buttonPin1);  //Allign time from start
  buttonState2 = digitalRead(buttonPin2);  //Reset Current Count values
  if (buttonState3 != Prev_buttonState3) {
    if (buttonState3 == HIGH) {
      digitalWrite(ledPin, LOW);
    } else {
      digitalWrite(ledPin, HIGH);
      //reset_OCXO();
      b += 30;
      if (b > 100) b = 10;
      DisplayBrightness();
    }
    delay(50);
  }
  if (buttonState4 != Prev_buttonState4) {
    if (buttonState4 == HIGH) {
      digitalWrite(ledPin, LOW);
      Pushed_button4 = 0;
    } else {
      digitalWrite(ledPin, HIGH);
      sec_buttonState4 = oSeconds;  //saving current seconds - logic with the hold function for 2 seconds
      Pushed_button4 = 1;
    }
    delay(50);
  }
  if ((Pushed_button4 == 1) and (abs(sec_buttonState4 - oSeconds) > 1)) {  //and (buttonState1 == LOW)
    digitalWrite(ledPin, LOW);
    allign2 = 1;
    allign2_count = 0;
    allign2_delta = 0;
    Pushed_button4 = 0;
  }
  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if (buttonState1 != Prev_buttonState1) {
    if (buttonState1 == HIGH) {
      digitalWrite(ledPin, LOW);
      Pushed_button1 = 0;
    } else {
      digitalWrite(ledPin, HIGH);
      sec_buttonState1 = oSeconds;  //saving current seconds - logic with the hold function for 2 seconds
      Pushed_button1 = 1;
    }
    delay(50);
  }
  if ((Pushed_button1 == 1) and (abs(sec_buttonState1 - oSeconds) > 1)) {  //and (buttonState1 == LOW)
    digitalWrite(ledPin, LOW);
    Serial.println("button1 pressed");
    allign = 1;
    min_to_ignore = 2;
    Pushed_button1 = 0;
  }

  if (buttonState2 != Prev_buttonState2) {
    if (buttonState2 == HIGH) {
      digitalWrite(ledPin, LOW);
      Pushed_button2 = 0;
    } else {
      digitalWrite(ledPin, HIGH);
      sec_buttonState2 = oSeconds;  //saving current seconds - logic with the hold function for 2 seconds
      Pushed_button2 = 1;
    }
    delay(50);
  }
  if ((Pushed_button2 == 1) and (abs(sec_buttonState2 - oSeconds) > 1)) {  //and (buttonState1 == LOW)
    digitalWrite(ledPin, LOW);
    TicsPerDay = 0;  //this is needed because 1. seconds synch moment is shifting and thus old timing valus become irrelevant 2. because new time and new seconds sync is made new start of accuracy is needed
    TicsPerYear = 0;
    Pushed_button2 = 0;
  }
  Prev_buttonState1 = buttonState1;
  Prev_buttonState2 = buttonState2;
  Prev_buttonState3 = buttonState3;
  Prev_buttonState4 = buttonState4;
}

void DisplayTime() {
  char temp[9];
  //char temp22[30];
  sprintf(temp, "%02ld:%02ld:%02ld", currHours, currMinutes, oSeconds);
  DisplaySerial.print(("t0.txt=\""));
  DisplaySerial.print(temp);
  DisplaySerial.print(("\""));
  DisplaySerial.print(("\xFF\xFF\xFF"));
}

void DisplayDelta() {
  char temp1[10];
  char temp2[10];
  dtostrf(forecasted_dev_in_sec, 9, 6, temp1);
  sprintf(temp2, "%s", temp1);
  DisplaySerial.print(F("t1.txt=\""));
  DisplaySerial.print(temp2);
  DisplaySerial.print(F("\""));
  DisplaySerial.print(F("\xFF\xFF\xFF"));
}
void DisplayLifeTime() {
  char temp[9];
  sprintf(temp, "%02ld:%02ld:%02ld", oDays, oHours, oMinutes);
  DisplaySerial.print(F("t3.txt=\"life "));
  DisplaySerial.print(F("time DD:HH:MM "));
  DisplaySerial.print(temp);
  DisplaySerial.print(F("\""));
  DisplaySerial.print(F("\xFF\xFF\xFF"));
}
void DisplayLifeDelta() {
  char temp[9];
  sprintf(temp, "%02ld:%02ld:%02ld", oTotalSeconds3, TicsPerDay, TicsPerYear);
  DisplaySerial.print(F("t4.txt=\"delta "));
  DisplaySerial.print(F("per min:day:year "));
  DisplaySerial.print(temp);
  DisplaySerial.print(F("\""));
  DisplaySerial.print(F("\xFF\xFF\xFF"));
}
void DisplayPPS() {
  if (pps_live == 1) {
    DisplaySerial.print(F("r0.bco"));
    DisplaySerial.print(F("=1024"));
    DisplaySerial.print(F("\xFF\xFF\xFF"));
  } else {
    DisplaySerial.print(F("r0.bco"));
    DisplaySerial.print(F("=53248"));
    DisplaySerial.print(F("\xFF\xFF\xFF"));
  }
}
void DisplayMario() {
  char temp[12];
  if (mario_i % 7 == 0) {
    mario_x++;
    sprintf(temp, "%d", mario_x);
    DisplaySerial.print(F("p2.x="));
    DisplaySerial.print(temp);
    DisplaySerial.print(F("\xFF\xFF\xFF"));
    uint16_t lux = sensor.readLux();
    if (lux < 5) b0 = 10;
    if ((lux >= 5) and (lux < 20)) b0 = 15;
    if ((lux >= 20) and (lux < 50)) b0 = 25;
    if ((lux >= 50) and (lux < 150)) b0 = 33;
    if ((lux >= 150) and (lux < 300)) b0 = 40;
    if ((lux >= 300) and (lux < 800)) b0 = 70;
    if (lux >= 800) b0 = 100;
    if (b0 != b) {
      b = b0;
      DisplayBrightness();
    }
    //Serial.println(b);
    //Serial.println(lux);
    //if (mario_x > 480) mario_x = -33;
  }
}
void DisplayGraph(long delta_per_min) {
  char temp[10];
  int graph_max = 50;  //value on the monitor maximum (ie ssize of sqare)
  int graph_min = 0;
  int value_max = 10;  //max value to fit inside the square so it does not go out
                       // here actually value is 9,5 which 5K ticks (tics per 1 sec) that we want to achive in 1 min  / (365 * 24 * 60)
  long converted_value;
  converted_value = delta_per_min * (graph_max - graph_min) / (value_max * 2) + ((graph_max - graph_min) / 2);
  sprintf(temp, "%ld", converted_value);
  DisplaySerial.print("va0.val=");
  DisplaySerial.print(temp);
  DisplaySerial.print(F("\xFF\xFF\xFF"));
  if (pps_live == 1) {  //if pps is not live do not update
    DisplaySerial.print("add 6,0,va0.val");
    DisplaySerial.print(F("\xFF\xFF\xFF"));
  }
}
void DisplayBrightness() {
  char temp[12];
  sprintf(temp, "%d", b);
  DisplaySerial.print(F("dim="));
  DisplaySerial.print(temp);
  DisplaySerial.print(F("\xFF\xFF\xFF"));
}
 
I looked through your code a little bit, focusing on the interrupt sources and functions, and I don't see any obvious problem. I thought there might be something getting incremented at a rate that it would overflow in about 30 days, but I don't see one. 30 days is only about 2.5 million seconds, so it's unlikely to be anything to do with counting seconds. Are you counting anything in milliseconds? That would be about 2.5 billion in 30 days, which is about the positive range of a 32-bit integer. You are using type long (32-bit signed integer) in many places where the data is logically unsigned, so that's a possibility.

When I saw the writes to EEPROM, I thought that could be a problem if it was being done often, but it looks like it's only being done when button 1 is pressed. Still, be aware that EEPROM is emulated in flash on T4.x, so writing to EEPROM can take quite a long time if the condition to erase a flash sector is triggered.

One other comment for now, I know that all of the TinyGPSPlus examples use software serial, but since you are using pins 0 and 1, you could easily switch to hardware serial (Serial1), and avoid a lot of low-level work that your program is currently doing to sample those inputs fast enough for software serial. You have the software serial pins 0=TX, 1=RX. For hardware Serial1, you would have to physically swap those two wires to use the default 0=RX, 1=TX.
 
@anbolge: The crash report will include an address where the crash was recorded (specifically 0x1500 in your case). Paul has created a CrashReport() <webpage> with useful details. You can also check the entry in the unofficial Teensy wiki <here> for links to descriptions of where to find the addr2line utility for both the old (1.8.x) & new (2.3.x) Arduino IDE, as well as detailed descriptions of how to use it.

Good luck . . .

Mark J Culross
KD5RXT
 
18:51:36.169 -> Temperature inside the chip was 59.67 °C
18:51:36.169 -> Startup CPU clock speed is 720MHz
Is OC==720MHz speed really needed or helping? It will add more heat to the Teensy if not in good 'cooling' location. Also adds some wear to the MCU running at elevated voltage and temp.

That temp may not be on the edge of total crash - but what is reported is not always the worst-case temp within the chip, and also may not be the final temp ... but that is usually when the overheat restart is more drastic. And 720 MHz isn't that extreme generally as long as it has good ambient air flow.

That wouldn't explain the good 29 days then - BOOM, where p#4 @joepasquariello may have a better hint - and running 30 days at 528 MHz for lower temp to see it repro would be a waste. Using uint32_t for unsigned 32 bits is best with counts as they generally work across 32 bit rollover as well.
 
I would be suspicious of the places where you're using sprintf to write to char arrays that are 9 bytes long - if any of those values is larger than 99 sprintf will write beyond the end of the array, probably writing a 0 to the lowest byte of the return address on the stack (which would cause the "illegal use of EPSR" fault since it would clear the T bit when returning from the function).
 
Last edited:
If anyone comes to this post while facing a similar issue. The resolution was quite yeasy actually.

After I addressed a compilation warning: 'sprintf' may write a terminating nul past the end of the destination; the program become stable and was able to run for over 4 months now.

This was the code before change:
char temp[10];
sprintf(temp, "%ld", converted_value);

This is an updated code:
char temp[11];
snprintf(temp, sizeof(temp), "%ld", converted_value);
 
It’s good that you use snprintf, but you should make temp at it least 12 bytes. For example, -1 billion, which is within the range of long integer is

-1000000000

Requires 12 bytes including the terminating NULL.
 
Back
Top