GPS IRQ added to increase gps time sync accuracy
This commit is contained in:
parent
4824e2c096
commit
359b31e9e9
@ -83,6 +83,7 @@ typedef struct {
|
|||||||
uint8_t satellites;
|
uint8_t satellites;
|
||||||
uint16_t hdop;
|
uint16_t hdop;
|
||||||
int16_t altitude;
|
int16_t altitude;
|
||||||
|
time_t utctime;
|
||||||
} gpsStatus_t;
|
} gpsStatus_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -111,12 +112,13 @@ extern uint16_t volatile macs_total, macs_wifi, macs_ble,
|
|||||||
batt_voltage; // display values
|
batt_voltage; // display values
|
||||||
extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC
|
extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC
|
||||||
extern timesource_t timeSource;
|
extern timesource_t timeSource;
|
||||||
extern hw_timer_t *displayIRQ, *ppsIRQ;
|
extern hw_timer_t *displayIRQ, *ppsIRQ, *gpsIRQ;
|
||||||
extern SemaphoreHandle_t I2Caccess;
|
extern SemaphoreHandle_t I2Caccess;
|
||||||
extern TaskHandle_t irqHandlerTask, ClockTask;
|
extern TaskHandle_t irqHandlerTask, ClockTask;
|
||||||
extern TimerHandle_t WifiChanTimer;
|
extern TimerHandle_t WifiChanTimer;
|
||||||
extern Timezone myTZ;
|
extern Timezone myTZ;
|
||||||
extern time_t userUTCTime;
|
extern time_t userUTCTime;
|
||||||
|
extern time_t volatile gps_pps_time;
|
||||||
|
|
||||||
// application includes
|
// application includes
|
||||||
#include "led.h"
|
#include "led.h"
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#define TIMESYNC_IRQ 0x10
|
#define TIMESYNC_IRQ 0x10
|
||||||
#define MASK_IRQ 0x20
|
#define MASK_IRQ 0x20
|
||||||
#define UNMASK_IRQ 0x40
|
#define UNMASK_IRQ 0x40
|
||||||
#define RESERVED_IRQ 0x80
|
#define GPS_IRQ 0x80
|
||||||
|
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "cyclic.h"
|
#include "cyclic.h"
|
||||||
@ -27,4 +27,8 @@ void IRAM_ATTR DisplayIRQ();
|
|||||||
void IRAM_ATTR ButtonIRQ();
|
void IRAM_ATTR ButtonIRQ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (HAS_GPS)
|
||||||
|
void IRAM_ATTR GpsIRQ();
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -11,9 +11,10 @@ TaskHandle_t GpsTask;
|
|||||||
|
|
||||||
#ifdef GPS_SERIAL
|
#ifdef GPS_SERIAL
|
||||||
HardwareSerial GPS_Serial(1); // use UART #1
|
HardwareSerial GPS_Serial(1); // use UART #1
|
||||||
static TickType_t gps_txDelay = tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL);
|
static uint16_t nmea_txDelay_ms =
|
||||||
|
tx_Ticks(NMEA_FRAME_SIZE, GPS_SERIAL) / portTICK_PERIOD_MS;
|
||||||
#else
|
#else
|
||||||
static TickType_t gps_txDelay = 0;
|
static uint16_t nmea_txDelay_ms = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// initialize and configure GPS
|
// initialize and configure GPS
|
||||||
@ -71,37 +72,24 @@ void gps_read() {
|
|||||||
gps_status.satellites = (uint8_t)gps.satellites.value();
|
gps_status.satellites = (uint8_t)gps.satellites.value();
|
||||||
gps_status.hdop = (uint16_t)gps.hdop.value();
|
gps_status.hdop = (uint16_t)gps.hdop.value();
|
||||||
gps_status.altitude = (int16_t)gps.altitude.meters();
|
gps_status.altitude = (int16_t)gps.altitude.meters();
|
||||||
|
gps_status.utctime = get_gpstime();
|
||||||
|
|
||||||
// show NMEA data in debug mode, useful for debugging GPS
|
// show NMEA data in debug mode, useful for debugging GPS
|
||||||
ESP_LOGD(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d",
|
ESP_LOGV(TAG, "GPS NMEA data: passed %d / failed: %d / with fix: %d",
|
||||||
gps.passedChecksum(), gps.failedChecksum(), gps.sentencesWithFix());
|
gps.passedChecksum(), gps.failedChecksum(), gps.sentencesWithFix());
|
||||||
}
|
}
|
||||||
|
|
||||||
// function to fetch current time from gps
|
// function to fetch current time from gps
|
||||||
time_t get_gpstime(void) {
|
time_t get_gpstime(void) {
|
||||||
|
|
||||||
// set time to wait for arrive next recent NMEA time record
|
|
||||||
static const uint32_t gpsDelay_ms = 1000 - gps_txDelay / portTICK_PERIOD_MS;
|
|
||||||
|
|
||||||
time_t t = 0;
|
time_t t = 0;
|
||||||
uint32_t time_age = gps.time.age();
|
uint32_t time_age = gps.time.age();
|
||||||
|
|
||||||
if ((time_age < gpsDelay_ms) && gps.time.isValid() && gps.date.isValid() &&
|
if (gps.time.isValid() && gps.date.isValid() && (time_age < 1000))
|
||||||
gps.time.isUpdated()) {
|
|
||||||
|
|
||||||
t = tmConvert(gps.date.year(), gps.date.month(), gps.date.day(),
|
t = tmConvert(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());
|
||||||
|
|
||||||
if (time_age < (gpsDelay_ms / 2))
|
return timeIsValid(time_age > nmea_txDelay_ms ? t : t - 1);
|
||||||
t--;
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "GPS time age: %dms", time_age);
|
|
||||||
|
|
||||||
#ifndef GPS_INT
|
|
||||||
// wait until top of second with millisecond precision
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000 - time_age) - gps_txDelay);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return timeIsValid(t);
|
|
||||||
} // get_gpstime()
|
} // get_gpstime()
|
||||||
|
|
||||||
// GPS serial feed FreeRTos Task
|
// GPS serial feed FreeRTos Task
|
||||||
|
@ -39,6 +39,12 @@ void irqHandler(void *pvParameters) {
|
|||||||
refreshtheDisplay();
|
refreshtheDisplay();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// gps refresh buffer?
|
||||||
|
#if (HAS_GPS)
|
||||||
|
if (InterruptStatus & GPS_IRQ)
|
||||||
|
gps_read();
|
||||||
|
#endif
|
||||||
|
|
||||||
// are cyclic tasks due?
|
// are cyclic tasks due?
|
||||||
if (InterruptStatus & CYCLIC_IRQ)
|
if (InterruptStatus & CYCLIC_IRQ)
|
||||||
doHousekeeping();
|
doHousekeeping();
|
||||||
@ -47,7 +53,6 @@ void irqHandler(void *pvParameters) {
|
|||||||
// is time to be synced?
|
// is time to be synced?
|
||||||
if (InterruptStatus & TIMESYNC_IRQ) {
|
if (InterruptStatus & TIMESYNC_IRQ) {
|
||||||
time_t t = timeProvider();
|
time_t t = timeProvider();
|
||||||
ESP_LOGD(TAG, "Sync time = %d", t);
|
|
||||||
if (timeIsValid(t))
|
if (timeIsValid(t))
|
||||||
setTime(t);
|
setTime(t);
|
||||||
}
|
}
|
||||||
@ -85,6 +90,17 @@ void IRAM_ATTR ButtonIRQ() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (HAS_GPS)
|
||||||
|
void IRAM_ATTR GpsIRQ() {
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
|
xTaskNotifyFromISR(irqHandlerTask, GPS_IRQ, eSetBits,
|
||||||
|
&xHigherPriorityTaskWoken);
|
||||||
|
if (xHigherPriorityTaskWoken)
|
||||||
|
portYIELD_FROM_ISR();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int mask_user_IRQ() {
|
int mask_user_IRQ() {
|
||||||
// begin of time critical section: lock I2C bus to ensure accurate timing
|
// begin of time critical section: lock I2C bus to ensure accurate timing
|
||||||
if (!I2C_MUTEX_LOCK())
|
if (!I2C_MUTEX_LOCK())
|
||||||
|
14
src/main.cpp
14
src/main.cpp
@ -51,7 +51,7 @@ So don't do it if you do not own a digital oscilloscope.
|
|||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS)
|
0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS)
|
||||||
1 ppsIRQ -> pps clock irq -> 1sec
|
1 ppsIRQ -> pps clock irq -> 1sec
|
||||||
2 unused
|
2 gpsIRQ -> gps store data -> 500ms
|
||||||
3 unused
|
3 unused
|
||||||
|
|
||||||
|
|
||||||
@ -61,6 +61,7 @@ So don't do it if you do not own a digital oscilloscope.
|
|||||||
fired by hardware
|
fired by hardware
|
||||||
DisplayIRQ -> esp32 timer 0 -> irqHandlerTask (Core 1)
|
DisplayIRQ -> esp32 timer 0 -> irqHandlerTask (Core 1)
|
||||||
CLOCKIRQ -> esp32 timer 1 -> ClockTask (Core 1)
|
CLOCKIRQ -> esp32 timer 1 -> ClockTask (Core 1)
|
||||||
|
GpsIRQ -> esp32 timer 2 -> irqHandlerTask (Core 1)
|
||||||
ButtonIRQ -> external gpio -> irqHandlerTask (Core 1)
|
ButtonIRQ -> external gpio -> irqHandlerTask (Core 1)
|
||||||
|
|
||||||
fired by software (Ticker.h)
|
fired by software (Ticker.h)
|
||||||
@ -84,11 +85,12 @@ 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
|
||||||
|
|
||||||
hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL;
|
hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL, *gpsIRQ = NULL;
|
||||||
|
|
||||||
TaskHandle_t irqHandlerTask = NULL, ClockTask = NULL;
|
TaskHandle_t irqHandlerTask = NULL, ClockTask = NULL;
|
||||||
SemaphoreHandle_t I2Caccess;
|
SemaphoreHandle_t I2Caccess;
|
||||||
bool volatile TimePulseTick = false;
|
bool volatile TimePulseTick = false;
|
||||||
|
time_t volatile gps_pps_time = 0;
|
||||||
time_t userUTCTime = 0;
|
time_t userUTCTime = 0;
|
||||||
timesource_t timeSource = _unsynced;
|
timesource_t timeSource = _unsynced;
|
||||||
|
|
||||||
@ -408,6 +410,14 @@ void setup() {
|
|||||||
timerAlarmEnable(displayIRQ);
|
timerAlarmEnable(displayIRQ);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// gps buffer read interrupt
|
||||||
|
#if (HAS_GPS)
|
||||||
|
gpsIRQ = timerBegin(2, 80, true);
|
||||||
|
timerAttachInterrupt(gpsIRQ, &GpsIRQ, true);
|
||||||
|
timerAlarmWrite(gpsIRQ, 500 * 1000, true);
|
||||||
|
timerAlarmEnable(gpsIRQ);
|
||||||
|
#endif
|
||||||
|
|
||||||
// cyclic function interrupts
|
// cyclic function interrupts
|
||||||
sendcycler.attach(SENDCYCLE * 2, sendcycle);
|
sendcycler.attach(SENDCYCLE * 2, sendcycle);
|
||||||
housekeeper.attach(HOMECYCLE, housekeeping);
|
housekeeper.attach(HOMECYCLE, housekeeping);
|
||||||
|
@ -253,7 +253,6 @@ void get_status(uint8_t val[]) {
|
|||||||
void get_gps(uint8_t val[]) {
|
void get_gps(uint8_t val[]) {
|
||||||
ESP_LOGI(TAG, "Remote command: get gps status");
|
ESP_LOGI(TAG, "Remote command: get gps status");
|
||||||
#if(HAS_GPS)
|
#if(HAS_GPS)
|
||||||
gps_read();
|
|
||||||
payload.reset();
|
payload.reset();
|
||||||
payload.addGPS(gps_status);
|
payload.addGPS(gps_status);
|
||||||
SendPayload(GPSPORT, prio_high);
|
SendPayload(GPSPORT, prio_high);
|
||||||
|
@ -87,7 +87,6 @@ void sendCounter() {
|
|||||||
case GPS_DATA:
|
case GPS_DATA:
|
||||||
// send GPS position only if we have a fix
|
// send GPS position only if we have a fix
|
||||||
if (gps.location.isValid()) {
|
if (gps.location.isValid()) {
|
||||||
gps_read();
|
|
||||||
payload.reset();
|
payload.reset();
|
||||||
payload.addGPS(gps_status);
|
payload.addGPS(gps_status);
|
||||||
SendPayload(GPSPORT, prio_high);
|
SendPayload(GPSPORT, prio_high);
|
||||||
|
@ -27,7 +27,7 @@ time_t timeProvider(void) {
|
|||||||
time_t t = 0;
|
time_t t = 0;
|
||||||
|
|
||||||
#if (HAS_GPS)
|
#if (HAS_GPS)
|
||||||
t = get_gpstime(); // fetch recent time from last NEMA record
|
t = gps_pps_time; // fetch recent time from last NEMA record
|
||||||
if (t) {
|
if (t) {
|
||||||
#ifdef HAS_RTC
|
#ifdef HAS_RTC
|
||||||
set_rtctime(t, do_mutex); // calibrate RTC
|
set_rtctime(t, do_mutex); // calibrate RTC
|
||||||
@ -106,6 +106,7 @@ uint8_t timepulse_init() {
|
|||||||
} // timepulse_init
|
} // timepulse_init
|
||||||
|
|
||||||
void timepulse_start(void) {
|
void timepulse_start(void) {
|
||||||
|
|
||||||
#ifdef GPS_INT // start external clock gps pps line
|
#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 rtc
|
#elif defined RTC_INT // start external clock rtc
|
||||||
@ -114,9 +115,14 @@ void timepulse_start(void) {
|
|||||||
timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true);
|
timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true);
|
||||||
timerAlarmEnable(ppsIRQ);
|
timerAlarmEnable(ppsIRQ);
|
||||||
#endif
|
#endif
|
||||||
now(); // refresh sysTime to pps
|
|
||||||
|
#if (HAS_GPS)
|
||||||
|
gps_read();
|
||||||
|
gps_pps_time = gps_status.utctime;
|
||||||
|
#endif
|
||||||
|
|
||||||
// start cyclic time sync
|
// start cyclic time sync
|
||||||
|
now(); // ensure sysTime is ßrecent
|
||||||
timeSync(); // init systime by RTC or GPS or LORA
|
timeSync(); // init systime by RTC or GPS or LORA
|
||||||
timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync);
|
timesyncer.attach(TIME_SYNC_INTERVAL * 60, timeSync);
|
||||||
}
|
}
|
||||||
@ -126,13 +132,20 @@ void IRAM_ATTR CLOCKIRQ(void) {
|
|||||||
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
SyncToPPS(); // calibrates UTC systime and advances it +1, see microTime.h
|
SyncToPPS(); // advance systime, see microTime.h
|
||||||
|
|
||||||
|
// store recent gps time, if we have
|
||||||
|
#if (HAS_GPS)
|
||||||
|
gps_pps_time = gps_status.utctime + 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// advance wall clock, if we have
|
||||||
#if (defined HAS_IF482 || defined HAS_DCF77)
|
#if (defined HAS_IF482 || defined HAS_DCF77)
|
||||||
xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits,
|
xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits,
|
||||||
&xHigherPriorityTaskWoken);
|
&xHigherPriorityTaskWoken);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// flip time pulse ticker, if needed
|
||||||
#ifdef HAS_DISPLAY
|
#ifdef HAS_DISPLAY
|
||||||
#if (defined GPS_INT || defined RTC_INT)
|
#if (defined GPS_INT || defined RTC_INT)
|
||||||
TimePulseTick = !TimePulseTick; // flip pulse ticker
|
TimePulseTick = !TimePulseTick; // flip pulse ticker
|
||||||
|
@ -216,8 +216,12 @@ int recv_timesync_ans(uint8_t seq_no, uint8_t buf[], uint8_t buf_len) {
|
|||||||
// adjust system time, calibrate RTC and RTC_INT pps
|
// adjust system time, calibrate RTC and RTC_INT pps
|
||||||
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec) {
|
void IRAM_ATTR setMyTime(uint32_t t_sec, uint16_t t_msec) {
|
||||||
|
|
||||||
// advance time 1 sec wait time
|
time_t time_to_set = (time_t)t_sec;
|
||||||
time_t time_to_set = (time_t)(t_sec + 1);
|
|
||||||
|
// advance time 1 sec wait time if we have no pulse clock
|
||||||
|
#if (!defined GPS_INT) && (!defined RTC_INT)
|
||||||
|
time_to_set++;
|
||||||
|
#endif
|
||||||
|
|
||||||
ESP_LOGD(TAG, "[%0.3f] Calculated UTC epoch time: %d.%03d sec",
|
ESP_LOGD(TAG, "[%0.3f] Calculated UTC epoch time: %d.%03d sec",
|
||||||
millis() / 1000.0, time_to_set, t_msec);
|
millis() / 1000.0, time_to_set, t_msec);
|
||||||
|
Loading…
Reference in New Issue
Block a user