getting time from GPS reworked
This commit is contained in:
parent
817f7793c4
commit
a71a7e08a4
@ -5,17 +5,10 @@
|
|||||||
#include <RtcDateTime.h>
|
#include <RtcDateTime.h>
|
||||||
#include "timekeeper.h"
|
#include "timekeeper.h"
|
||||||
|
|
||||||
#ifdef GPS_I2C // Needed for reading from I2C Bus
|
|
||||||
#include <Wire.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef GPS_BAUDRATE
|
#ifndef GPS_BAUDRATE
|
||||||
#define GPS_BAUDRATE 115200
|
#define GPS_BAUDRATE 115200UL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NMEA_FRAME_SIZE 82 // NEMA has a maxium of 82 bytes per record
|
|
||||||
#define NMEA_COMPENSATION_FACTOR 480 // empiric for Ublox Neo 6M
|
|
||||||
|
|
||||||
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
extern TinyGPSPlus gps; // Make TinyGPS++ instance globally availabe
|
||||||
extern TaskHandle_t GpsTask;
|
extern TaskHandle_t GpsTask;
|
||||||
|
|
||||||
|
@ -21,13 +21,13 @@ extern Ticker timesyncer;
|
|||||||
extern timesource_t timeSource;
|
extern timesource_t timeSource;
|
||||||
extern TaskHandle_t ClockTask;
|
extern TaskHandle_t ClockTask;
|
||||||
extern DRAM_ATTR bool TimePulseTick; // 1sec pps flag set by GPS or RTC
|
extern DRAM_ATTR bool TimePulseTick; // 1sec pps flag set by GPS or RTC
|
||||||
|
extern DRAM_ATTR unsigned long lastPPS;
|
||||||
extern hw_timer_t *ppsIRQ;
|
extern hw_timer_t *ppsIRQ;
|
||||||
extern portMUX_TYPE mux;
|
|
||||||
|
|
||||||
void IRAM_ATTR CLOCKIRQ(void);
|
void IRAM_ATTR CLOCKIRQ(void);
|
||||||
|
void IRAM_ATTR GPSIRQ(void);
|
||||||
void clock_init(void);
|
void clock_init(void);
|
||||||
void clock_loop(void *pvParameters);
|
void clock_loop(void *pvParameters);
|
||||||
void timepulse_start(void);
|
|
||||||
void setTimeSyncIRQ(void);
|
void setTimeSyncIRQ(void);
|
||||||
uint8_t timepulse_init(void);
|
uint8_t timepulse_init(void);
|
||||||
bool timeIsValid(time_t const t);
|
bool timeIsValid(time_t const t);
|
||||||
@ -38,5 +38,4 @@ time_t compileTime(void);
|
|||||||
time_t mkgmtime(const struct tm *ptm);
|
time_t mkgmtime(const struct tm *ptm);
|
||||||
TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config,
|
TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config,
|
||||||
int8_t rxPin, int8_t txPins);
|
int8_t rxPin, int8_t txPins);
|
||||||
|
|
||||||
#endif // _timekeeper_H
|
#endif // _timekeeper_H
|
@ -317,9 +317,6 @@ void dp_drawPage(bool nextpage) {
|
|||||||
|
|
||||||
#if (TIME_SYNC_INTERVAL)
|
#if (TIME_SYNC_INTERVAL)
|
||||||
timeState = TimePulseTick ? ' ' : timeSetSymbols[timeSource];
|
timeState = TimePulseTick ? ' ' : timeSetSymbols[timeSource];
|
||||||
portENTER_CRITICAL(&mux);
|
|
||||||
TimePulseTick = false; // flip global variable pulse ticker
|
|
||||||
portEXIT_CRITICAL(&mux);
|
|
||||||
time(&now);
|
time(&now);
|
||||||
localtime_r(&now, &timeinfo);
|
localtime_r(&now, &timeinfo);
|
||||||
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
|
||||||
|
200
src/gpsread.cpp
200
src/gpsread.cpp
@ -6,38 +6,12 @@
|
|||||||
// Local logging tag
|
// Local logging tag
|
||||||
static const char TAG[] = __FILE__;
|
static const char TAG[] = __FILE__;
|
||||||
|
|
||||||
// we use NMEA ZDA sentence field 1 for time synchronization
|
|
||||||
// ZDA gives time for preceding pps pulse
|
|
||||||
// downsight is that it does not have a constant offset
|
|
||||||
// thus precision is only +/- 1 second
|
|
||||||
|
|
||||||
TinyGPSPlus gps;
|
TinyGPSPlus gps;
|
||||||
TinyGPSCustom gpstime(gps, "GPZDA", 1); // field 1 = UTC time (hhmmss.ss)
|
|
||||||
TinyGPSCustom gpsday(gps, "GPZDA", 2); // field 2 = day (01..31)
|
|
||||||
TinyGPSCustom gpsmonth(gps, "GPZDA", 3); // field 3 = month (01..12)
|
|
||||||
TinyGPSCustom gpsyear(gps, "GPZDA", 4); // field 4 = year (4-digit)
|
|
||||||
static const String ZDA_Request = "$EIGPQ,ZDA*39\r\n";
|
|
||||||
TaskHandle_t GpsTask;
|
TaskHandle_t GpsTask;
|
||||||
|
|
||||||
HardwareSerial GPS_Serial(1); // use UART #1
|
HardwareSerial GPS_Serial(1); // use UART #1
|
||||||
static uint16_t nmea_txDelay_ms =
|
|
||||||
(tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL) / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
// helper functions to send UBX commands to ublox gps chip
|
// helper functions to send UBX commands to ublox gps chip
|
||||||
|
|
||||||
/*
|
|
||||||
// Print the UBX packet for debugging
|
|
||||||
void printPacket(byte *packet, byte len) {
|
|
||||||
char temp[3];
|
|
||||||
|
|
||||||
for (byte i = 0; i < len; i++) {
|
|
||||||
sprintf(temp, "%.2X", packet[i]);
|
|
||||||
ESP_LOGD(TAG, "%s", temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Send the packet specified to the receiver.
|
|
||||||
void sendPacket(byte *packet, byte len) {
|
void sendPacket(byte *packet, byte len) {
|
||||||
|
|
||||||
uint8_t CK_A = 0;
|
uint8_t CK_A = 0;
|
||||||
@ -55,55 +29,85 @@ void sendPacket(byte *packet, byte len) {
|
|||||||
GPS_Serial.write(CK_B);
|
GPS_Serial.write(CK_B);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a packet to the receiver to restore default configuration.
|
|
||||||
void restoreDefaults() {
|
void restoreDefaults() {
|
||||||
// CFG-CFG packet.
|
// UBX CFG-CFG packet
|
||||||
byte packet[] = {
|
byte packet[] = {
|
||||||
0xB5, // sync char 1
|
0xB5, // sync char 1
|
||||||
0x62, // sync char 2
|
0x62, // sync char 2
|
||||||
0x06, // class
|
0x06, // class
|
||||||
0x09, // id
|
0x09, // id
|
||||||
0x0D, // length
|
0x0D, // length
|
||||||
0x00, // length
|
0x00, // .
|
||||||
0b00011111, // clearmask
|
0b00011111, // clearmask
|
||||||
0b00000110, // clearmask
|
0b00000110, // .
|
||||||
0x00, // clearmask
|
0x00, // .
|
||||||
0x00, // clearmask
|
0x00, // .
|
||||||
0x00, // savemask
|
|
||||||
0x00, // savemask
|
|
||||||
0x00, // savemask
|
|
||||||
0x00, // savemask
|
0x00, // savemask
|
||||||
|
0x00, // .
|
||||||
|
0x00, // .
|
||||||
|
0x00, // .
|
||||||
0b00011111, // loadmask
|
0b00011111, // loadmask
|
||||||
0b00000110, // loadmask
|
0b00000110, // .
|
||||||
0x00, // loadmask
|
0x00, // .
|
||||||
0x00, // loadmask
|
0x00, // .
|
||||||
0b00010001 // devicemask
|
0b00010001 // devicemask
|
||||||
};
|
};
|
||||||
|
|
||||||
sendPacket(packet, sizeof(packet));
|
sendPacket(packet, sizeof(packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a set of packets to the receiver to disable NMEA messages.
|
void setTimePulse() {
|
||||||
|
// UBX TIM-TP packet
|
||||||
|
byte packet[] = {
|
||||||
|
0xB5, // sync char 1
|
||||||
|
0x62, // sync char 2
|
||||||
|
0x06, // class
|
||||||
|
0x07, // id
|
||||||
|
0x14, // length
|
||||||
|
0x40, // time interval for time pulse [us]
|
||||||
|
0x42, // -> 1 sec = 1000000us
|
||||||
|
0x0F, // .
|
||||||
|
0x00, // .
|
||||||
|
0xE8, // length of time pulse [us]
|
||||||
|
0x03, // -> 1000us
|
||||||
|
0x00, // .
|
||||||
|
0x00, // .
|
||||||
|
0x01, // status -> positive edge
|
||||||
|
0x00, // timeRef -> UTC
|
||||||
|
0b00000001, // syncMode asynchronized
|
||||||
|
0x00, // reserved
|
||||||
|
0x00, // antenna cable delay [ns]
|
||||||
|
0x00, // .
|
||||||
|
0x00, // receiver rf group delay [ns]
|
||||||
|
0x00, // .
|
||||||
|
0x00, // user time function delay [ns]
|
||||||
|
0x00, // .
|
||||||
|
0x00, // .
|
||||||
|
0x00 // .
|
||||||
|
};
|
||||||
|
|
||||||
|
sendPacket(packet, sizeof(packet));
|
||||||
|
}
|
||||||
|
|
||||||
void disableNmea() {
|
void disableNmea() {
|
||||||
|
|
||||||
// for tinygps++ we need only $GPGGA and $GPRMC
|
// for tinygps++ we need only $GPGGA and $GPRMC
|
||||||
// for getting time we use $GPZDA
|
// thus, we disable all other NMEA messages
|
||||||
// we disable all other NMEA messages
|
|
||||||
|
|
||||||
// Array of two bytes for CFG-MSG packets payload.
|
// Array of two bytes for CFG-MSG packets payload.
|
||||||
byte messages[][2] = {{0xF0, 0x01}, {0xF0, 0x02}, {0xF0, 0x03}, {0xF0, 0x05},
|
byte messages[][2] = {{0xF0, 0x01}, {0xF0, 0x02}, {0xF0, 0x03}, {0xF0, 0x05},
|
||||||
{0xF0, 0x06}, {0xF0, 0x07}, {0xF0, 0x09}, {0xF0, 0x0A},
|
{0xF0, 0x06}, {0xF0, 0x07}, {0xF0, 0x08}, {0xF0, 0x09},
|
||||||
{0xF0, 0x0E}, {0xF1, 0x00}, {0xF1, 0x03}, {0xF1, 0x04},
|
{0xF0, 0x0A}, {0xF0, 0x0E}, {0xF1, 0x00}, {0xF1, 0x03},
|
||||||
{0xF1, 0x05}, {0xF1, 0x06}};
|
{0xF1, 0x04}, {0xF1, 0x05}, {0xF1, 0x06}};
|
||||||
|
|
||||||
// CFG-MSG packet buffer.
|
// UBX CFG-MSG packet
|
||||||
byte packet[] = {
|
byte packet[] = {
|
||||||
0xB5, // sync char 1
|
0xB5, // sync char 1
|
||||||
0x62, // sync char 2
|
0x62, // sync char 2
|
||||||
0x06, // class
|
0x06, // class
|
||||||
0x01, // id
|
0x01, // id
|
||||||
0x03, // length
|
0x03, // length
|
||||||
0x00, // length
|
0x00, // .
|
||||||
0x00, // payload (first byte from messages array element)
|
0x00, // payload (first byte from messages array element)
|
||||||
0x00, // payload (second byte from messages array element)
|
0x00, // payload (second byte from messages array element)
|
||||||
0x00 // payload (zero to disable message)
|
0x00 // payload (zero to disable message)
|
||||||
@ -124,25 +128,24 @@ void disableNmea() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a packet to the receiver to change baudrate to 115200.
|
|
||||||
void changeBaudrate(uint32_t baudRate) {
|
void changeBaudrate(uint32_t baudRate) {
|
||||||
// CFG-PRT packet.
|
// UBX CFG-PRT packet
|
||||||
byte packet[] = {
|
byte packet[] = {
|
||||||
0xB5, // sync char 1
|
0xB5, // sync char 1
|
||||||
0x62, // sync char 2
|
0x62, // sync char 2
|
||||||
0x06, // class
|
0x06, // class
|
||||||
0x00, // id
|
0x00, // id
|
||||||
0x14, // length
|
0x14, // length
|
||||||
0x00, // length
|
0x00, // .
|
||||||
0x01, // portID (UART 1)
|
0x01, // portID (UART 1)
|
||||||
0x00, // reserved
|
0x00, // reserved
|
||||||
0x00, // txReady
|
0x00, // txReady
|
||||||
0x00, // .
|
0x00, // .
|
||||||
0b11010000, // UART mode: 8bit
|
0b11010000, // UART mode: 8N1
|
||||||
0b00001000, // UART mode: No Parity, 1 Stopbit
|
0b00001000, // .
|
||||||
0x00, // .
|
0x00, // .
|
||||||
0x00, // .
|
0x00, // .
|
||||||
(byte)baudRate, // baudrate (4 bytes)
|
(byte)baudRate, // baudrate
|
||||||
(byte)(baudRate >> 8), // .
|
(byte)(baudRate >> 8), // .
|
||||||
(byte)(baudRate >> 16), // .
|
(byte)(baudRate >> 16), // .
|
||||||
(byte)(baudRate >> 24), // .
|
(byte)(baudRate >> 24), // .
|
||||||
@ -151,30 +154,9 @@ void changeBaudrate(uint32_t baudRate) {
|
|||||||
0b00000010, // output protocols: NMEA
|
0b00000010, // output protocols: NMEA
|
||||||
0x00000000, // .
|
0x00000000, // .
|
||||||
0x00, // reserved
|
0x00, // reserved
|
||||||
0x00, // reserved
|
0x00, // .
|
||||||
0x00, // reserved
|
0x00, // .
|
||||||
0x00 // reserved
|
0x00 // .
|
||||||
};
|
|
||||||
|
|
||||||
sendPacket(packet, sizeof(packet));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a packet to the receiver to change frequency to 100 ms.
|
|
||||||
void changeFrequency() {
|
|
||||||
// CFG-RATE packet.
|
|
||||||
byte packet[] = {
|
|
||||||
0xB5, // sync char 1
|
|
||||||
0x62, // sync char 2
|
|
||||||
0x06, // class
|
|
||||||
0x08, // id
|
|
||||||
0x06, // length
|
|
||||||
0x00, // length
|
|
||||||
0x64, // Measurement rate 100ms
|
|
||||||
0x00, // Measurement rate
|
|
||||||
0x01, // Measurement cycles
|
|
||||||
0x00, // Measurement cycles
|
|
||||||
0x00, // Alignment to reference time: UTC time
|
|
||||||
0x00 // payload
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sendPacket(packet, sizeof(packet));
|
sendPacket(packet, sizeof(packet));
|
||||||
@ -184,8 +166,11 @@ void changeFrequency() {
|
|||||||
int gps_init(void) {
|
int gps_init(void) {
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Opening serial GPS");
|
ESP_LOGI(TAG, "Opening serial GPS");
|
||||||
|
|
||||||
GPS_Serial.begin(GPS_SERIAL);
|
GPS_Serial.begin(GPS_SERIAL);
|
||||||
|
|
||||||
restoreDefaults();
|
restoreDefaults();
|
||||||
|
delay(100);
|
||||||
|
|
||||||
changeBaudrate(GPS_BAUDRATE);
|
changeBaudrate(GPS_BAUDRATE);
|
||||||
delay(100);
|
delay(100);
|
||||||
@ -193,8 +178,7 @@ int gps_init(void) {
|
|||||||
GPS_Serial.updateBaudRate(GPS_BAUDRATE);
|
GPS_Serial.updateBaudRate(GPS_BAUDRATE);
|
||||||
|
|
||||||
disableNmea();
|
disableNmea();
|
||||||
changeFrequency();
|
setTimePulse();
|
||||||
// enableNavTimeUTC();
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@ -224,40 +208,38 @@ bool gps_hasfix() {
|
|||||||
// function to poll UTC time from GPS NMEA data; note: this is costly
|
// function to poll UTC time from GPS NMEA data; note: this is costly
|
||||||
time_t get_gpstime(uint16_t *msec) {
|
time_t get_gpstime(uint16_t *msec) {
|
||||||
|
|
||||||
// poll NMEA ZDA sentence
|
*msec = 0;
|
||||||
GPS_Serial.print(ZDA_Request);
|
|
||||||
// wait for gps NMEA answer
|
|
||||||
// vTaskDelay(tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL));
|
|
||||||
|
|
||||||
// did we get a current date & time?
|
// did we get a current date & time?
|
||||||
if (gpstime.isValid()) {
|
if (gps.time.isValid() && gps.date.isValid() && gps.time.age() < 1000) {
|
||||||
|
|
||||||
uint32_t delay_ms =
|
// convert tinygps time format to struct tm format
|
||||||
gpstime.age() + nmea_txDelay_ms + NMEA_COMPENSATION_FACTOR;
|
|
||||||
uint32_t zdatime = atof(gpstime.value());
|
|
||||||
|
|
||||||
// convert UTC time from gps NMEA ZDA sentence to tm format
|
|
||||||
struct tm gps_tm = {0};
|
struct tm gps_tm = {0};
|
||||||
gps_tm.tm_sec = zdatime % 100; // second (UTC)
|
gps_tm.tm_sec = gps.time.second();
|
||||||
gps_tm.tm_min = (zdatime / 100) % 100; // minute (UTC)
|
gps_tm.tm_min = gps.time.minute();
|
||||||
gps_tm.tm_hour = zdatime / 10000; // hour (UTC)
|
gps_tm.tm_hour = gps.time.hour();
|
||||||
gps_tm.tm_mday = atoi(gpsday.value()); // day, 01 to 31
|
gps_tm.tm_mday = gps.date.day();
|
||||||
gps_tm.tm_mon = atoi(gpsmonth.value()) - 1; // month, 01 to 12
|
gps_tm.tm_mon = gps.date.month() - 1; // 1-12 -> 0-11
|
||||||
gps_tm.tm_year = atoi(gpsyear.value()) - 1900; // year, YYYY
|
gps_tm.tm_year = gps.date.year() - 1900; // 2000+ -> years since 1900
|
||||||
|
|
||||||
// convert UTC tm to time_t epoch
|
// convert UTC tm to time_t epoch
|
||||||
gps_tm.tm_isdst = 0; // UTC has no DST
|
gps_tm.tm_isdst = 0; // UTC has no DST
|
||||||
time_t t = mkgmtime(&gps_tm);
|
time_t t = mkgmtime(&gps_tm);
|
||||||
|
|
||||||
// add protocol delay with millisecond precision
|
#ifdef GPS_INT
|
||||||
t += (time_t)(delay_ms / 1000);
|
// if we have a recent GPS PPS pulse, sync on top of next second
|
||||||
*msec = delay_ms % 1000; // fractional seconds
|
if (millis() - lastPPS < 1000)
|
||||||
|
*msec = (uint16_t)(millis() - lastPPS);
|
||||||
|
else {
|
||||||
|
ESP_LOGD(TAG, "no PPS from GPS");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "no valid GPS time");
|
ESP_LOGD(TAG, "no valid GPS time");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} // get_gpstime()
|
} // get_gpstime()
|
||||||
@ -271,20 +253,24 @@ void gps_loop(void *pvParameters) {
|
|||||||
|
|
||||||
while (cfg.payloadmask & GPS_DATA) {
|
while (cfg.payloadmask & GPS_DATA) {
|
||||||
// feed GPS decoder with serial NMEA data from GPS device
|
// feed GPS decoder with serial NMEA data from GPS device
|
||||||
while (GPS_Serial.available())
|
while (GPS_Serial.available()) {
|
||||||
if (gps.encode(GPS_Serial.read()))
|
if (gps.encode(GPS_Serial.read())) {
|
||||||
break; // leave encode loop after each NMEA complete sentence
|
|
||||||
|
|
||||||
// show NMEA data, very noisy, useful only for debugging GPS
|
// show NMEA data, very noisy, for debugging GPS
|
||||||
// ESP_LOGV(TAG, "GPS NMEA data: passed %u / failed: %u / with fix:
|
// ESP_LOGV(
|
||||||
// %u", gps.passedChecksum(), gps.failedChecksum(), gps
|
// TAG,
|
||||||
// .sentencesWithFix());
|
// "GPS NMEA data: chars %u / passed %u / failed: %u / with fix:
|
||||||
|
// %u", gps.charsProcessed(), gps.passedChecksum(),
|
||||||
|
// gps.failedChecksum(), gps.sentencesWithFix());
|
||||||
|
|
||||||
|
delay(5); // yield after each sentence to crack NMEA burst
|
||||||
|
}
|
||||||
|
} // read from serial buffer loop
|
||||||
delay(5);
|
delay(5);
|
||||||
} // inner while loop
|
}
|
||||||
|
|
||||||
delay(1000);
|
delay(1000);
|
||||||
} // outer while loop
|
} // infinite while loop
|
||||||
|
|
||||||
} // gps_loop()
|
} // gps_loop()
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ triggers pps 1 sec impulse
|
|||||||
|
|
||||||
ISRs fired by CPU or GPIO:
|
ISRs fired by CPU or GPIO:
|
||||||
DisplayIRQ <- esp32 timer 0
|
DisplayIRQ <- esp32 timer 0
|
||||||
CLOCKIRQ <- esp32 timer 1 or GPIO (RTC_INT or GPS_INT)
|
CLOCKIRQ <- esp32 timer 1 or GPIO (RTC_INT)
|
||||||
MatrixDisplayIRQ<- esp32 timer 3
|
MatrixDisplayIRQ<- esp32 timer 3
|
||||||
ButtonIRQ <- GPIO <- Button
|
ButtonIRQ <- GPIO <- Button
|
||||||
PMUIRQ <- GPIO <- PMU chip
|
PMUIRQ <- GPIO <- PMU chip
|
||||||
@ -492,8 +492,7 @@ void setup() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Starting Timekeeper...");
|
ESP_LOGI(TAG, "Starting Timekeeper...");
|
||||||
_ASSERT(timepulse_init()); // setup pps timepulse
|
_ASSERT(timepulse_init()); // starts pps and cyclic time sync
|
||||||
timepulse_start(); // starts pps and cyclic time sync
|
|
||||||
strcat_P(features, " TIME");
|
strcat_P(features, " TIME");
|
||||||
|
|
||||||
#endif // timesync
|
#endif // timesync
|
||||||
|
@ -19,9 +19,8 @@ static const char TAG[] = __FILE__;
|
|||||||
// G = GPS / R = RTC / L = LORA / * = no sync / ? = never synced
|
// G = GPS / R = RTC / L = LORA / * = no sync / ? = never synced
|
||||||
const char timeSetSymbols[] = {'G', 'R', 'L', '*', '?'};
|
const char timeSetSymbols[] = {'G', 'R', 'L', '*', '?'};
|
||||||
|
|
||||||
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
|
|
||||||
|
|
||||||
DRAM_ATTR bool TimePulseTick = false;
|
DRAM_ATTR bool TimePulseTick = false;
|
||||||
|
DRAM_ATTR unsigned long lastPPS = millis();
|
||||||
timesource_t timeSource = _unsynced;
|
timesource_t timeSource = _unsynced;
|
||||||
TaskHandle_t ClockTask = NULL;
|
TaskHandle_t ClockTask = NULL;
|
||||||
hw_timer_t *ppsIRQ = NULL;
|
hw_timer_t *ppsIRQ = NULL;
|
||||||
@ -144,26 +143,23 @@ uint8_t timepulse_init() {
|
|||||||
// sntp_init();
|
// sntp_init();
|
||||||
sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED);
|
sntp_set_sync_mode(SNTP_SYNC_MODE_IMMED);
|
||||||
|
|
||||||
// use time pulse from GPS as time base with fixed 1Hz frequency
|
// if we have, use PPS time pulse from GPS for syncing time on top of second
|
||||||
#ifdef GPS_INT
|
#ifdef GPS_INT
|
||||||
|
// setup external interupt pin for rising edge of GPS PPS
|
||||||
// setup external interupt pin for rising edge GPS INT
|
|
||||||
pinMode(GPS_INT, INPUT_PULLDOWN);
|
pinMode(GPS_INT, INPUT_PULLDOWN);
|
||||||
// setup external rtc 1Hz clock as pulse per second clock
|
attachInterrupt(digitalPinToInterrupt(GPS_INT), GPSIRQ, RISING);
|
||||||
ESP_LOGI(TAG, "Timepulse: external (GPS)");
|
#endif
|
||||||
return 1; // success
|
|
||||||
|
|
||||||
// use pulse from on board RTC chip as time base with fixed frequency
|
// if we have, use pulse from on board RTC chip as time base for calendar time
|
||||||
#elif defined RTC_INT
|
#if defined RTC_INT
|
||||||
|
|
||||||
// setup external interupt pin for falling edge RTC INT
|
// setup external rtc 1Hz clock pulse
|
||||||
pinMode(RTC_INT, INPUT_PULLUP);
|
|
||||||
|
|
||||||
// setup external rtc 1Hz clock as pulse per second clock
|
|
||||||
if (I2C_MUTEX_LOCK()) {
|
if (I2C_MUTEX_LOCK()) {
|
||||||
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
|
Rtc.SetSquareWavePinClockFrequency(DS3231SquareWaveClock_1Hz);
|
||||||
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
|
Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeClock);
|
||||||
I2C_MUTEX_UNLOCK();
|
I2C_MUTEX_UNLOCK();
|
||||||
|
pinMode(RTC_INT, INPUT_PULLUP);
|
||||||
|
attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
|
||||||
ESP_LOGI(TAG, "Timepulse: external (RTC)");
|
ESP_LOGI(TAG, "Timepulse: external (RTC)");
|
||||||
return 1; // success
|
return 1; // success
|
||||||
} else {
|
} else {
|
||||||
@ -173,33 +169,39 @@ uint8_t timepulse_init() {
|
|||||||
return 1; // success
|
return 1; // success
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// use ESP32 hardware timer as time base with adjustable frequency
|
// use ESP32 hardware timer as time base for calendar time
|
||||||
ppsIRQ = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec
|
ppsIRQ = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec
|
||||||
timerAlarmWrite(ppsIRQ, 10000, true); // 1000ms
|
timerAlarmWrite(ppsIRQ, 10000, true); // 1000ms
|
||||||
|
timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true);
|
||||||
|
timerAlarmEnable(ppsIRQ);
|
||||||
ESP_LOGI(TAG, "Timepulse: internal (ESP32 hardware timer)");
|
ESP_LOGI(TAG, "Timepulse: internal (ESP32 hardware timer)");
|
||||||
return 1; // success
|
return 1; // success
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
} // timepulse_init
|
|
||||||
|
|
||||||
void timepulse_start(void) {
|
// start cyclic time sync
|
||||||
#ifdef GPS_INT // start external clock gps pps line
|
timesyncer.attach(TIME_SYNC_INTERVAL * 60, setTimeSyncIRQ);
|
||||||
attachInterrupt(digitalPinToInterrupt(GPS_INT), CLOCKIRQ, RISING);
|
|
||||||
#elif defined RTC_INT // start external clock rtc
|
|
||||||
attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
|
|
||||||
#else // start internal clock esp32 hardware timer
|
|
||||||
timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true);
|
|
||||||
timerAlarmEnable(ppsIRQ);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// get time if we don't have one
|
// get time if we don't have one
|
||||||
if (timeSource != _set)
|
if (timeSource != _set)
|
||||||
setTimeSyncIRQ(); // init systime by RTC or GPS or LORA
|
setTimeSyncIRQ(); // init systime by RTC or GPS or LORA
|
||||||
// start cyclic time sync
|
|
||||||
timesyncer.attach(TIME_SYNC_INTERVAL * 60, setTimeSyncIRQ);
|
} // timepulse_init
|
||||||
|
|
||||||
|
// interrupt service routine triggered by GPS PPS
|
||||||
|
void IRAM_ATTR GPSIRQ(void) {
|
||||||
|
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
// take timestamp
|
||||||
|
lastPPS = millis(); // last time of pps
|
||||||
|
|
||||||
|
// yield only if we should
|
||||||
|
if (xHigherPriorityTaskWoken)
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
|
||||||
// interrupt service routine triggered by either pps or esp32 hardware timer
|
// interrupt service routine triggered by esp32 hardware timer
|
||||||
void IRAM_ATTR CLOCKIRQ(void) {
|
void IRAM_ATTR CLOCKIRQ(void) {
|
||||||
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
@ -212,11 +214,7 @@ void IRAM_ATTR CLOCKIRQ(void) {
|
|||||||
|
|
||||||
// flip time pulse ticker, if needed
|
// flip time pulse ticker, if needed
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
#if (defined GPS_INT || defined RTC_INT)
|
|
||||||
portENTER_CRITICAL(&mux);
|
|
||||||
TimePulseTick = !TimePulseTick; // flip global variable pulse ticker
|
TimePulseTick = !TimePulseTick; // flip global variable pulse ticker
|
||||||
portEXIT_CRITICAL(&mux);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// yield only if we should
|
// yield only if we should
|
||||||
|
Loading…
Reference in New Issue
Block a user