R4 WiFi Regelmäßiger Update des RTC über NTP Zeit im RTC driftet

Hallo, ich bin gerade dabei, eine Terrariensteuerung zu realisieren und habe ein Problem bei der Synchronisierung des RTC über einen NTP. Hier das Minimalbeispiel:

#include <LiquidCrystal.h>
#include "clock_updater.h"

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

void setup() {
  RTC.begin();
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  //lcd.print("INITIALIZE");
  Serial.begin(9600);
  update_rtc();
}
//for update rtc
static unsigned long confirmed_start_time = 0;
unsigned long start_time;
//delay for the WiFi update (90000  = 15min, 60000 = 10 min, 30000 = 5min)
int update_delay = 600000;
//time till next loop
unsigned long confirmed_loop_time = 0;
unsigned long loop_time;
int loop_delay = 200;
void loop() {
  start_time = millis();
  //updates ntp after update_delay ms
  if (start_time - confirmed_start_time > update_delay)  //updates rtc 
  {
          Serial.print("RTC time before update: ");
    // Print out date (DD/MM//YYYY)
  Serial.print(current_time.getDayOfMonth());
  Serial.print("/");
  Serial.print(Month2int(current_time.getMonth()));
  Serial.print("/");
  Serial.print(current_time.getYear());
  Serial.print(" - ");

  // Print time (HH/MM/SS)
  Serial.print(current_time.getHour());
  Serial.print(":");
  Serial.print(current_time.getMinutes());
  Serial.print(":");
  Serial.println(current_time.getSeconds());

    update_rtc();
    confirmed_start_time = start_time;
    RTC.getTime(current_time);
      Serial.print("RTC time after update ");
    // Print out date (DD/MM//YYYY)
  Serial.print(current_time.getDayOfMonth());
  Serial.print("/");
  Serial.print(Month2int(current_time.getMonth()));
  Serial.print("/");
  Serial.print(current_time.getYear());
  Serial.print(" - ");

  // Print time (HH/MM/SS)
  Serial.print(current_time.getHour());
  Serial.print(":");
  Serial.print(current_time.getMinutes());
  Serial.print(":");
  Serial.println(current_time.getSeconds());


  }
  loop_time = millis();
  if (loop_time - confirmed_loop_time > loop_delay) {

    RTC.getTime(current_time);
    confirmed_loop_time = loop_time;
    //float humidity = dht.readHumidity();
    lcd.setCursor(0, 0);
    int h_1 = current_time.getHour() / 10;
    int h_2 = current_time.getHour() % 10;
    int m_1 = current_time.getMinutes() / 10;
    int m_2 = current_time.getMinutes() % 10;
    int s_1 = current_time.getSeconds() / 10;
    int s_2 = current_time.getSeconds() % 10;
    lcd.print(String(h_1) + String(h_2) + ":" + String(m_1) + String(m_2)+":"+String(s_1)+String(s_2));
  }
}

terraSteuerung.ino

