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

Thread: Time limitations on Teensy 3.5 wakeup alarms?

  1. #1
    Junior Member
    Join Date
    Jun 2019
    Posts
    6

    Time limitations on Teensy 3.5 wakeup alarms?

    Hi everyone, thanks so much for all the information on this forum, it's been invaluable as I've been working on a few different Teensy projects. I'm currently working on a water sampling device that utilizes the Teensy 3.5 microcontroller to run code that lets the user set a predetermined date and time to power pumps for collecting water samples. The point of this project is to collect samples while not on-site. The user sets the alarms and the code operates in a loop that calculates time to the first set alarm, and then using the Teensy RTC it sleeps (snooze.hibernate, thanks to Duff for that one!) until time to wake up and run the pump. Once done running the Teensy recalculates time to sleep and does so until next alarm. The sampler has worked great for short term deployments (hours-days), but on the longer deployments (weeks, 2 weeks for sure, maybe less) it's getting stuck and not following through on the loop. My suspicion is that there is some limit to the Teensy's RTC in terms of how long it can sit and count down seconds to waking, or maybe the RTC is more limited in hibernate mode. I know the Teensy has a 32 bit processor, and I couldn't find any obvious issues in looking over the spec. sheet, so I wouldn't have thought this would be an issue, but given that the short-term alarms work fine, it seems like the length of time for alarms is the issue. Given the depth of knowledge on this forum I'm hoping some of you might be able to weigh in and give your two cents. Could the RTC be my problem? Does the snooze library reduce the RTC capabilities? Or is there any reason why neither of those could be the issue? Thanks for any help or input!

  2. #2
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,530
    Quote Originally Posted by natef View Post
    The sampler has worked great for short term deployments (hours-days), but on the longer deployments (weeks, 2 weeks for sure, maybe less) it's getting stuck and not following through on the loop.
    deployment time is not the issue, but what is the max sleep time, or better what is the sleep time where it does not work anymore?
    Also what means it is getting stuck? does it not wake-up od does the loop() freeze;

  3. #3
    Junior Member
    Join Date
    Jun 2019
    Posts
    6
    WMXZ thanks for responding! Thatís a factor I havenít pinpointed yet. One week is ok, two weeks is not. Somewhere in between is where it fails. The failure is the loop freezing. Once itís programming mode is reactivated/woke up with a reed switch it goes back to normal. Iíve got a change to the code Iím testing right now that Iím hoping will solve this (but I wonít know for a few weeks still). The fix approaches the problem from it solely being a code issue and Iím hopeful it will work, but I just wanted to check in and see if someone could tell me I was playing an impossible game here.

  4. #4
    Senior Member
    Join Date
    Jul 2014
    Posts
    2,530
    Quote Originally Posted by natef View Post
    Once itís programming mode is reactivated/woke up with a reed switch it goes back to normal.
    makes no sense.
    the reed switch is doing what? switching the programming or do you have the reed on reset pin?

    for further comments, we need to see a complete program that generates the effect.

  5. #5
    Junior Member
    Join Date
    Jun 2019
    Posts
    6
    The reed switch is programmed as an interrupt for the Teensy when it's in sleep mode (snooze.hibernate), bringing the programming back to the start menu where alarms are set by the user.

    I realize I misrepresented part of my issue. The first wakeup alarm set always seems to go off ( I just had one go off after 3 weeks), it's the recalculation that seems to be time limited. If the second wakeup alarm is set to go off 24 or 48 hrs later, no problem, but when it's set for two weeks later it doesn't ever go off. I'm confused about why time is acting as a variable since the program can function over a few days without issue and wakeup right on time, but not for long-term deployments. I understand the need for code to receive analytical assistance, if it comes to that I'll parse it down and stick it on here.

  6. #6
    Senior Member duff's Avatar
    Join Date
    Jan 2013
    Location
    Las Vegas
    Posts
    993
    This is very interesting, so the first RTC alarm wakeup always works even if it's say three weeks away but after going back to sleep (for like a two weeks or longer), does it fail every time? Can you share how you calculating the wakeup times and how you set it using Snooze? I never tested this long of a sleep before.

    Is it battery powered? If so do you monitor the battery and share that data with us?

  7. #7
    Junior Member
    Join Date
    Jun 2019
    Posts
    6
    Quote Originally Posted by duff View Post
    This is very interesting, so the first RTC alarm wakeup always works even if it's say three weeks away but after going back to sleep (for like a two weeks or longer), does it fail every time? Can you share how you calculating the wakeup times and how you set it using Snooze? I never tested this long of a sleep before.
    Yes, I have yet to record a successful second alarm on the long deployments, so it seems to fail every time. Below is the section of the code for calculating the sleep times, but the general scheme is: Determine if Alarm A or Alarm B is set to go off first, then calculate the time until the earlier alarm is to go off. Snooze until then. RTC wakes up Teensy, pump goes off. A loop is now running that will go until the pump time is up, and then the pump turns off, the sleep time is recalculated, and the system is set to Snooze again until the newly set next alarm. If both alarms have already fired, and it's not set to fire every day (a daily mode that hasn't given any issues) it will wake up every month and go back to sleep. It seems to be getting stuck without a second alarm to wake up the system when it goes back to Snooze.

    Quote Originally Posted by duff View Post
    Is it battery powered? If so do you monitor the battery and share that data with us?
    The sampler is battery powered and it does log battery voltage every time it samples. With the Teensy's low draw in Snooze (seriously, thanks for that!) we don't usually see a drop of more than 0.2-0.4 volts, if even that much, over the month long deployment time.
    Here's an example of the log that is input on the microSD card each time it samples:

    9:0:1,2/5/2019,19.75,10.89,1,0
    10:0:1,4/5/2019,19.31,10.85,3,1


    the data translates to:

    Pump activated at 9:00:01 AM, May 2, 2019, Temperature=19.75, Voltage=10.89, Pump A started, Pump B waiting
    Pump activated at 10:00:01 AM, May 4, 2019, Temperature=19.31, Voltage=10.85, Pump A done pumping and off, Pump B started


    Here's the code:

    Code:
    void samplingMode(){
      //PUMP A
      if (aAlarmFlag == 0){//Execute the following if aAlarmFlag is 0
        digitalWrite(pumpAPin, LOW);//Make sure pumpA is off
        if ((aSecTime != 0)&&(nowSecTime > aSecTime)){aAlarmFlag = 1;}//If the time now is past the time pumpA should go off, set aAlarmFlag to 1
      }
      if (aAlarmFlag == 1){//Execute the following if aAlarmFlag is 1
        digitalWrite(pumpAPin, HIGH);//Turn on pumpA
        aEndTime = nowSecTime + (int(sampleVolume/(pumpACalibration/10.0))); //Calculate the amount of time that pumpA should run
      }
      if (aAlarmFlag == 2){//Execute the following if aAlarmFlag is 2
        digitalWrite(pumpAPin, HIGH);//Make sure pumpA is on
        if (nowSecTime > aEndTime){//Execute the following if duration of pumpA time is greater than the amount of time pumpA should run
          if (sampleMode == 1){aAlarmFlag = 3;}//If the sample mode is set to once, set aAlarmFlag to 3, i.e., never to run again.
          if (sampleMode == 0){//If the sample mode is set to daily, calculate the new aSecTime, the time for the aAlarm to wake
            aSecTime = (aSecTime + 86400);// Add 24 hrs to the time that A fires (aSecTime)
            tmElements_t updateAtm;//This is a time elements variable named updateAtm
            breakTime(aSecTime, updateAtm);// Break aSecTime into the time elements variable updateTm
            aHr = updateAtm.Hour;// Name the hour that pump A needs to fire aHr 
            aMin = updateAtm.Minute;// Name the minute that pump A needs to fire aMin 
            aSec = updateAtm.Second;// Name the second that pump A needs to fire aSec 
            aDay = updateAtm.Day;// Name the day that pump A needs to fire aDay
            aMon = updateAtm.Month;// Name the month that pump A needs to fire aMon 
            aYr = updateAtm.Year-30;// Name the year that pump A needs to fire aYr. Minus thirty because value is years since 1970, and we are dealing with years since 2000
            aAlarmFlag = 0; //Set aAlarmFlag to 0, so that it will restart and fire again when it wakes up at the appropriate time
            digitalWrite(pumpAPin, LOW);
          }
        }
      }
      if (aAlarmFlag == 3){digitalWrite(pumpAPin, LOW);}//If aAlarmFlag is 3, then make sure pumpA is off
    
      //PUMP B
      if (bAlarmFlag == 0){//Execute the following if bAlarmFlag is 0
        digitalWrite(pumpBPin, LOW);//Make sure pumpB is off
        if ((bSecTime != 0)&&(nowSecTime > bSecTime)){bAlarmFlag = 1;}//If the time now is past the time pumpB should go off, set bAlarmFlag to 1
      }
      if (bAlarmFlag == 1){//Execute the following if bAlarmFlag is 1
        digitalWrite(pumpBPin, HIGH);//Turn on pumpB
        bEndTime = nowSecTime + (int(sampleVolume/(pumpBCalibration/10.0))); //Calculate the amount of time that pumpB should run
      }
      if (bAlarmFlag == 2){//Execute the following if bAlarmFlag is 2
        digitalWrite(pumpBPin, HIGH);//Make sure pumpB is on
        if (nowSecTime > bEndTime){//Execute the following if duration of pumpB time is greater than the amount of time pumpB should run
          if (sampleMode == 1){bAlarmFlag = 3;}//If the sample mode is set to once, set bAlarmFlag to 3, i.e., never to run again.
          if (sampleMode == 0){//If the sample mode is set to daily, calculate the new bSecTime, the time for the aAlarm to wake
            bSecTime = (bSecTime + 86400);// Add 24 hrs to the time that B fires (bSecTime)
            tmElements_t updateBtm;//This is a time elements variable named updateBtm
            breakTime(bSecTime, updateBtm);// Break bSecTime into the time elements variable updateTm
            bHr = updateBtm.Hour;// Name the hour that pump B needs to fire bHr 
            bMin = updateBtm.Minute;// Name the minute that pump B needs to fire bMin 
            bSec = updateBtm.Second;// Name the second that pump B needs to fire bSec 
            bDay = updateBtm.Day;// Name the day that pump B needs to fire bDay
            bMon = updateBtm.Month;// Name the month that pump B needs to fire bMon 
            bYr = updateBtm.Year-30;// Name the year that pump B needs to fire bYr. Minus thirty because value is years since 1970, and we are dealing with years since 2000
            bAlarmFlag = 0; //Set bAlarmFlag to 0, so that it will restart and fire again when it wakes up at the appropriate time
            digitalWrite(pumpBPin, LOW);
          }
        }
      }
      if (bAlarmFlag == 3){digitalWrite(pumpBPin, LOW);}//If aAlarmFlag is 3, then make sure pumpB is off
    }
    
    void checkSleep(){//Determines if the sampler should go back to sleep
      if ((aAlarmFlag == 0)&&(bAlarmFlag == 3)&&(aSecTime>nowSecTime+60)){goToSleep();}
      if ((aAlarmFlag == 3)&&(bAlarmFlag == 0)&&(bSecTime>nowSecTime+60)){goToSleep();}
      if ((aAlarmFlag == 0)&&(bAlarmFlag == 0)&&(aSecTime>nowSecTime+60)&&(bSecTime>nowSecTime+60)){goToSleep();}
      if ((aAlarmFlag == 3)&&(bAlarmFlag == 3)){goToSleep();}
    }
    
    void goToSleep(){//Puts the sampler to sleep
      long sleepSecTime;
      if ((aAlarmFlag != 3)&&(bAlarmFlag != 3)&&(aSecTime < bSecTime)){sleepSecTime = aSecTime - nowSecTime;}
      if ((aAlarmFlag != 3)&&(bAlarmFlag != 3)&&(bSecTime < aSecTime)){sleepSecTime = bSecTime - nowSecTime;}
      if ((aAlarmFlag != 3)&&(bAlarmFlag != 3)&&(aSecTime == bSecTime)){sleepSecTime = aSecTime - nowSecTime;}
      
      if ((aAlarmFlag != 3)&&(bAlarmFlag == 3)) {sleepSecTime = aSecTime - nowSecTime;}
      if ((aAlarmFlag == 3)&&(bAlarmFlag != 3)) {sleepSecTime = bSecTime - nowSecTime;}
      if ((aAlarmFlag == 3)&&(bAlarmFlag == 3)) {sleepSecTime = 2628000;}//sleep one month, will wake and go to sleep again after that one month
    
      hrToSleep = int(sleepSecTime/3600);// calculates the hours to sleep
      minToSleep = int((sleepSecTime-(3600*hrToSleep))/60);// calculates the remaining minutes to sleep
      secToSleep = int(sleepSecTime-(3600*hrToSleep)-(60*minToSleep));// calculates the remaining seconds to sleep
      
      tempSensor.shutdown();// Shut down the temperature sensor
      delay (200);  
      digitalWrite(oledPowerPin, LOW);// Turn off the power to the OLED
      digitalWrite(tempPowerPin, LOW);// Turn off the power to the temperature sensor
      digitalWrite(irPowerPin, LOW);// Turn off the power to the IR sensor
      digitalWrite(voltageReadPin, LOW);// Turn off the power to the voltage read pin A15
      alarm.setRtcTimer(hrToSleep, minToSleep, secToSleep);// Sets the RTC TIMER with the appropriate amount of hour, min, sec to sleep
      delay (100);
      int who; 
      who = Snooze.hibernate( config_teensy35 );// wake up the Teensy and identify who woke it up
      if (who == REED_INTERRUPT_PIN){
        delay(500);
        if (digitalRead(REED_INTERRUPT_PIN)==HIGH){
          delay(500);
          if (digitalRead(REED_INTERRUPT_PIN)==HIGH){
            digitalWrite(oledPowerPin, HIGH);// Power on the oled    
            digitalWrite(tempPowerPin, HIGH);// Power on the temperature sensor
            digitalWrite(irPowerPin, HIGH);// Power on the IR sensor
            digitalWrite(voltageReadPin, HIGH);// Turn on the power to the voltage read pin A15
    
            tempSensor.wake();// Wake up the temperature sensor
            delay(200);
            display.begin(SSD1306_SWITCHCAPVCC, 0x3C);// Start the OLED back up again
            display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE,BLACK); display.setCursor(0,16); display.println("Interrupt");// Put "Interrupt" on the first line of the OLED
            display.display();// Update the OLED display
            menu = 0; pos = 0;//Sets menu and position to 0
            readSampleParamArray();
            delay(1000);  
          }
          if (digitalRead(REED_INTERRUPT_PIN)==LOW){menu = 9;}
        }
        if (digitalRead(REED_INTERRUPT_PIN)==LOW){menu = 9;}
      }
      else{//alarm pin wake up
        digitalWrite(oledPowerPin, HIGH);// Power on the oled    
        digitalWrite(tempPowerPin, HIGH);// Power on the temperature sensor
        digitalWrite(voltageReadPin, HIGH);// Turn on the power to the voltage read pin A15
    
        tempSensor.wake();// Wake up the temperature sensor
        display.begin(SSD1306_SWITCHCAPVCC, 0x3C);// Start the OLED back up again
        delay(500);    
        getVoltage();
        menu = 9;//finishes out sleep and sends back to loop running sampling mode (case 9)
      }
    }
    
    void samplingDisplay(){//Updates the display during sampling
      if ((aAlarmFlag == 2)&&(bAlarmFlag !=2)){display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE,BLACK); display.setCursor(0,16); display.println("Pump A");}// Display Pump A
      if ((aAlarmFlag != 2)&&(bAlarmFlag ==2)){display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE,BLACK); display.setCursor(0,16); display.println("Pump B");}// Display Pump B
      if ((aAlarmFlag == 2)&&(bAlarmFlag ==2)){display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE,BLACK); display.setCursor(0,16); display.println("Both Pumps");}// Display Both Pumps
      if ((aAlarmFlag != 2)&&(bAlarmFlag !=2)){display.clearDisplay(); display.setTextSize(2); display.setTextColor(WHITE,BLACK); display.setCursor(0,16); display.println("Wait...");}// Display Wait...
      display.display();// Update the OLED display
    }

  8. #8
    Senior Member duff's Avatar
    Join Date
    Jan 2013
    Location
    Las Vegas
    Posts
    993
    Ok looking at the setRtcTimer function in Snooze the hours, minutes and seconds are defined uint8_t so the maximum value can only be 255 for each, so 14 days would be 336 hours! Since I'm doing a complete update to Snooze for the upcoming T4 it's not in state that you can download and use from my GitHub currently so if you can change the your copy of Snooze setRtcTimer functions hours, mins, secs to uint32_t and see if that works, remember to change both the SnoozeAlarm.h and SnoozeAlarm.cpp files.

  9. #9
    Junior Member
    Join Date
    Jun 2019
    Posts
    6
    Duff I will try that right now and see what comes of it and follow up on here, thanks for the insight and guidance, you might've just saved my sanity!

  10. #10
    Junior Member
    Join Date
    Jun 2019
    Posts
    6
    Duff, follow up on the uint8 -> uint32 fix. I changed SnoozeAlarm.h and SnoozeAlarm.cpp files and it looks like it worked! Thank you for your help! I still don't understand why my initial alarm could work for a period longer than 255 hours since my second alarm clearly couldn't, but post-fix it's worked on three different machines with a second alarm two weeks after the first. Maybe the uint8 was still being used during the alarm reset after the first alarm finished
    Code:
    alarm.setRtcTimer(hrToSleep, minToSleep, secToSleep);
    even though the Teensy had been woken up by the first alarm and should've been back to uint32? Just guessing now, I can live with the mystery but if anyone has other thoughts it is interesting. Thanks again for helping me move forward!

Posting Permissions

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