Teensy 4.0 RTC with battery doesn't save correct time after power loss

Status
Not open for further replies.

PickyBiker

Well-known member
The attached sketch shows the time on a display, allows it to be updated, and attempts to save any time updates. While everything seems to work okay while it is running, when power is removed the time is restored to the original time settings, not the updated time settings. There is a good battery connected to the teensy 4.

I tried loading the Teensy Arduino IDE software again, but that doesn't help.

What am I doing wrong?

Code:
// designed for for teensy 4.0

#include <TimeLib.h>
#include "Adafruit_HX8357.h"
#include <Adafruit_GFX.h>    // Core graphics library
#include "TouchScreen.h"

// These are the four touchscreen analog pins
#define YP A2  // must be an analog pin, use "An" notation!
#define XM A3  // must be an analog pin, use "An" notation!
#define YM 7   // can be a digital pin
#define XP 8   // can be a digital pin
TouchScreen tscr = TouchScreen(XP, YP, XM, YM, 500);

#define MINPRESSURE 300
#define MAXPRESSURE 1000

// The display uses hardware SPI, plus #9 & #10
#define TFT_RST 15  // if you dont want to use a reset pin, tie this to arduino RST if you like
#define TFT_DC 9
#define TFT_CS 10

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 110
#define TS_MINY 80
#define TS_MAXX 900
#define TS_MAXY 940

Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, TFT_RST);

// Colors
#define BACKGROUNDCLR 0xA514
#define TEXTCLR       0x0000
#define BUTTONCLR     0xAD75
#define REDCLR        0xA800

struct Button
{
  public:
    int x;
    int y;
    int buttonHeight;
    int buttonLength;
    void (*funct)(int n);
    int arg;
};

Button myArray[12];
Button item;

boolean AM = true;                          // true for AM false for PM
int buttonCount = 0;                        // keeps track of # of buttons on screen
int zIdx = 1, stIdx = 1;                    // indexes zone = 1-ZONECOUNT, start time = 1-3

/***************************************************************************************************************/
void CreateButton(int txSize, int x, int y, String txt, int bgClr, int txClr, void (funct)(int n), int arg)
{
  float charWidth[6]  = {6, 6, 12, 18, 24, 28};
  float charHeight[6] = {7, 7, 14, 22, 30, 36};
  float rectWidth, rectHeight;

  rectWidth = (txt.length() + 1) * charWidth[txSize];
  rectHeight = charHeight[txSize] + 20;

  tft.drawRoundRect(x, y, rectWidth, rectHeight,  10, TEXTCLR);
  tft.fillRoundRect(x + 1, y + 1, rectWidth - 2, rectHeight - 2, 10, bgClr);

  int txtStartX = x + (charWidth[txSize] / 2) + 1;                         // Center the TEXTCLR;
  int txtStartY = y + 10;                                                  // TEXTCLR in the middle

  tft.setCursor(txtStartX, txtStartY);
  tft.setTextColor(txClr);
  tft.setTextSize(txSize);
  tft.print(txt);

  item.x = x;
  item.y = y;
  item.buttonLength =  rectWidth;
  item.buttonHeight = rectHeight;
  item.funct = funct;
  item.arg = arg;

  myArray[buttonCount++] = item;
}

/***************************************************************************************************************/
void setup(void)
{
  Serial.begin(115200);
  delay(500);
  pinMode(15, OUTPUT);                            // TFT Display reset pin
  digitalWrite(15, HIGH);

  setSyncProvider(getTeensy3Time);                // use the Teensy 4.0 RTC timer

  StartDisplay();                                 // start the 3.5" display

  if (timeStatus() != timeSet)
    Serial.println(F("Unable to sync with RTC"));
  else
    Serial.println(F("RTC has set system time"));

  if (hour() > 12)                                // set AM/PM
    AM = false;
  else
    AM = true;

  DrawTimeSetPage(0);
}

/***************************************************************************************************************/
void loop(void)
{
  GetTouch();                       // See if a button is touched
  CheckTimeDisplay();               // update the time once per minute
}

time_t getTeensy3Time()
{
  return Teensy3Clock.get();
}

/***************************************************************************************************************/
void CheckTimeDisplay()  // display the clock time every minute
{
  static int nMin, oMin;
  nMin = minute();

  if (oMin != nMin)
  {
    DisplayTime();
    oMin = nMin;
  }
}

/***************************************************************************************************************/
void Rotation(int n)
{
  tft.setRotation(n);
}

/***************************************************************************************************************/
void StartDisplay()
{
  tft.begin();
  delay(200);
  Rotation(1);
  tft.fillScreen(BACKGROUNDCLR);
  tft.setTextColor(TEXTCLR);
  tft.setTextSize(3);
}

