Michael.Scholz
Member
Hi!
Hello everyone, this my first posting in here.
Alright, I have been trying to use the Teensy 4.0's SRTC feature in a clock project. The Teensy 4.0 (https://www.adafruit.com/product/4323) is the core module, driving an OLED display (https://www.adafruit.com/product/2674) and a WiFi module (https://www.adafruit.com/product/2999) via SPI. The Teensy has a (proven working) 3V button cell connected to Vbat and GND. What it does is simple, upon first power up (no (S)RTC is set) it connects to the web, fetches the time via NTP, sets the time and the (S)RTC. Next time, when it is powered up, it should check with the SRTC (hopefully), tell the battery backed up time is okay and there is no need to go out on the web and start right away with the saved time. Every day at 1.55am (chosen arbitrarily) it syncs the time from the web (later this is gonna be set to sync once per month or so).
Basically, it works but the time from reading the (S)RTC always returns the compile time of the sketch (can be verified by changing the host computer's system time), along with a "timeSet".
I have searched this forum and have found these:
https://forum.pjrc.com/threads/6031...RTC-in-a-Teensy-4-0?highlight=teensy+4.0+srtc
https://forum.pjrc.com/threads/57176-teensy_loader_cli-and-Teensy-4-0?highlight=teensy+4.0+srtc
https://forum.pjrc.com/threads/58249-T4-rtc-setting-with-time-change?highlight=teensy+4.0+srtc
https://forum.pjrc.com/threads/5819...s-after-power-cycle?highlight=teensy+4.0+srtc
... but all the hints there haven't helped solving my problem so far, also
already seems to be part of the installed library that came with the Teensyduino-download that I am using. Nevertheless, I added it as a separate function to my code to make sure.
Here is my code, might seem mangled as it is the result of all attempts to get this working:
Hope I didn't forget to provide any information and that the documentation is sufficient someone can make some sense out of it. Any help is greatly appreciated.
Thanks!
Michael
Hello everyone, this my first posting in here.
Alright, I have been trying to use the Teensy 4.0's SRTC feature in a clock project. The Teensy 4.0 (https://www.adafruit.com/product/4323) is the core module, driving an OLED display (https://www.adafruit.com/product/2674) and a WiFi module (https://www.adafruit.com/product/2999) via SPI. The Teensy has a (proven working) 3V button cell connected to Vbat and GND. What it does is simple, upon first power up (no (S)RTC is set) it connects to the web, fetches the time via NTP, sets the time and the (S)RTC. Next time, when it is powered up, it should check with the SRTC (hopefully), tell the battery backed up time is okay and there is no need to go out on the web and start right away with the saved time. Every day at 1.55am (chosen arbitrarily) it syncs the time from the web (later this is gonna be set to sync once per month or so).
Basically, it works but the time from reading the (S)RTC always returns the compile time of the sketch (can be verified by changing the host computer's system time), along with a "timeSet".
I have searched this forum and have found these:
https://forum.pjrc.com/threads/6031...RTC-in-a-Teensy-4-0?highlight=teensy+4.0+srtc
https://forum.pjrc.com/threads/57176-teensy_loader_cli-and-Teensy-4-0?highlight=teensy+4.0+srtc
https://forum.pjrc.com/threads/58249-T4-rtc-setting-with-time-change?highlight=teensy+4.0+srtc
https://forum.pjrc.com/threads/5819...s-after-power-cycle?highlight=teensy+4.0+srtc
... but all the hints there haven't helped solving my problem so far, also
Code:
void rtc_set(unsigned long t)
{
// stop the RTC
SNVS_HPCR &= ~(SNVS_HPCR_RTC_EN | SNVS_HPCR_HP_TS);
while (SNVS_HPCR & SNVS_HPCR_RTC_EN) ; // wait
// stop the SRTC
SNVS_LPCR &= ~SNVS_LPCR_SRTC_ENV;
while (SNVS_LPCR & SNVS_LPCR_SRTC_ENV); // wait
// set the SRTC
SNVS_LPSRTCLR = t << 15;
SNVS_LPSRTCMR = t >> 17;
// start the SRTC
SNVS_LPCR |= SNVS_LPCR_SRTC_ENV;
while (!(SNVS_LPCR & SNVS_LPCR_SRTC_ENV)); // wait
// start the RTC and sync it to the SRTC
SNVS_HPCR |= SNVS_HPCR_RTC_EN | SNVS_HPCR_HP_TS;
}
already seems to be part of the installed library that came with the Teensyduino-download that I am using. Nevertheless, I added it as a separate function to my code to make sure.
Here is my code, might seem mangled as it is the result of all attempts to get this working:
Code:
/*
OLED Display clock
*/
#include <TimeLib.h>
#include <Timezone.h>
#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1325.h>
// If using software SPI, define CLK and MOSI
#define OLED_CLK 13
#define OLED_MOSI 11
// These are neede for both hardware & softare SPI
#define OLED_CS 10
#define OLED_RESET 9
#define OLED_DC 8
// WiFi control pin
#define WIFI_EN 18
int status = WL_IDLE_STATUS;
char ssid[] = "*******"; // network SSID
char pass[] = "********"; // network password
int keyIndex = 0; // your network key Index number (needed only for WEP)
// NTP
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets
// A UDP instance to let us send and receive packets over UDP
unsigned int localPort = 2390; // local port to listen for UDP packets
WiFiUDP Udp;
// hardware SPI
Adafruit_SSD1325 display(OLED_DC, OLED_RESET, OLED_CS);
// the setup routine runs once when you press reset:
void setup() {
// time source
setSyncProvider(getTeensyTime);
// sane wifi
pinMode(WIFI_EN, OUTPUT);
enableWifi();
WiFi.setPins(19, 17, 16);
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
display.begin(); // init
display.clearDisplay(); // clears the screen and buffer
if (timeStatus() != timeSet) {
fetchTime();
}
else {
Serial.println("RTC is good, no need to fetch time from network.");
}
}
// the loop routine runs over and over again forever:
void loop() {
char tstr[10] = {0};
// central European Time (Berlin, Prague)
TimeChangeRule myDST = {"CEST", Last, Sun, Mar, 2, 120}; // Daylight time = UTC + 2 hours
TimeChangeRule mySTD = {"CET", Last, Sun, Oct, 2, 60}; // Standard time = UTC + 1 hour
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr; //pointer to the time change rule, use to get TZ abbrev /**/
time_t utc = now();
time_t local = myTZ.toLocal(utc, &tcr);/**/
snprintf(tstr, sizeof(tstr)-1, "%02d:%02d:%02d", hour(local), minute(local), second(local));
display.clearDisplay();
display.setCursor(17, 25);
printScn((const char*)(tstr), WHITE, 2);
// every day at 01:55 (am) fetch time from internet to sync things up
if ((hour(local) == 1) && (minute(local) == 55) && (second(local) == 0)) {
fetchTime();
}
delay(450); // make sure we update the display more than twice per second to see every update
}
void printScnXY(const char* text, const int& x, const int& y, const int& col, const int& txtsz) {
display.setTextSize(txtsz);
display.setTextColor(col);
display.setCursor(x, y);
display.println(text);
display.display();
}
void printScn(const char* text, const int& col, const int& txtsz) {
display.setTextSize(txtsz);
display.setTextColor(col);
display.print(text);
display.display();
}
void printlnScn(const char* text, const int& col, const int& txtsz) {
display.setTextSize(txtsz);
display.setTextColor(col);
display.println(text);
display.display();
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address) {
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
void printWiFiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
printScn("IP: ", WHITE, 1);
char ipprnbuf[17] = {0};
snprintf(ipprnbuf, sizeof(ipprnbuf)-1, "%03d.%03d.%03d.%03d", ip[0], ip[1], ip[2], ip[3]);
printlnScn((const char*)(ipprnbuf), WHITE, 1);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
void fetchTime() {
connectToWifi();
getNtpTime();
}
void enableWifi() {
digitalWrite(WIFI_EN, HIGH); // turn on WiFi module
delay(1000);
}
void disableWifi() {
digitalWrite(WIFI_EN, LOW); // turn off WiFi module
delay(1000);
}
void connectToWifi() {
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
printScnXY("No WiFi device found!", 0, 0, WHITE, 1);
// don't continue:
while (true);
}
display.clearDisplay();
display.setCursor(0, 0);
// attempt to connect to WiFi network:
status = WL_IDLE_STATUS;
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
printlnScn("Connecting to WiFi...", WHITE, 1);
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to wifi");
printScn("Link: ", WHITE, 1);
printlnScn(ssid, WHITE, 1);
printWiFiStatus();
Serial.println("\nStarting connection to server...");
Udp.begin(localPort);
}
void getNtpTime() {
sendNTPpacket(timeServer); // send an NTP packet to a time server
// wait to see if a reply is available
delay(1000);
if ( Udp.parsePacket() ) {
Serial.println("NTP packet received");
// We've received a packet, read the data from it
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
Serial.print("Seconds since Jan 1 1900 = " );
Serial.println(secsSince1900);
// now convert NTP time into everyday time:
Serial.print("Unix time = ");
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL;
// subtract seventy years:
unsigned long epoch = secsSince1900 - seventyYears;
// print Unix time:
Serial.println(epoch);
setTime(epoch); // sets volatile time
Teensy3Clock.set(epoch); // supposed to set the battery backed up RTC
srtc_set(epoch); // test, to set the 'real' RTC
// print the hour, minute and second on serial console:
char tstr[10] = {0};
snprintf(tstr, sizeof(tstr)-1, "%02d:%02d:%02d", hour(epoch), minute(epoch), second(epoch));
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
Serial.println(tstr);
}
}
time_t getTeensyTime() {
Serial.println("calling getTeensyTime() / Teensy3Clock.get()...");
return Teensy3Clock.get();
}
void srtc_set(unsigned long t) {
// stop the RTC
SNVS_HPCR &= ~(SNVS_HPCR_RTC_EN | SNVS_HPCR_HP_TS);
while (SNVS_HPCR & SNVS_HPCR_RTC_EN) ; // wait
// stop the SRTC
SNVS_LPCR &= ~SNVS_LPCR_SRTC_ENV;
while (SNVS_LPCR & SNVS_LPCR_SRTC_ENV); // wait
// set the SRTC
SNVS_LPSRTCLR = t << 15;
SNVS_LPSRTCMR = t >> 17;
// start the SRTC
SNVS_LPCR |= SNVS_LPCR_SRTC_ENV;
while (!(SNVS_LPCR & SNVS_LPCR_SRTC_ENV)); // wait
// start the RTC and sync it to the SRTC
SNVS_HPCR |= SNVS_HPCR_RTC_EN | SNVS_HPCR_HP_TS;
}
Hope I didn't forget to provide any information and that the documentation is sufficient someone can make some sense out of it. Any help is greatly appreciated.
Thanks!
Michael