interrupt timing issues (not fully solved yet)

This commit is contained in:
Verkehrsrot 2019-03-23 15:12:11 +01:00
parent 8de2ee0680
commit 54c6536349
7 changed files with 58 additions and 36 deletions

View File

@ -2,13 +2,9 @@
#define _IF482_H #define _IF482_H
#include "globals.h" #include "globals.h"
#include "timekeeper.h"
#define IF482_FRAME_SIZE (17) #define IF482_FRAME_SIZE (17)
extern HardwareSerial IF482;
void IF482_Pulse(time_t t);
String IRAM_ATTR IF482_Frame(time_t tt); String IRAM_ATTR IF482_Frame(time_t tt);
#endif #endif

View File

@ -6,9 +6,10 @@
#include "TimeLib.h" #include "TimeLib.h"
#include "irqhandler.h" #include "irqhandler.h"
#if(HAS_GPS) #ifdef HAS_GPS
#include "gpsread.h" #include "gpsread.h"
#endif #endif
#ifdef HAS_IF482 #ifdef HAS_IF482
#include "if482.h" #include "if482.h"
#elif defined HAS_DCF77 #elif defined HAS_DCF77

View File

@ -84,18 +84,6 @@ not evaluated by model BU-190, use "F" instead for this model
// Local logging tag // Local logging tag
static const char TAG[] = __FILE__; static const char TAG[] = __FILE__;
HardwareSerial IF482(2); // use UART #2 (note: #1 may be in use for serial GPS)
// triggered by timepulse to send IF482 signal
void IF482_Pulse(time_t t) {
static const TickType_t txDelay =
pdMS_TO_TICKS(1000) - tx_Ticks(IF482_FRAME_SIZE, HAS_IF482);
vTaskDelay(txDelay); // wait until moment to fire
IF482.print(IF482_Frame(t + 1)); // note: if482 telegram for *next* second
}
String IRAM_ATTR IF482_Frame(time_t printTime) { String IRAM_ATTR IF482_Frame(time_t printTime) {
time_t t = myTZ.toLocal(printTime); time_t t = myTZ.toLocal(printTime);

View File

@ -3,6 +3,8 @@
// Local logging tag // Local logging tag
static const char TAG[] = __FILE__; static const char TAG[] = __FILE__;
static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
// irq handler task, handles all our application level interrupts // irq handler task, handles all our application level interrupts
void irqHandler(void *pvParameters) { void irqHandler(void *pvParameters) {
@ -54,12 +56,13 @@ void irqHandler(void *pvParameters) {
#ifdef HAS_DISPLAY #ifdef HAS_DISPLAY
void IRAM_ATTR DisplayIRQ() { void IRAM_ATTR DisplayIRQ() {
portENTER_CRITICAL_ISR(&mux);
BaseType_t xHigherPriorityTaskWoken; BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE; xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits,
&xHigherPriorityTaskWoken); &xHigherPriorityTaskWoken);
portEXIT_CRITICAL_ISR(&mux);
if (xHigherPriorityTaskWoken) if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
} }
@ -67,11 +70,13 @@ void IRAM_ATTR DisplayIRQ() {
#ifdef HAS_BUTTON #ifdef HAS_BUTTON
void IRAM_ATTR ButtonIRQ() { void IRAM_ATTR ButtonIRQ() {
portENTER_CRITICAL_ISR(&mux);
BaseType_t xHigherPriorityTaskWoken; BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE; xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits, xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits,
&xHigherPriorityTaskWoken); &xHigherPriorityTaskWoken);
portEXIT_CRITICAL_ISR(&mux);
if (xHigherPriorityTaskWoken) if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();

View File

@ -36,7 +36,7 @@ looptask 1 1 arduino core -> runs the LMIC LoRa stack
irqhandler 1 1 executes tasks triggered by timer irq irqhandler 1 1 executes tasks triggered by timer irq
gpsloop 1 2 reads data from GPS via serial or i2c gpsloop 1 2 reads data from GPS via serial or i2c
bmeloop 1 1 reads data from BME sensor via i2c bmeloop 1 1 reads data from BME sensor via i2c
timesync_req 1 4 temporary task for processing time sync requests timesync_req 1 2 temporary task for processing time sync requests
IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator
Low priority numbers denote low priority tasks. Low priority numbers denote low priority tasks.

View File

@ -14,8 +14,14 @@ static const char TAG[] = __FILE__;
// symbol to display current time source // symbol to display current time source
const char timeSetSymbols[] = {'G', 'R', 'L', '?'}; const char timeSetSymbols[] = {'G', 'R', 'L', '?'};
#ifdef HAS_IF482
HardwareSerial IF482(2); // use UART #2 (#1 may be in use for serial GPS)
#endif
Ticker timesyncer; Ticker timesyncer;
static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
void timeSync() { xTaskNotify(irqHandlerTask, TIMESYNC_IRQ, eSetBits); } void timeSync() { xTaskNotify(irqHandlerTask, TIMESYNC_IRQ, eSetBits); }
time_t timeProvider(void) { time_t timeProvider(void) {
@ -115,18 +121,22 @@ void timepulse_start(void) {
// interrupt service routine triggered by either pps or esp32 hardware timer // interrupt service routine triggered by either pps or esp32 hardware timer
void IRAM_ATTR CLOCKIRQ(void) { void IRAM_ATTR CLOCKIRQ(void) {
portENTER_CRITICAL_ISR(&mux);
BaseType_t xHigherPriorityTaskWoken; BaseType_t xHigherPriorityTaskWoken;
SyncToPPS(); // calibrates UTC systime, see microTime.h
xHigherPriorityTaskWoken = pdFALSE; xHigherPriorityTaskWoken = pdFALSE;
SyncToPPS(); // calibrates UTC systime, see microTime.h
if (ClockTask != NULL) if (ClockTask != NULL)
xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits, xTaskNotifyFromISR(ClockTask, uint32_t(now()), eSetBits,
&xHigherPriorityTaskWoken); &xHigherPriorityTaskWoken);
#if defined GPS_INT || defined RTC_INT #if (defined GPS_INT || defined RTC_INT)
TimePulseTick = !TimePulseTick; // flip ticker TimePulseTick = !TimePulseTick; // flip pulse ticker
#endif #endif
portEXIT_CRITICAL_ISR(&mux);
// yield only if we should // yield only if we should
if (xHigherPriorityTaskWoken) if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
@ -163,8 +173,8 @@ TickType_t tx_Ticks(uint32_t framesize, unsigned long baud, uint32_t config,
uint32_t databits = ((config & 0x0c) >> 2) + 5; uint32_t databits = ((config & 0x0c) >> 2) + 5;
uint32_t stopbits = ((config & 0x20) >> 5) + 1; uint32_t stopbits = ((config & 0x20) >> 5) + 1;
uint32_t txTime = (databits + stopbits + 2) * framesize * 1000.0 / baud; uint32_t txTime = (databits + stopbits + 1) * framesize * 1000.0 / baud;
// +1 ms margin for the startbit +1 ms for pending processing time // +1 for the startbit
return round(txTime); return round(txTime);
} }
@ -207,10 +217,13 @@ void clock_loop(void *taskparameter) { // ClockTask
uint32_t printtime; uint32_t printtime;
time_t t = *((time_t *)taskparameter); // UTC time seconds time_t t = *((time_t *)taskparameter); // UTC time seconds
// preload first DCF frame before start
#ifdef HAS_DCF77 #ifdef HAS_DCF77
uint8_t *DCFpulse; // pointer on array with DCF pulse bits uint8_t *DCFpulse; // pointer on array with DCF pulse bits
DCFpulse = DCF77_Frame(nextmin(t)); DCFpulse = DCF77_Frame(nextmin(t)); // load first DCF frame before start
#elif defined HAS_IF482
static TickType_t txDelay =
pdMS_TO_TICKS(1000 - 2) - tx_Ticks(IF482_FRAME_SIZE, HAS_IF482);
// 2ms margin for processing time
#endif #endif
// output the next second's pulse after timepulse arrived // output the next second's pulse after timepulse arrived
@ -226,7 +239,8 @@ void clock_loop(void *taskparameter) { // ClockTask
#if defined HAS_IF482 #if defined HAS_IF482
IF482_Pulse(t); vTaskDelay(txDelay); // wait until moment to fire
IF482.print(IF482_Frame(t + 1)); // note: if482 telegram for *next* second
#elif defined HAS_DCF77 #elif defined HAS_DCF77

View File

@ -54,7 +54,7 @@ void send_timesync_req() {
"timesync_req", // name of task "timesync_req", // name of task
2048, // stack size of task 2048, // stack size of task
(void *)1, // task parameter (void *)1, // task parameter
4, // priority of the task 2, // priority of the task
&timeSyncReqTask, // task handle &timeSyncReqTask, // task handle
1); // CPU core 1); // CPU core
} }
@ -129,10 +129,14 @@ void process_timesync_req(void *taskparameter) {
// calculate absolute time offset with millisecond precision using time base // calculate absolute time offset with millisecond precision using time base
// of LMIC os, since we use LMIC's ostime_t txEnd as tx timestamp // of LMIC os, since we use LMIC's ostime_t txEnd as tx timestamp
time_offset += milliseconds(osticks2ms(os_getTime())); time_offset += milliseconds(osticks2ms(os_getTime()));
// apply calibration factor for processing time // apply calibration factor for processing time
time_offset += milliseconds(TIME_SYNC_FIXUP); time_offset += milliseconds(TIME_SYNC_FIXUP);
// convert to seconds // convert to whole seconds
time_to_set = static_cast<time_t>(myClock_secTick(time_offset).count()); time_to_set = static_cast<time_t>(myClock_secTick(time_offset).count());
// time_to_set =
// static_cast<time_t>(duration_cast<seconds>(time_offset).count());
// calculate fraction milliseconds // calculate fraction milliseconds
time_to_set_fraction_msec = static_cast<uint16_t>(time_offset.count() % 1000); time_to_set_fraction_msec = static_cast<uint16_t>(time_offset.count() % 1000);
@ -145,15 +149,14 @@ void process_timesync_req(void *taskparameter) {
TIME_SYNC_TRIGGER) { // milliseconds threshold TIME_SYNC_TRIGGER) { // milliseconds threshold
// wait until top of second // wait until top of second
uint16_t const wait_ms = 1000 - time_to_set_fraction_msec; vTaskDelay(pdMS_TO_TICKS(1000 - time_to_set_fraction_msec));
ESP_LOGD(TAG, "[%0.3f] waiting %d ms", millis() / 1000.0, wait_ms);
vTaskDelay(pdMS_TO_TICKS(wait_ms));
#if !defined(GPS_INT) && !defined(RTC_INT) time_to_set++; // advance time the one waited second
#if (!defined GPS_INT && !defined RTC_INT)
// sync esp32 hardware timer based pps to top of second // sync esp32 hardware timer based pps to top of second
timerRestart(ppsIRQ); // reset pps timer timerRestart(ppsIRQ); // reset pps timer
CLOCKIRQ(); // fire clock pps interrupt CLOCKIRQ(); // fire clock pps interrupt
time_to_set++; // advance time 1 second
#endif #endif
setTime(time_to_set); // set the time on top of second setTime(time_to_set); // set the time on top of second
@ -193,6 +196,21 @@ void store_time_sync_req(uint32_t t_txEnd_ms) {
t_txEnd_ms % 1000); t_txEnd_ms % 1000);
} }
/*
// called from lorawan.cpp after time_sync_req was sent
void store_time_sync_req_pwm(void) {
uint8_t k = time_sync_seqNo % TIME_SYNC_SAMPLES;
time_sync_tx[k] += milliseconds(t_txEnd_ms);
ESP_LOGD(TAG, "[%0.3f] Timesync request #%d sent at %d.%03d",
millis() / 1000.0, time_sync_seqNo, t_txEnd_ms / 1000,
t_txEnd_ms % 1000);
}
*/
// process timeserver timestamp answer, called from lorawan.cpp // process timeserver timestamp answer, called from lorawan.cpp
int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) { int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) {
@ -229,7 +247,7 @@ int recv_timesync_ans(uint8_t buf[], uint8_t buf_len) {
// construct the timepoint when message was seen on gateway // construct the timepoint when message was seen on gateway
time_sync_rx[k] += seconds(timestamp_sec) + milliseconds(timestamp_msec); time_sync_rx[k] += seconds(timestamp_sec) + milliseconds(timestamp_msec);
// guess if the timepoint is recent by comparing with code compile date // guess timepoint is recent if newer than code compile date
if (timeIsValid(myClock::to_time_t(time_sync_rx[k]))) { if (timeIsValid(myClock::to_time_t(time_sync_rx[k]))) {
ESP_LOGD(TAG, "[%0.3f] Timesync request #%d rcvd at %d.%03d", ESP_LOGD(TAG, "[%0.3f] Timesync request #%d rcvd at %d.%03d",
millis() / 1000.0, seq_no, timestamp_sec, timestamp_msec); millis() / 1000.0, seq_no, timestamp_sec, timestamp_msec);