/***************************************************************************************************************/
void SwitchAMPM(int n)
{
  if (AM == true) AM = false; else  AM = true;
  DisplayTime();
}



/***************************************************************************************************************/
void WriteText(String txt, int txtSize, int x, int y, int clr)
{
  Rotation(1);
  tft.setTextColor(clr);
  tft.setTextSize(txtSize);
  tft.setCursor(x, y);
  tft.print(txt);
}

/***************************************************************************************************************/
void DisplayTime()
{
  int hr = hour(), mn = minute();
  String strHr, strMin;

  if (hr > 12)
    hr = hr - 12;

  if (hr < 10)
    strHr = "0" + String(hr);
  else
    strHr = String(hr);

  if (mn < 10)
    strMin = "0" + String(mn);
  else
    strMin = String(mn);

  Rotation(1);
  tft.fillRect(284, 5, 90, 21, BACKGROUNDCLR);
  WriteText("Current Time " + strHr + ":" + strMin, 3, 50, 5, TEXTCLR);

  if (AM)
  {
    WriteText("PM", 3, 390, 5, BACKGROUNDCLR);
    WriteText("AM", 3, 390, 5, TEXTCLR);
  }
  else
  {
    WriteText("AM", 3, 390, 5, BACKGROUNDCLR);
    WriteText("PM", 3, 390, 5, TEXTCLR);
  }
}

/***************************************************************************************************************/
void HourUp(int n)
{
  int hr = hour() % 12;

  hr += 1;
  if (hr > 12)
  {
    hr = 1;
  }
  setTime(hr, minute(), 0, 1, 1, 2021);
  DisplayTime();
}

/***************************************************************************************************************/
void HourDown(int n)
{
  int hr = hour() % 12;
  hr -= 1;
  if (hr < 1)
  {
    hr = 12;
  }

  setTime(hr, minute(), 0, 1, 1, 2020);
  DisplayTime();
}

/***************************************************************************************************************/
void MinuteUp(int n)
{
  int mn;
  mn = minute() + 1;
  if (mn > 59)
    mn = 0;
  setTime(hour(), mn, 0, 1, 1, 2020);
  DisplayTime();
}

/***************************************************************************************************************/
void MinuteDown(int n)
{
  int mn;

  mn = minute() - 1;
  if (mn < 0)
    mn = 59;
  setTime(hour(), mn, 0, 1, 1, 2020);
  DisplayTime();
}

/***************************************************************************************************************/
void ClearScreen()
{
  Rotation(1);
  tft.fillRoundRect(10, 5, 460, 315, 10, BACKGROUNDCLR);
}

/***************************************************************************************************************/
void Press(int x, int y)
{
  int cnt = buttonCount;
  for (int i = 0; i < cnt; i++)
  {
    if (x >= myArray[i].x && x <= myArray[i].x + myArray[i].buttonLength)
      if (y >= myArray[i].y && y <= myArray[i].y + myArray[i].buttonHeight)
      {
        myArray[i].funct(myArray[i].arg);  // call the button's function
        break;
      }
  }
  delay(150);
}

/***************************************************************************************************************/
void GetTouch()
{
  TSPoint p;
  Rotation(0);
  p.z = 0;

  // get a point
  p  = tscr.getPoint();
  if (p.z < MINPRESSURE || p.z > MAXPRESSURE)
  {
    return;
  }

  // Scale from ~0->1000 to tft.width using the calibration #'s
  p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());

  int s = p.x;
  p.x = p.y;
  p.y = s;

  Press(p.x, p.y);
  Rotation(1);
}

/***************************************************************************************************************/
void DrawTimeSetPage(int n)
{
  buttonCount = 0;
  ClearScreen();
  Rotation(1);
  DisplayTime();
  WriteText("TIME SET", 2, 190, 40, REDCLR);
  CreateButton(2, 150, 80, "Hour", BUTTONCLR, TEXTCLR, HourUp, 0);
  CreateButton(2, 230, 80, "Minute", BUTTONCLR, TEXTCLR, MinuteUp, 0);
  CreateButton(2, 340, 80, "AMPM", BUTTONCLR, TEXTCLR, SwitchAMPM, 0);
}
 
Your code never sets the RTC with a call to Teensy3Clock.set(time).

Honestly, the only thing I ever use the stuff in TimeLib for is formatting the time I get from the RTC. Having library routines to keep time is fine for chips that don't have an always available accurate time, but just confuses the issue when you're using something that has an RTC.
 
Thank you. I was confused by the timelib and teensy3clock. I'll remove the timelib stuff.
I will also figure out how to use the Teensy3Clock.set(time)
 
