clock time handling modifications (still experimental)
This commit is contained in:
parent
42971b60cd
commit
1ac176075a
@ -102,7 +102,6 @@ extern uint16_t volatile macs_total, macs_wifi, macs_ble,
|
|||||||
batt_voltage; // display values
|
batt_voltage; // display values
|
||||||
extern hw_timer_t *sendCycle, *displaytimer;
|
extern hw_timer_t *sendCycle, *displaytimer;
|
||||||
extern SemaphoreHandle_t I2Caccess, TimePulse;
|
extern SemaphoreHandle_t I2Caccess, TimePulse;
|
||||||
extern bool volatile BitsPending;
|
|
||||||
|
|
||||||
extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
|
extern std::set<uint16_t, std::less<uint16_t>, Mallocator<uint16_t>> macs;
|
||||||
extern std::array<uint64_t, 0xff>::iterator it;
|
extern std::array<uint64_t, 0xff>::iterator it;
|
||||||
|
@ -13,6 +13,7 @@ extern RtcDS3231<TwoWire> Rtc; // make RTC instance globally available
|
|||||||
|
|
||||||
extern TaskHandle_t ClockTask;
|
extern TaskHandle_t ClockTask;
|
||||||
extern hw_timer_t *clockCycle;
|
extern hw_timer_t *clockCycle;
|
||||||
|
extern bool volatile TimePulseTick;
|
||||||
|
|
||||||
int rtc_init(void);
|
int rtc_init(void);
|
||||||
int set_rtctime(uint32_t t);
|
int set_rtctime(uint32_t t);
|
||||||
@ -23,6 +24,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();
|
||||||
time_t sync_clock(time_t t);
|
void sync_clock(void);
|
||||||
|
|
||||||
#endif // _RTCTIME_H
|
#endif // _RTCTIME_H
|
@ -17,6 +17,8 @@ https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/Funkuhr.zip/
|
|||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = "main";
|
static const char TAG[] = "main";
|
||||||
|
|
||||||
|
bool volatile BitsPending = false;
|
||||||
|
|
||||||
#define DCF77_FRAME_SIZE (60)
|
#define DCF77_FRAME_SIZE (60)
|
||||||
#define DCF77_PULSE_DURATION (100)
|
#define DCF77_PULSE_DURATION (100)
|
||||||
|
|
||||||
@ -35,8 +37,6 @@ uint8_t DCFtimeframe[DCF77_FRAME_SIZE];
|
|||||||
// initialize and configure DCF77 output
|
// initialize and configure DCF77 output
|
||||||
int dcf77_init(void) {
|
int dcf77_init(void) {
|
||||||
|
|
||||||
BitsPending = false;
|
|
||||||
|
|
||||||
pinMode(HAS_DCF77, OUTPUT);
|
pinMode(HAS_DCF77, OUTPUT);
|
||||||
set_DCF77_pin(dcf_low);
|
set_DCF77_pin(dcf_low);
|
||||||
timepulse_init(PPS); // setup timepulse
|
timepulse_init(PPS); // setup timepulse
|
||||||
@ -49,9 +49,9 @@ int dcf77_init(void) {
|
|||||||
&ClockTask, // task handle
|
&ClockTask, // task handle
|
||||||
0); // CPU core
|
0); // CPU core
|
||||||
|
|
||||||
assert(ClockTask); // has clock task started?
|
assert(ClockTask); // has clock task started?
|
||||||
DCF_Out(second(now())); // sync DCF time on next second
|
DCF_Out(second(now())); // sync DCF time on next second
|
||||||
timepulse_start(); // start pulse
|
timepulse_start(); // start pulse
|
||||||
|
|
||||||
return 1; // success
|
return 1; // success
|
||||||
} // ifdcf77_init
|
} // ifdcf77_init
|
||||||
@ -70,7 +70,7 @@ void DCF_Out(uint8_t startOffset_sec) {
|
|||||||
if ((timeStatus() == timeSet) || (timeStatus() == timeNeedsSync)) {
|
if ((timeStatus() == timeSet) || (timeStatus() == timeNeedsSync)) {
|
||||||
// prepare frame to send for next minute
|
// prepare frame to send for next minute
|
||||||
generateTimeframe(now() + DCF77_FRAME_SIZE + 1);
|
generateTimeframe(now() + DCF77_FRAME_SIZE + 1);
|
||||||
// start blinking symbol on display and kick off timer
|
// kick off output of telegram
|
||||||
BitsPending = true;
|
BitsPending = true;
|
||||||
} else
|
} else
|
||||||
return;
|
return;
|
||||||
@ -103,7 +103,7 @@ void DCF_Out(uint8_t startOffset_sec) {
|
|||||||
// recalibrate clock after a fixed timespan, do this in 59th second
|
// recalibrate clock after a fixed timespan, do this in 59th second
|
||||||
#ifdef TIME_SYNC_INTERVAL_DCF
|
#ifdef TIME_SYNC_INTERVAL_DCF
|
||||||
if ((millis() >= nextDCFsync)) {
|
if ((millis() >= nextDCFsync)) {
|
||||||
sync_clock(now()); // waiting for second 59
|
sync_clock(); // waiting for second 59
|
||||||
nextDCFsync = millis() + TIME_SYNC_INTERVAL_DCF *
|
nextDCFsync = millis() + TIME_SYNC_INTERVAL_DCF *
|
||||||
60000; // set up next time sync period
|
60000; // set up next time sync period
|
||||||
}
|
}
|
||||||
|
@ -221,15 +221,12 @@ void refreshtheDisplay() {
|
|||||||
// update LoRa status display (line 6)
|
// update LoRa status display (line 6)
|
||||||
u8x8.printf("%-16s", display_line6);
|
u8x8.printf("%-16s", display_line6);
|
||||||
#else // we want a time display instead LoRa status
|
#else // we want a time display instead LoRa status
|
||||||
// update time/date display (line 6)
|
|
||||||
time_t t = myTZ.toLocal(now());
|
time_t t = myTZ.toLocal(now());
|
||||||
char timeState =
|
char timeState =
|
||||||
timeStatus() == timeSet ? timesyncSymbol : timeNosyncSymbol;
|
(timeStatus() == timeSet) ? timesyncSymbol : timeNosyncSymbol;
|
||||||
// make timestatus symbol blinking if pps line
|
char timePulse = TimePulseTick ? '.' : ':';
|
||||||
if ((BitsPending) && (second(t) % 2))
|
u8x8.printf("%02d:%02d%c%02d%c %2d.%3s", hour(t), minute(t), timePulse,
|
||||||
timeState = ' ';
|
second(t), timeState, day(t), printmonth[month(t)]);
|
||||||
u8x8.printf("%02d:%02d:%02d%c %2d.%3s", hour(t), minute(t), second(t),
|
|
||||||
timeState, day(t), printmonth[month(t)]);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// update LMiC event display (line 7)
|
// update LMiC event display (line 7)
|
||||||
|
@ -88,28 +88,23 @@ 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 break this function
|
// !! never call now() in this function, this would break this function
|
||||||
// to use as SyncProvider due to recursive call to now()
|
// to be used as SyncProvider due to recursive call to now()
|
||||||
|
|
||||||
time_t t;
|
|
||||||
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(),
|
// get current gps time
|
||||||
gps.time.hour(), gps.time.minute(), gps.time.second());
|
time_t t =
|
||||||
|
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),
|
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));
|
||||||
|
// sync on top of next second by timepulse
|
||||||
|
sync_clock();
|
||||||
|
return t + 1;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "GPS has no confident time");
|
ESP_LOGW(TAG, "GPS has no confident time");
|
||||||
return 0;
|
return 0; // sync failure, 0 effects calling SyncProvider() to not set time
|
||||||
}
|
}
|
||||||
|
|
||||||
// sync on top of next second bv timepulse
|
|
||||||
if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)) == pdTRUE)
|
|
||||||
return t;
|
|
||||||
else {
|
|
||||||
ESP_LOGW(TAG, "No GPS timepulse, thus time can't be synced by GPS");
|
|
||||||
return 0;
|
|
||||||
} // failure
|
|
||||||
|
|
||||||
} // get_gpstime()
|
} // get_gpstime()
|
||||||
|
|
||||||
// GPS serial feed FreeRTos Task
|
// GPS serial feed FreeRTos Task
|
||||||
|
@ -161,16 +161,11 @@ void if482_loop(void *pvParameters) {
|
|||||||
|
|
||||||
TickType_t wakeTime;
|
TickType_t wakeTime;
|
||||||
const TickType_t tTx = tx_time(HAS_IF482); // duration of telegram transmit
|
const TickType_t tTx = tx_time(HAS_IF482); // duration of telegram transmit
|
||||||
BitsPending = true; // start blink in display
|
|
||||||
|
|
||||||
// phase 1: sync task on top of second
|
// phase 1: sync task on top of second
|
||||||
|
|
||||||
const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second
|
const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second
|
||||||
|
sync_clock(); // delay until top of second
|
||||||
sync_clock(now()); // delay until top of second
|
|
||||||
|
|
||||||
// const TickType_t t0 = xTaskGetTickCount(); // moment of start top of second
|
|
||||||
|
|
||||||
timepulse_start(); // start timepulse
|
timepulse_start(); // start timepulse
|
||||||
|
|
||||||
xTaskNotifyWait(
|
xTaskNotifyWait(
|
||||||
|
28
src/main.cpp
28
src/main.cpp
@ -65,7 +65,6 @@ char display_line6[16], display_line7[16]; // display buffers
|
|||||||
uint8_t volatile channel = 0; // channel rotation counter
|
uint8_t volatile channel = 0; // channel rotation counter
|
||||||
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0,
|
||||||
batt_voltage = 0; // globals for display
|
batt_voltage = 0; // globals for display
|
||||||
bool volatile BitsPending = false; // DCF77 or IF482 ticker indicator
|
|
||||||
|
|
||||||
hw_timer_t *sendCycle = NULL, *homeCycle = NULL;
|
hw_timer_t *sendCycle = NULL, *homeCycle = NULL;
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
@ -97,16 +96,14 @@ void setup() {
|
|||||||
|
|
||||||
char features[100] = "";
|
char features[100] = "";
|
||||||
|
|
||||||
|
// create some semaphores for syncing / mutexing tasks
|
||||||
I2Caccess = xSemaphoreCreateMutex(); // for access management of i2c bus
|
I2Caccess = xSemaphoreCreateMutex(); // for access management of i2c bus
|
||||||
if (I2Caccess)
|
if (I2Caccess)
|
||||||
xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use
|
xSemaphoreGive(I2Caccess); // Flag the i2c bus available for use
|
||||||
|
|
||||||
TimePulse = xSemaphoreCreateMutex(); // for time pulse flip
|
TimePulse = xSemaphoreCreateBinary(); // as signal that shows time pulse flip
|
||||||
if (TimePulse)
|
|
||||||
xSemaphoreTake(TimePulse, (TickType_t)10);
|
|
||||||
// Block TimePulse since we have no pulse yet
|
|
||||||
|
|
||||||
// disable brownout detection
|
// disable brownout detection
|
||||||
#ifdef DISABLE_BROWNOUT
|
#ifdef DISABLE_BROWNOUT
|
||||||
// register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
|
// register with brownout is at address DR_REG_RTCCNTL_BASE + 0xd4
|
||||||
(*((uint32_t volatile *)ETS_UNCACHED_ADDR((DR_REG_RTCCNTL_BASE + 0xd4)))) = 0;
|
(*((uint32_t volatile *)ETS_UNCACHED_ADDR((DR_REG_RTCCNTL_BASE + 0xd4)))) = 0;
|
||||||
@ -146,10 +143,21 @@ void setup() {
|
|||||||
ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
|
ESP.getChipRevision(), ESP.getCpuFreqMHz(), ESP.getSdkVersion());
|
||||||
ESP_LOGI(TAG, "Flash Size %d, Flash Speed %d", ESP.getFlashChipSize(),
|
ESP_LOGI(TAG, "Flash Size %d, Flash Speed %d", ESP.getFlashChipSize(),
|
||||||
ESP.getFlashChipSpeed());
|
ESP.getFlashChipSpeed());
|
||||||
ESP_LOGI(TAG, "Wifi/BT software coexist version: %s", esp_coex_version_get());
|
ESP_LOGI(TAG, "Wifi/BT software coexist version %s", esp_coex_version_get());
|
||||||
|
|
||||||
|
#ifdef HAS_LORA
|
||||||
|
ESP_LOGI(TAG, "IBM LMIC version %d.%d.%d", LMIC_VERSION_MAJOR,
|
||||||
|
LMIC_VERSION_MINOR, LMIC_VERSION_BUILD);
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Arduino LMIC version %d.%d.%d.%d",
|
||||||
|
ARDUINO_LMIC_VERSION_GET_MAJOR(ARDUINO_LMIC_VERSION),
|
||||||
|
ARDUINO_LMIC_VERSION_GET_MINOR(ARDUINO_LMIC_VERSION),
|
||||||
|
ARDUINO_LMIC_VERSION_GET_PATCH(ARDUINO_LMIC_VERSION),
|
||||||
|
ARDUINO_LMIC_VERSION_GET_LOCAL(ARDUINO_LMIC_VERSION));
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
ESP_LOGI(TAG, "TinyGPS+ v%s", TinyGPSPlus::libraryVersion());
|
ESP_LOGI(TAG, "TinyGPS+ version %s", TinyGPSPlus::libraryVersion());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // verbose
|
#endif // verbose
|
||||||
@ -330,7 +338,7 @@ void setup() {
|
|||||||
#ifdef HAS_RTC
|
#ifdef HAS_RTC
|
||||||
strcat_P(features, " RTC");
|
strcat_P(features, " RTC");
|
||||||
assert(rtc_init());
|
assert(rtc_init());
|
||||||
setSyncProvider(&get_rtctime);
|
setSyncProvider(&get_rtctime); // sync time now and then
|
||||||
if (timeStatus() != timeSet)
|
if (timeStatus() != timeSet)
|
||||||
ESP_LOGI(TAG, "Unable to sync system time with RTC");
|
ESP_LOGI(TAG, "Unable to sync system time with RTC");
|
||||||
else
|
else
|
||||||
@ -408,7 +416,7 @@ void setup() {
|
|||||||
#endif // HAS_BUTTON
|
#endif // HAS_BUTTON
|
||||||
|
|
||||||
#ifdef HAS_GPS
|
#ifdef HAS_GPS
|
||||||
setSyncProvider(&get_gpstime);
|
setSyncProvider(&get_gpstime); // sync time now and then
|
||||||
if (timeStatus() != timeSet)
|
if (timeStatus() != timeSet)
|
||||||
ESP_LOGI(TAG, "Unable to sync system time with GPS");
|
ESP_LOGI(TAG, "Unable to sync system time with GPS");
|
||||||
else {
|
else {
|
||||||
|
227
src/rtctime.cpp
227
src/rtctime.cpp
@ -7,104 +7,7 @@ static const char TAG[] = "main";
|
|||||||
|
|
||||||
TaskHandle_t ClockTask;
|
TaskHandle_t ClockTask;
|
||||||
hw_timer_t *clockCycle = NULL;
|
hw_timer_t *clockCycle = NULL;
|
||||||
|
bool volatile TimePulseTick = false;
|
||||||
#ifdef HAS_RTC // we have hardware RTC
|
|
||||||
|
|
||||||
RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
|
|
||||||
|
|
||||||
// initialize RTC
|
|
||||||
int rtc_init(void) {
|
|
||||||
|
|
||||||
// return = 0 -> error / return = 1 -> success
|
|
||||||
|
|
||||||
// block i2c bus access
|
|
||||||
if (I2C_MUTEX_LOCK()) {
|
|
||||||
|
|
||||||
Wire.begin(HAS_RTC);
|
|
||||||
Rtc.Begin();
|
|
||||||
|
|
||||||
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
|
|
||||||
|
|
||||||
if (!Rtc.IsDateTimeValid()) {
|
|
||||||
ESP_LOGW(TAG,
|
|
||||||
"RTC has no valid RTC date/time, setting to compilation date");
|
|
||||||
Rtc.SetDateTime(compiled);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Rtc.GetIsRunning()) {
|
|
||||||
ESP_LOGI(TAG, "RTC not running, starting now");
|
|
||||||
Rtc.SetIsRunning(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
RtcDateTime now = Rtc.GetDateTime();
|
|
||||||
|
|
||||||
if (now < compiled) {
|
|
||||||
ESP_LOGI(TAG, "RTC date/time is older than compilation date, updating");
|
|
||||||
Rtc.SetDateTime(compiled);
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure RTC chip
|
|
||||||
Rtc.Enable32kHzPin(false);
|
|
||||||
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
|
||||||
ESP_LOGI(TAG, "RTC initialized");
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
error:
|
|
||||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
} // rtc_init()
|
|
||||||
|
|
||||||
int set_rtctime(time_t t) { // t is seconds epoch time starting 1.1.1970
|
|
||||||
if (I2C_MUTEX_LOCK()) {
|
|
||||||
time_t tt = sync_clock(t); // wait for top of second
|
|
||||||
Rtc.SetDateTime(RtcDateTime(tt));
|
|
||||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
|
||||||
ESP_LOGI(TAG, "RTC calibrated");
|
|
||||||
return 1; // success
|
|
||||||
}
|
|
||||||
return 0; // failure
|
|
||||||
} // set_rtctime()
|
|
||||||
|
|
||||||
int set_rtctime(uint32_t t) { // t is epoch seconds starting 1.1.1970
|
|
||||||
return set_rtctime(static_cast<time_t>(t));
|
|
||||||
// set_rtctime()
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t get_rtctime(void) {
|
|
||||||
// never call now() in this function, this would cause a recursion!
|
|
||||||
time_t t = 0;
|
|
||||||
// block i2c bus access
|
|
||||||
if (I2C_MUTEX_LOCK()) {
|
|
||||||
if (Rtc.IsDateTimeValid()) {
|
|
||||||
RtcDateTime tt = Rtc.GetDateTime();
|
|
||||||
t = tt.Epoch32Time();
|
|
||||||
} else {
|
|
||||||
ESP_LOGW(TAG, "RTC has no confident time");
|
|
||||||
}
|
|
||||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
|
||||||
}
|
|
||||||
return t;
|
|
||||||
} // get_rtctime()
|
|
||||||
|
|
||||||
float get_rtctemp(void) {
|
|
||||||
// block i2c bus access
|
|
||||||
if (I2C_MUTEX_LOCK()) {
|
|
||||||
RtcTemperature temp = Rtc.GetTemperature();
|
|
||||||
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
|
||||||
return temp.AsFloatDegC();
|
|
||||||
} // while
|
|
||||||
return 0;
|
|
||||||
} // get_rtctemp()
|
|
||||||
|
|
||||||
#endif // HAS_RTC
|
|
||||||
|
|
||||||
// helper function to setup a pulse for time synchronisation
|
// helper function to setup a pulse for time synchronisation
|
||||||
int timepulse_init(uint32_t pulse_period_ms) {
|
int timepulse_init(uint32_t pulse_period_ms) {
|
||||||
@ -170,29 +73,139 @@ pulse_period_error:
|
|||||||
return 0; // failure
|
return 0; // failure
|
||||||
}
|
}
|
||||||
|
|
||||||
void timepulse_start() {
|
void timepulse_start(void) {
|
||||||
#ifdef GPS_INT // start external clock
|
#ifdef GPS_INT // start external clock gps pps line
|
||||||
attachInterrupt(digitalPinToInterrupt(GPS_INT), CLOCKIRQ, RISING);
|
attachInterrupt(digitalPinToInterrupt(GPS_INT), CLOCKIRQ, RISING);
|
||||||
#elif defined RTC_INT // start external clock
|
#elif defined RTC_INT // start external clock rtc
|
||||||
attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
|
attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
|
||||||
#else // start internal clock
|
#else // start internal clock esp32 hardware timer
|
||||||
timerAlarmEnable(clockCycle);
|
timerAlarmEnable(clockCycle);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function to sync time_t of top of next second
|
// helper function to sync time_t of top of next second
|
||||||
time_t sync_clock(time_t t) {
|
void sync_clock(void) {
|
||||||
|
// do we have a second time pulse? Then wait for next pulse
|
||||||
|
#if defined(RTC_INT) || defined(GPS_INT)
|
||||||
|
// sync on top of next second by timepulse
|
||||||
|
if (xSemaphoreTake(TimePulse, pdMS_TO_TICKS(1000)) == pdTRUE) {
|
||||||
|
ESP_LOGI(TAG, "clock synced by timepulse");
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
ESP_LOGW(TAG, "Missing timepulse, thus clock can't be synced by second");
|
||||||
|
#endif
|
||||||
|
// no external timepulse, thus we must use less precise internal system clock
|
||||||
while (millis() % 1000)
|
while (millis() % 1000)
|
||||||
; // wait for milli seconds to be zero before setting new time
|
; // wait for milli seconds to be zero before setting new time
|
||||||
return (now());
|
ESP_LOGI(TAG, "clock synced by systime");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// interrupt service routine triggered by either rtc pps or esp32 hardware
|
// interrupt service routine triggered by either rtc pps or esp32 hardware
|
||||||
// timer
|
// timer
|
||||||
void IRAM_ATTR CLOCKIRQ() {
|
void IRAM_ATTR CLOCKIRQ() {
|
||||||
xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL);
|
xTaskNotifyFromISR(ClockTask, xTaskGetTickCountFromISR(), eSetBits, NULL);
|
||||||
#ifdef GPS_INT
|
#if defined(GPS_INT) || defined(RTC_INT)
|
||||||
xSemaphoreGiveFromISR(TimePulse, NULL);
|
xSemaphoreGiveFromISR(TimePulse, pdFALSE);
|
||||||
|
TimePulseTick = !TimePulseTick; // flip ticker
|
||||||
#endif
|
#endif
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAS_RTC // we have hardware RTC
|
||||||
|
|
||||||
|
RtcDS3231<TwoWire> Rtc(Wire); // RTC hardware i2c interface
|
||||||
|
|
||||||
|
// initialize RTC
|
||||||
|
int rtc_init(void) {
|
||||||
|
|
||||||
|
// return = 0 -> error / return = 1 -> success
|
||||||
|
|
||||||
|
// block i2c bus access
|
||||||
|
if (I2C_MUTEX_LOCK()) {
|
||||||
|
|
||||||
|
Wire.begin(HAS_RTC);
|
||||||
|
Rtc.Begin();
|
||||||
|
|
||||||
|
RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
|
||||||
|
|
||||||
|
if (!Rtc.IsDateTimeValid()) {
|
||||||
|
ESP_LOGW(TAG,
|
||||||
|
"RTC has no valid RTC date/time, setting to compilation date");
|
||||||
|
Rtc.SetDateTime(compiled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Rtc.GetIsRunning()) {
|
||||||
|
ESP_LOGI(TAG, "RTC not running, starting now");
|
||||||
|
Rtc.SetIsRunning(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcDateTime now = Rtc.GetDateTime();
|
||||||
|
|
||||||
|
if (now < compiled) {
|
||||||
|
ESP_LOGI(TAG, "RTC date/time is older than compilation date, updating");
|
||||||
|
Rtc.SetDateTime(compiled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure RTC chip
|
||||||
|
Rtc.Enable32kHzPin(false);
|
||||||
|
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "I2c bus busy - RTC initialization error");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||||
|
ESP_LOGI(TAG, "RTC initialized");
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} // rtc_init()
|
||||||
|
|
||||||
|
int set_rtctime(time_t t) { // t is seconds epoch time starting 1.1.1970
|
||||||
|
if (I2C_MUTEX_LOCK()) {
|
||||||
|
sync_clock(); // wait for top of second
|
||||||
|
Rtc.SetDateTime(RtcDateTime(t));
|
||||||
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||||
|
ESP_LOGI(TAG, "RTC calibrated");
|
||||||
|
return 1; // success
|
||||||
|
}
|
||||||
|
return 0; // failure
|
||||||
|
} // set_rtctime()
|
||||||
|
|
||||||
|
int set_rtctime(uint32_t t) { // t is epoch seconds starting 1.1.1970
|
||||||
|
return set_rtctime(static_cast<time_t>(t));
|
||||||
|
// set_rtctime()
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t get_rtctime(void) {
|
||||||
|
// never call now() in this function, this would cause a recursion!
|
||||||
|
time_t t = 0;
|
||||||
|
// block i2c bus access
|
||||||
|
if (I2C_MUTEX_LOCK()) {
|
||||||
|
if (Rtc.IsDateTimeValid()) {
|
||||||
|
RtcDateTime tt = Rtc.GetDateTime();
|
||||||
|
t = tt.Epoch32Time();
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "RTC has no confident time");
|
||||||
|
}
|
||||||
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
} // get_rtctime()
|
||||||
|
|
||||||
|
float get_rtctemp(void) {
|
||||||
|
// block i2c bus access
|
||||||
|
if (I2C_MUTEX_LOCK()) {
|
||||||
|
RtcTemperature temp = Rtc.GetTemperature();
|
||||||
|
I2C_MUTEX_UNLOCK(); // release i2c bus access
|
||||||
|
return temp.AsFloatDegC();
|
||||||
|
} // while
|
||||||
|
return 0;
|
||||||
|
} // get_rtctemp()
|
||||||
|
|
||||||
|
#endif // HAS_RTC
|
Loading…
Reference in New Issue
Block a user