From 035b7abe269d056c5213f3d0f0563c5b4b005a58 Mon Sep 17 00:00:00 2001 From: Klaus K Wilting Date: Mon, 11 Feb 2019 23:37:45 +0100 Subject: [PATCH] IF482 precision improvement --- include/rtctime.h | 2 +- src/gpsread.cpp | 5 +++-- src/if482.cpp | 49 +++++++++++++++++++++++++++++++---------------- src/rtctime.cpp | 24 +++++++++++------------ 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/include/rtctime.h b/include/rtctime.h index 8a98f241..603f6e64 100644 --- a/include/rtctime.h +++ b/include/rtctime.h @@ -23,6 +23,6 @@ float get_rtctemp(void); void IRAM_ATTR CLOCKIRQ(); int timepulse_init(uint32_t pps_freq); void timepulse_start(); -uint8_t sync_clock(time_t t); +time_t sync_clock(time_t t); #endif // _RTCTIME_H \ No newline at end of file diff --git a/src/gpsread.cpp b/src/gpsread.cpp index 6e094faf..639ad725 100644 --- a/src/gpsread.cpp +++ b/src/gpsread.cpp @@ -88,10 +88,11 @@ time_t tmConvert_t(uint16_t YYYY, uint8_t MM, uint8_t DD, uint8_t hh, // function to fetch current time from gps time_t get_gpstime(void) { - // never call now() in this function, this would cause a recursion! + // never call now() in this function, this would break this function + // to use as SyncProvider due to recursive call to now() time_t t = 0; if ((gps.time.age() < 1500) && (gps.time.isValid())) { - t = tmConvert_t(gps.date.year(), gps.date.month(), gps.date.day(), + t = 1 + tmConvert_t(gps.date.year(), gps.date.month(), gps.date.day(), gps.time.hour(), gps.time.minute(), gps.time.second()); ESP_LOGD(TAG, "GPS time: %4d/%02d/%02d %02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t)); diff --git a/src/if482.cpp b/src/if482.cpp index c08cdec3..d823e19b 100644 --- a/src/if482.cpp +++ b/src/if482.cpp @@ -115,19 +115,19 @@ int if482_init(void) { "if482loop", // name of task 2048, // stack size of task (void *)1, // parameter of the task - 3, // priority of the task + 4, // priority of the task &ClockTask, // task handle 0); // CPU core assert(ClockTask); // has clock task started? - timepulse_start(); // start pulse + // timepulse_start(); // start pulse return 1; // success } // if482_init String IF482_Out(time_t tt) { - time_t t = myTZ.toLocal(tt); + time_t t = 1 + myTZ.toLocal(tt); char mon, buf[14], out[IF482_FRAME_SIZE]; switch (timeStatus()) { // indicates if time has been set and recently synced @@ -159,18 +159,32 @@ void if482_loop(void *pvParameters) { configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check + time_t tOut; TickType_t wakeTime; - const TickType_t timeOffset = - tx_time(HAS_IF482); // duration of telegram transmit - const TickType_t startTime = xTaskGetTickCount(); // now + const TickType_t tTx = tx_time(HAS_IF482); // duration of telegram transmit + BitsPending = true; // start blink in display - sync_clock(now()); // wait until begin of a new second - BitsPending = true; // start blink in display + // phase 1: sync task on top of second - // take timestamp at moment of start of new second - const TickType_t shotTime = xTaskGetTickCount() - startTime - timeOffset; + sync_clock(now()); - // task remains in blocked state until it is notified by isr + const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second + + timepulse_start(); // start timepulse + + xTaskNotifyWait( + 0x00, // don't clear any bits on entry + ULONG_MAX, // clear all bits on exit + &wakeTime, // receives moment of call from isr + portMAX_DELAY); // wait forever (missing error handling here...) + + const TickType_t tOffset = wakeTime - t0; + const TickType_t tShot = + (tOffset < tTx) ? (1000 - tOffset - tTx) : (tOffset - tTx); + + ESP_LOGI(TAG, "IF482 signal synced with precision %dms", 1000 - tOffset); + + // phase 2: sync task on time pulse interrupt for (;;) { xTaskNotifyWait( 0x00, // don't clear any bits on entry @@ -178,22 +192,25 @@ void if482_loop(void *pvParameters) { &wakeTime, // receives moment of call from isr portMAX_DELAY); // wait forever (missing error handling here...) + tOut = now() + 1; // next second after waketime + // select clock scale #if (PPS == IF482_PULSE_DURATION) // we don't need clock rescaling // wait until it's time to start transmit telegram for next second - vTaskDelayUntil(&wakeTime, shotTime); // sets waketime to moment of shot - IF482.print(IF482_Out(now() + 1)); + vTaskDelayUntil(&wakeTime, tShot); // sets waketime to moment of tShot + IF482.print(IF482_Out(tOut)); #elif (PPS > IF482_PULSE_DURATION) // we need upclocking for (uint8_t i = 1; i <= PPS / IF482_PULSE_DURATION; i++) { - vTaskDelayUntil(&wakeTime, shotTime); // sets waketime to moment of shot - IF482.print(IF482_Out(now() + 1)); + vTaskDelayUntil(&wakeTime, tShot); // sets waketime to moment of shot + IF482.print(IF482_Out(tOut)); } #elif (PPS < IF482_PULSE_DURATION) // we need downclocking, not yet implemented #error Timepulse is too low for IF482! #endif - } + } // forever + } // if482_loop() // helper function to calculate IF482 telegram serial tx time from serial diff --git a/src/rtctime.cpp b/src/rtctime.cpp index 7c120ac7..1f2c13da 100644 --- a/src/rtctime.cpp +++ b/src/rtctime.cpp @@ -1,5 +1,7 @@ #include "rtctime.h" +#define I2C_DELAY (12) // 12ms is i2c delay when saving time to RTC chip + // Local logging tag static const char TAG[] = "main"; @@ -60,11 +62,13 @@ error: } // rtc_init() -int set_rtctime(time_t t) { // t is epoch time starting 1.1.1970 +int set_rtctime(time_t t) { // t is seconds epoch time starting 1.1.1970 if (I2C_MUTEX_LOCK()) { - Rtc.SetDateTime(RtcDateTime(t)); + time_t tt = sync_clock(t); // wait for top of second + Rtc.SetDateTime(RtcDateTime(tt)); I2C_MUTEX_UNLOCK(); // release i2c bus access - return 1; // success + ESP_LOGI(TAG, "RTC calibrated"); + return 1; // success } return 0; // failure } // set_rtctime() @@ -176,15 +180,11 @@ void timepulse_start() { #endif } -// helper function to sync phase of DCF output signal to start of second t -uint8_t sync_clock(time_t t) { - time_t tt = t; - // delay until start of next second - do { - tt = now(); - } while (t == tt); - ESP_LOGI(TAG, "Sync on Sec %d", second(tt)); - return second(tt); +// helper function to sync time_t of top of next second +time_t sync_clock(time_t t) { + while (millis() % 1000) + ; // wait for milli seconds to be zero before setting new time + return (now()); } // interrupt service routine triggered by either rtc pps or esp32 hardware