On the T4, TimeLib is really handy for extracting values out of the timestamp that the RTC returns, and for formatting time strings, and lots of auxiliary stuff like that. But that's about all I use it for; the RTC's already keeping the time.

No guarantee that this will actually run correctly, but I took a quick stab at converting your program to let the RTC do the timekeeping and just use TimeLib for extracting hours and minutes, and converting the various time fields back into the RTC timestamp.

Code:
// designed for for teensy 4.0

#include <TimeLib.h>
#include "Adafruit_HX8357.h"
#include <Adafruit_GFX.h>    // Core graphics library
#include "TouchScreen.h"

// These are the four touchscreen analog pins
#define YP A2  // must be an analog pin, use "An" notation!
#define XM A3  // must be an analog pin, use "An" notation!
#define YM 7   // can be a digital pin
#define XP 8   // can be a digital pin
TouchScreen tscr = TouchScreen(XP, YP, XM, YM, 500);

#define MINPRESSURE 300
#define MAXPRESSURE 1000

// The display uses hardware SPI, plus #9 & #10
#define TFT_RST 15  // if you dont want to use a reset pin, tie this to arduino RST if you like
#define TFT_DC 9
#define TFT_CS 10

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 110
#define TS_MINY 80
#define TS_MAXX 900
#define TS_MAXY 940

Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC, TFT_RST);

// Colors
#define BACKGROUNDCLR 0xA514
#define TEXTCLR       0x0000
#define BUTTONCLR     0xAD75
#define REDCLR        0xA800

struct Button
{
  public:
    int x;
    int y;
    int buttonHeight;
    int buttonLength;
    void (*funct)(int n);
    int arg;
};

Button myArray[12];
Button item;

boolean AM = true;                          // true for AM false for PM
int buttonCount = 0;                        // keeps track of # of buttons on screen
int zIdx = 1, stIdx = 1;                    // indexes zone = 1-ZONECOUNT, start time = 1-3

/***************************************************************************************************************/
void CreateButton(int txSize, int x, int y, String txt, int bgClr, int txClr, void (funct)(int n), int arg)
{
  float charWidth[6]  = {6, 6, 12, 18, 24, 28};
  float charHeight[6] = {7, 7, 14, 22, 30, 36};
  float rectWidth, rectHeight;

  rectWidth = (txt.length() + 1) * charWidth[txSize];
  rectHeight = charHeight[txSize] + 20;

  tft.drawRoundRect(x, y, rectWidth, rectHeight,  10, TEXTCLR);
  tft.fillRoundRect(x + 1, y + 1, rectWidth - 2, rectHeight - 2, 10, bgClr);

  int txtStartX = x + (charWidth[txSize] / 2) + 1;                         // Center the TEXTCLR;
  int txtStartY = y + 10;                                                  // TEXTCLR in the middle

  tft.setCursor(txtStartX, txtStartY);
  tft.setTextColor(txClr);
  tft.setTextSize(txSize);
  tft.print(txt);

  item.x = x;
  item.y = y;
  item.buttonLength =  rectWidth;
  item.buttonHeight = rectHeight;
  item.funct = funct;
  item.arg = arg;

  myArray[buttonCount++] = item;
}

/***************************************************************************************************************/
void setup(void)
{
  Serial.begin(115200);
  delay(500);
  pinMode(15, OUTPUT);                            // TFT Display reset pin
  digitalWrite(15, HIGH);

  StartDisplay();                                 // start the 3.5" display

  time_t now = Teensy3Clock.get();
  if (hour(now) > 12)                                // set AM/PM
    AM = false;
  else
    AM = true;

  DrawTimeSetPage(0);
}

/***************************************************************************************************************/
void loop(void)
{
  GetTouch();                       // See if a button is touched
  CheckTimeDisplay();               // update the time once per minute
}

/***************************************************************************************************************/
void CheckTimeDisplay()  // display the clock time every minute
{
  time_t now = Teensy3Clock.get();
  static int nMin, oMin;
  nMin = minute(now);

  if (oMin != nMin)
  {
    DisplayTime();
    oMin = nMin;
  }
}

/***************************************************************************************************************/
void Rotation(int n)
{
  tft.setRotation(n);
}

/***************************************************************************************************************/
void StartDisplay()
{
  tft.begin();
  delay(200);
  Rotation(1);
  tft.fillScreen(BACKGROUNDCLR);
  tft.setTextColor(TEXTCLR);
  tft.setTextSize(3);
}

/***************************************************************************************************************/
void SwitchAMPM(int n)
{
  if (AM == true) AM = false; else  AM = true;
  DisplayTime();
}



