IF482 precision improvement

This commit is contained in:
Klaus K Wilting 2019-02-11 23:37:45 +01:00
parent 87378738d2
commit 035b7abe26
4 changed files with 49 additions and 31 deletions

View File

@ -23,6 +23,6 @@ float get_rtctemp(void);
void IRAM_ATTR CLOCKIRQ(); void IRAM_ATTR CLOCKIRQ();
int timepulse_init(uint32_t pps_freq); int timepulse_init(uint32_t pps_freq);
void timepulse_start(); void timepulse_start();
uint8_t sync_clock(time_t t); time_t sync_clock(time_t t);
#endif // _RTCTIME_H #endif // _RTCTIME_H

View File

@ -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 // function to fetch current time from gps
time_t get_gpstime(void) { 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; time_t t = 0;
if ((gps.time.age() < 1500) && (gps.time.isValid())) { 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()); gps.time.hour(), gps.time.minute(), gps.time.second());
ESP_LOGD(TAG, "GPS time: %4d/%02d/%02d %02d:%02d:%02d", year(t), month(t), ESP_LOGD(TAG, "GPS time: %4d/%02d/%02d %02d:%02d:%02d", year(t), month(t),
day(t), hour(t), minute(t), second(t)); day(t), hour(t), minute(t), second(t));

View File

@ -115,19 +115,19 @@ int if482_init(void) {
"if482loop", // name of task "if482loop", // name of task
2048, // stack size of task 2048, // stack size of task
(void *)1, // parameter of the task (void *)1, // parameter of the task
3, // priority of the task 4, // priority of the task
&ClockTask, // task handle &ClockTask, // task handle
0); // CPU core 0); // CPU core
assert(ClockTask); // has clock task started? assert(ClockTask); // has clock task started?
timepulse_start(); // start pulse // timepulse_start(); // start pulse
return 1; // success return 1; // success
} // if482_init } // if482_init
String IF482_Out(time_t tt) { 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]; char mon, buf[14], out[IF482_FRAME_SIZE];
switch (timeStatus()) { // indicates if time has been set and recently synced 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 configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
time_t tOut;
TickType_t wakeTime; TickType_t wakeTime;
const TickType_t timeOffset = const TickType_t tTx = tx_time(HAS_IF482); // duration of telegram transmit
tx_time(HAS_IF482); // duration of telegram transmit
const TickType_t startTime = xTaskGetTickCount(); // now
sync_clock(now()); // wait until begin of a new second
BitsPending = true; // start blink in display BitsPending = true; // start blink in display
// take timestamp at moment of start of new second // phase 1: sync task on top of second
const TickType_t shotTime = xTaskGetTickCount() - startTime - timeOffset;
// task remains in blocked state until it is notified by isr sync_clock(now());
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 (;;) { for (;;) {
xTaskNotifyWait( xTaskNotifyWait(
0x00, // don't clear any bits on entry 0x00, // don't clear any bits on entry
@ -178,22 +192,25 @@ void if482_loop(void *pvParameters) {
&wakeTime, // receives moment of call from isr &wakeTime, // receives moment of call from isr
portMAX_DELAY); // wait forever (missing error handling here...) portMAX_DELAY); // wait forever (missing error handling here...)
tOut = now() + 1; // next second after waketime
// select clock scale // select clock scale
#if (PPS == IF482_PULSE_DURATION) // we don't need clock rescaling #if (PPS == IF482_PULSE_DURATION) // we don't need clock rescaling
// wait until it's time to start transmit telegram for next second // wait until it's time to start transmit telegram for next second
vTaskDelayUntil(&wakeTime, shotTime); // sets waketime to moment of shot vTaskDelayUntil(&wakeTime, tShot); // sets waketime to moment of tShot
IF482.print(IF482_Out(now() + 1)); IF482.print(IF482_Out(tOut));
#elif (PPS > IF482_PULSE_DURATION) // we need upclocking #elif (PPS > IF482_PULSE_DURATION) // we need upclocking
for (uint8_t i = 1; i <= PPS / IF482_PULSE_DURATION; i++) { for (uint8_t i = 1; i <= PPS / IF482_PULSE_DURATION; i++) {
vTaskDelayUntil(&wakeTime, shotTime); // sets waketime to moment of shot vTaskDelayUntil(&wakeTime, tShot); // sets waketime to moment of shot
IF482.print(IF482_Out(now() + 1)); IF482.print(IF482_Out(tOut));
} }
#elif (PPS < IF482_PULSE_DURATION) // we need downclocking, not yet implemented #elif (PPS < IF482_PULSE_DURATION) // we need downclocking, not yet implemented
#error Timepulse is too low for IF482! #error Timepulse is too low for IF482!
#endif #endif
} } // forever
} // if482_loop() } // if482_loop()
// helper function to calculate IF482 telegram serial tx time from serial // helper function to calculate IF482 telegram serial tx time from serial

View File

@ -1,5 +1,7 @@
#include "rtctime.h" #include "rtctime.h"
#define I2C_DELAY (12) // 12ms is i2c delay when saving time to RTC chip
// Local logging tag // Local logging tag
static const char TAG[] = "main"; static const char TAG[] = "main";
@ -60,10 +62,12 @@ error:
} // rtc_init() } // 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()) { 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 I2C_MUTEX_UNLOCK(); // release i2c bus access
ESP_LOGI(TAG, "RTC calibrated");
return 1; // success return 1; // success
} }
return 0; // failure return 0; // failure
@ -176,15 +180,11 @@ void timepulse_start() {
#endif #endif
} }
// helper function to sync phase of DCF output signal to start of second t // helper function to sync time_t of top of next second
uint8_t sync_clock(time_t t) { time_t sync_clock(time_t t) {
time_t tt = t; while (millis() % 1000)
// delay until start of next second ; // wait for milli seconds to be zero before setting new time
do { return (now());
tt = now();
} while (t == tt);
ESP_LOGI(TAG, "Sync on Sec %d", second(tt));
return second(tt);
} }
// interrupt service routine triggered by either rtc pps or esp32 hardware // interrupt service routine triggered by either rtc pps or esp32 hardware