#include "wifi_config.h"
WiFiUDP wifiudp;
NTP ntp(wifiudp);
const char *wifi_ssid=WIFI_SSID;
const char *wifi_pw=WIFI_PW;
const unsigned long timeout_connection=15000;
Month getMonth(int month){
  switch (month) {
    case  1: return Month::JANUARY;   break;
    case  2: return Month::FEBRUARY;  break;
    case  3: return Month::MARCH;     break;
    case  4: return Month::APRIL;     break;
    case  5: return Month::MAY;       break;
    case  6: return Month::JUNE;      break;
    case  7: return Month::JULY;      break;
    case  8: return Month::AUGUST;    break;
    case  9: return Month::SEPTEMBER; break;
    case 10: return Month::OCTOBER;   break;
    case 11: return Month::NOVEMBER;  break;
    case 12: return Month::DECEMBER;  break;
    default: break;
  }
}
DayOfWeek getDay(int day){
  switch (day) {
    case  0: return DayOfWeek::SUNDAY;    break;
    case  1: return DayOfWeek::MONDAY;    break;
    case  2: return DayOfWeek::TUESDAY;   break;
    case  3: return DayOfWeek::WEDNESDAY; break;
    case  4: return DayOfWeek::THURSDAY;  break;
    case  5: return DayOfWeek::FRIDAY;    break;
    case  6: return DayOfWeek::SATURDAY;  break;
    default: break;
  }
}
//for fixing:
int updates=0;
void update_rtc(){
  unsigned long start_update_time=millis();
  WiFi.begin(wifi_ssid,wifi_pw);
  while(WiFi.status() != WL_CONNECTED)
  {
    delay(500); 
    Serial.print(".");
    if(start_update_time+timeout_connection<millis()){//if the start of the connection takes longer than max_time, end this turn
      Serial.println("connection error");
      return;
    }
  }
  delay(10000);
  ntp.update();
  if(ntp.year()<2000){
    NTP ntp_tmp(wifiudp);
    ntp_tmp.ruleDST("CEST", Last, Sun, Mar, 2, 120);
    // CET: Central European Time
    // start normal time last Sunday in October 3am GMT + 1h
    ntp_tmp.ruleSTD("CET", Last, Sun, Oct, 3, 60);
    ntp_tmp.begin();
    ntp=ntp_tmp;
  }
  WiFi.end();
  RTCTime update_time=RTCTime(ntp.day(), getMonth(ntp.month()), ntp.year(),ntp.hours(), ntp.minutes(), ntp.seconds(), getDay(ntp.weekDay()), SaveLight::SAVING_TIME_ACTIVE);
  RTC.setTime(update_time);
  RTC.getTime(current_time);
  Serial.print("NTP time: ");
    // Print out date (DD/MM//YYYY)
  Serial.print(ntp.day());
  Serial.print("/");
  Serial.print(ntp.month());
  Serial.print("/");
  Serial.print(ntp.year());
  Serial.print(" - ");

  // Print time (HH/MM/SS)
  Serial.print(ntp.hours());
  Serial.print(":");
  Serial.print(ntp.minutes());
  Serial.print(":");
  Serial.println(ntp.seconds());
      updates++;
  lcd.setCursor(0, 1);
  lcd.print(String(updates));
}

clock_updater.ino

#pragma once
#include <WiFiS3.h>

#include <WiFiUdp.h>

#include <NTP.h>
#include "RTC.h"
RTCTime current_time;
void update_rtc();

clock_updater.h

Bei Initialisierung wird die Zeit korrekt dargestellt. Nach ein paar Stunden allerdings macht sich ein Drift der Uhrzeit zwischen RTC und tatsächlicher Uhrzeit einer Funkuhr bemerkbar. Dieser summiert sich auf, sodass nach etwa 12h die RTC um 1,5min hinterher läuft. Falls es hilft, habe ich exemplarisch ein paar Ausgaben vom Seriellen Monitor

RTC time after update 3/7/2024 - 8:1:29
RTC time before update: 3/7/2024 - 8:11:34
NTP time: 3/7/2024 - 8:11:29
RTC time after update 3/7/2024 - 8:11:29
RTC time before update: 3/7/2024 - 8:21:34
NTP time: 3/7/2024 - 8:21:29
RTC time after update 3/7/2024 - 8:21:29
RTC time before update: 3/7/2024 - 8:31:34
NTP time: 3/7/2024 - 8:31:29
RTC time after update 3/7/2024 - 8:31:29
RTC time before update: 3/7/2024 - 8:41:34
NTP time: 3/7/2024 - 8:41:29
RTC time after update 3/7/2024 - 8:41:29

Allerdings war es auf dem Funkwecker heute Morgen zum Update bereits 8:42:55.

Hat zufällig jemand von euch eine Ahnung, was diesen Drift verursacht und wie ich diesen beheben kann? Habe auf meinem r4 auch schon die Firmenware aktualisiert. Bevor ich jetzt das blinde Stochern anfange, frage ich lieber euch. Falls ihr noch Angaben braucht, um das Problem weiter einzugrenzen, sagt gerne Bescheid.

Grüße
Andy

Hallo und willkommen.
Dann mal die Frage, warum überhaupt eine RTC, wenn du NTP nutzt ?