/***************************************************************************************************************/
void WriteText(String txt, int txtSize, int x, int y, int clr)
{
  Rotation(1);
  tft.setTextColor(clr);
  tft.setTextSize(txtSize);
  tft.setCursor(x, y);
  tft.print(txt);
}

/***************************************************************************************************************/
void DisplayTime()
{
  time_t now = Teensy3Clock.get();
  int hr = hour(now), mn = minute(now);
  String strHr, strMin;

  if (hr > 12)
    hr = hr - 12;

  if (hr < 10)
    strHr = "0" + String(hr);
  else
    strHr = String(hr);

  if (mn < 10)
    strMin = "0" + String(mn);
  else
    strMin = String(mn);

  Rotation(1);
  tft.fillRect(284, 5, 90, 21, BACKGROUNDCLR);
  WriteText("Current Time " + strHr + ":" + strMin, 3, 50, 5, TEXTCLR);

  if (AM)
  {
    WriteText("PM", 3, 390, 5, BACKGROUNDCLR);
    WriteText("AM", 3, 390, 5, TEXTCLR);
  }
  else
  {
    WriteText("AM", 3, 390, 5, BACKGROUNDCLR);
    WriteText("PM", 3, 390, 5, TEXTCLR);
  }
}

/***************************************************************************************************************/
void HourUp(int n)
{
  time_t now = Teensy3Clock.get();
  int hr = hour(now) % 12;

  hr += 1;
  if (hr > 12)
  {
    hr = 1;
  }

  setTeensyTime(hr, minute(now), 0, 1, 1, 2021);
  DisplayTime();
}

/***************************************************************************************************************/
void HourDown(int n)
{
  time_t now = Teensy3Clock.get();
  int hr = hour(now) % 12;

  hr -= 1;
  if (hr < 1)
  {
    hr = 12;
  }

  setTeensyTime(hr, minute(now), 0, 1, 1, 2021);
  DisplayTime();
}

/***************************************************************************************************************/
void MinuteUp(int n)
{
  time_t now = Teensy3Clock.get();
  int mn;

  mn = minute(now) + 1;
  if (mn > 59)
    mn = 0;

  setTime(hour(now), mn, 0, 1, 1, 2020);
  DisplayTime();
}

/***************************************************************************************************************/
void MinuteDown(int n)
{
  time_t now = Teensy3Clock.get();
  int mn;

  mn = minute(now) - 1;
  if (mn < 0)
    mn = 59;

  setTime(hour(now), mn, 0, 1, 1, 2020);
  DisplayTime();
}

/***************************************************************************************************************/
void ClearScreen()
{
  Rotation(1);
  tft.fillRoundRect(10, 5, 460, 315, 10, BACKGROUNDCLR);
}

/***************************************************************************************************************/
void Press(int x, int y)
{
  int cnt = buttonCount;
  for (int i = 0; i < cnt; i++)
  {
    if (x >= myArray[i].x && x <= myArray[i].x + myArray[i].buttonLength)
      if (y >= myArray[i].y && y <= myArray[i].y + myArray[i].buttonHeight)
      {
        myArray[i].funct(myArray[i].arg);  // call the button's function
        break;
      }
  }
  delay(150);
}

/***************************************************************************************************************/
void GetTouch()
{
  TSPoint p;
  Rotation(0);
  p.z = 0;

  // get a point
  p  = tscr.getPoint();
  if (p.z < MINPRESSURE || p.z > MAXPRESSURE)
  {
    return;
  }

  // Scale from ~0->1000 to tft.width using the calibration #'s
  p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());

  int s = p.x;
  p.x = p.y;
  p.y = s;

  Press(p.x, p.y);
  Rotation(1);
}

/***************************************************************************************************************/
void DrawTimeSetPage(int n)
{
  buttonCount = 0;
  ClearScreen();
  Rotation(1);
  DisplayTime();
  WriteText("TIME SET", 2, 190, 40, REDCLR);
  CreateButton(2, 150, 80, "Hour", BUTTONCLR, TEXTCLR, HourUp, 0);
  CreateButton(2, 230, 80, "Minute", BUTTONCLR, TEXTCLR, MinuteUp, 0);
  CreateButton(2, 340, 80, "AMPM", BUTTONCLR, TEXTCLR, SwitchAMPM, 0);
}

/***************************************************************************************************************/
void setTeensyTime(int hr,int mn,int sec,int dom, int mon, int yr) {
  tmElements_t tm;

  tm.Year = CalendarYrToTm(yr);
  tm.Month = mon;
  tm.Day = dom;
  tm.Hour = hr;
  tm.Minute = mn;
  tm.Second = sec;
  Teensy3Clock.set(makeTime(tm));
}
 
Status
Not open for further replies.
Back
Top