Was für eine RTC?
Was für ein Zeitserver? Bei den kurzen Abfrage-Intervallen könnte es sein, dass Du da bald gesperrt bist.

Gruß Tommy

Hallo, berechtigte Frage,

ich bin davon ausgegangen, dass der NTP nicht mitläuft, und für die Zeit zwingend das RTC brauche. Die Grundidee war, dass ich den R4 nur kurz ins Netz nehme um die Uhrzeit einzurichten und der dann auch ohne Netzwerk läuft. Dann habe ich erfahren, dass die RTC im R4 nicht als Uhr zu gebrauchen ist, daher entwickelte ich die Idee des Updates über den NTP.

Wenn du allerdings jetzt sagst, dass der NTP auch selbst eine eigenständige Uhr ist, dann kann ich meinen Ansatz nochmal neu denken.

Jedoch bin ich auch ein wenig neugierig, wie der Drift überhaupt entsteht.

Grüße

@Tommy56

Ich verwende den internen RTC vom Arduino R4 Wifi und welcher Zeitserver wird mir in der lib nicht beschrieben. Ich verwende diese Lib hier:

https://github.com/sstaub/NTP

Ich kann mich gleich mal auf die Suche danach machen, welcher Zeitserver da angesteuert wird.

Was das Intervall betrifft, so hatte ich eigentlich gelesen, dass das Intervall so ok wäre. Aber das wäre auch eine Fehlerquelle.

edit: laut code verbindet die lib mit pool.ntp.org

An der Abweichung siehst Du schon, das es mit deren Genauigkeit nicht weit her zu sein scheint. (Ich kenne das Teil nicht).
Normalerweise greift man so im Bereich 2Std bis 12 Std. auf NTP zu, den Rest schafft normalerweise der MC auch ohne RTC.

Gruß Tommy

Es gibt doch schon zahlreiche Beispiele im Web, RTC und NTP des R4 zu nutzen.
Z.B. Dies hier

Da ich den Uno R4 Wifi nicht nutze, muss ich auch googeln. :wink:

Ich fasse hier mal die Antwort auf euch beide zusammen.

Die "onboard RTC" hängt leider bereits nach 10 min um ein paar Sekunden hinterher. Die ist also mehr Mist, als angenommen.

Wenn alle 2h das Minimum ist, dann ist das schon mal kein Ansatz, den ich weiter verfolgen sollte. Ich schreibe den Sketch mal so um, dass sich das NTP deutlich seltener updated und ohne RTC auskommt.

Was die Beispiele angeht, im Vorfeld hatte ich eine Menge gegoogelt, hatte aber nur Beispiele gefunden, bei denen das NTP nur einmal in der Setup abgerufen wird und nicht in der Loop synchronisiert wird. Deshalb hatte ich die für mich aussortiert. :man_shrugging:
Ich hatte mein Problem in der update_rtc() vermutet.

Was mich halt wirklich stutzig macht: Es scheint, als ob der Arduino bei jedem Update ein paar Sekunden "verliert". Das würde den Drift erklären (ist aber nur Bauchgefühl).

Grüße
Andy

Ich weiß nicht, ob es am R4 liegt, aber ich verwende ESP8266 ohne RTC mit NTP mit 2 Stunden-Intervall-Abfrage von der lokalen Fritzbox im 24/7 Betrieb und kann dort keine Abweichungen von einer per Funk synchronisierten Uhr feststellen.

Gruß Tommy

Edit: Keine Abweichungen mit Sekundenanzeige

Bei mir läuft eine Uhr auf dem ESP32-C3.
Genutzt wird die Chip interne RTC
Jetzt seit ca. 2 Wochen.
Die Abweichung ist unter 1 Minute, kleinere Zeiten, also Sekunden zeigt sie nicht.

Eine neue Zeit holt sich das Ding nur auf Knopfdruck.


Wenn die RTC des Renesas RA4M1 so schief läuft, sollte man sich evtl. mal mit dem Datenblatt beschäftigen, evtl. gibt es da was zum kalibrieren.
Auch gibt es ja da den ESP32-S3 auf dem Board, mit einer RTC.

PS:
RTC Control Register 2 (RCR2) im User Manual

Hi, ich hatte den gestern Abend einmal ohne RTC laufen lassen. Die Zeit hatte er sich beim Start geholt. Nach etwa 2h hing die Zeit etwa 10s hinterher. Am Wochenende habe ich wieder etwas Zeit über, dann versuche ich das mal ohne RTC mit einem 4h Intervall und packe wieder meinen Wecker daneben. Wenn dabei kein Drift mehr entsteht, dann ist es ok. Mit einer Abweichung um 20 - 30 s. kann ich gut leben.

Einen lieben Dank für die Info, dass das mit einem ESP deutlich stabiler läuft. Mittelfristig soll das Projekt für mehrere Terras umgesetzt werden, daher wollte ich schon aus Kostengründen wechseln. Den r4 hatte ich halt da, werde da aber nicht mehr zu viel Zeit reinstecken.

Danke für euer aller Hilfe. Ich setze das Thema gleich auf gelöst.

Grüße
Andy

Kann ein Einzelfall sein.

Schon drüber nachgedacht?

Sind 4 Wemos D1 mini (evtl. aus der gleichen Charge)

Gruß Tommy

Habe gerade (hoffentlich)ein passendes Manual dazu gefunden

Corrections to Realtime Clock (RTC) in RX Family

(https://www.renesas.com/us/en/document/tcu/corrections-realtime-clock-rtc-rx-family)

allerdings ist das auf einem Niveau, an dem ich als Anfänger einfach noch nicht bin. Ich werde dafür noch deutlich mehr lernen müssen.

Grüße

Du hast die Korrekturen gefunden.
Auch ok, aber erst der zweite Schritt.

@combie
Hi, so, wie ich es verstehe, liegt der Fehler beim Start des RTC. Da wird in b7 vom RCR2 mit 0 initialisiert, und nicht mit 0x00. (Also nur ein halbes Byte). Ich müsste also beim Start der RTC "von Hand" den richtigen Wert ins Register laden, oder? Das müsste dann als Code in meinen Sketch mit rein.

Falls das so ist, dann würde ich mich da auf die Suche danach machen, wie das geht. Ich habe nur ein bisschen Angst, mir bei der Gelegenheit den r4 zu zerschießen. Deshalb frage ich lieber nochmal nach. :sweat_smile:

Grüße
Andy

Einen solchen Datentype gibt es nicht.

0, 0x00, 0b0 --- alles das gleiche.
Je 32Bit breit

Die genannte Stelle kenne ich nicht.

Glaube ich nicht, dass du das so hin bekommst.
Nach einem Power on, ist das Register wieder wie neu, (solange da keine Batterie an der RTC hängt).

Kenne ich aus Assembler als DWORD (4bit).

Ich hatte die Lösung falsch verstanden. Laut Lösung setzt sich beim Starten des RTC im Register RCR2 das b7=0. Der Fix ist, dass beim Starten des RTC aber das ganze Register RCR2=00H gesetzt werden muss. Ich finde hierzu blöderweise keine Anleitung. Wahrscheinlich hat das auch seinen Grund. Ich muss aber auch zugeben. Hier bin ich kognitiv raus.

Das sind 4 Byte, nicht 4 Bit

Ein Nibble oder auch Halbbyte hat 4 Bit

Einfach nur RCR2=0; funktioniert nicht?

Jetzt wird es hier für mich langsam peinlich. Du hast natürlich Recht mit dem 4 Byte. Ist bei mir schon etwas her. RCR2=0; verursacht einen Comlilerfehler.

Compilation error: 'RCR2' was not declared in this scope

Welche .h muss ich einbinden?

Ich war schon im englischsprachigen Teil des Forums auf einen Thread gestoßen, da wurde diskutiert, wie man überhaupt eine Registermanipulation auf den Chip bringt. Das Forum vom Chiphersteller ist da auch nicht hilfreich. Ich bin echt noch nicht tief genug in der Materie drin. Vielleicht bin ich auch schon auf die Lösung gestoßen, habe sie nur nicht als solche erkannt. Je mehr ich versuche mit einzulesen, umso widersprüchlicher wird das Ganze. Falls du ein gutes Tut kennst (auch für später mal) gerne her damit.