From 51917b79d349d27328462a68e34218738c03de6b Mon Sep 17 00:00:00 2001 From: Verkehrsrot Date: Sun, 3 Mar 2019 12:57:00 +0100 Subject: [PATCH] timer irqs refactored --- include/globals.h | 2 +- include/irqhandler.h | 2 +- src/irqhandler.cpp | 32 ++++++++++++++++++--------- src/main.cpp | 52 ++++++++++++++++++++++++++++---------------- src/paxcounter.conf | 2 +- src/payload.cpp | 9 ++++---- src/rcommand.cpp | 5 ++--- src/senddata.cpp | 2 +- src/timekeeper.cpp | 8 +++---- 9 files changed, 70 insertions(+), 44 deletions(-) diff --git a/include/globals.h b/include/globals.h index 0f232247..24c83580 100644 --- a/include/globals.h +++ b/include/globals.h @@ -111,7 +111,7 @@ extern uint16_t volatile macs_total, macs_wifi, macs_ble, batt_voltage; // display values extern bool volatile TimePulseTick; // 1sec pps flag set by GPS or RTC extern timesource_t timeSource; -extern hw_timer_t *sendCycle, *displaytimer, *clockCycle; +extern hw_timer_t *displayIRQ, *ppsIRQ; extern SemaphoreHandle_t I2Caccess, TimePulse; extern TaskHandle_t irqHandlerTask, ClockTask; extern TimerHandle_t WifiChanTimer; diff --git a/include/irqhandler.h b/include/irqhandler.h index d818e138..ad74f700 100644 --- a/include/irqhandler.h +++ b/include/irqhandler.h @@ -3,7 +3,7 @@ #define DISPLAY_IRQ 0x01 #define BUTTON_IRQ 0x02 -#define SENDCOUNTER_IRQ 0x04 +#define SENDCYCLE_IRQ 0x04 #define CYCLIC_IRQ 0x08 #define TIMESYNC_IRQ 0x10 diff --git a/src/irqhandler.cpp b/src/irqhandler.cpp index 06bf82e7..0757430b 100644 --- a/src/irqhandler.cpp +++ b/src/irqhandler.cpp @@ -30,17 +30,17 @@ void irqHandler(void *pvParameters) { #endif // are cyclic tasks due? - if (InterruptStatus & CYCLIC_IRQ) { + if (InterruptStatus & CYCLIC_IRQ) doHousekeeping(); - } - // time to be synced? - if (InterruptStatus & TIMESYNC_IRQ) { +#ifdef TIME_SYNC_INTERVAL + // is time to be synced? + if (InterruptStatus & TIMESYNC_IRQ) setTime(timeProvider()); - } +#endif // is time to send the payload? - if (InterruptStatus & SENDCOUNTER_IRQ) + if (InterruptStatus & SENDCYCLE_IRQ) sendCounter(); } vTaskDelete(NULL); // shoud never be reached @@ -51,14 +51,26 @@ void irqHandler(void *pvParameters) { #ifdef HAS_DISPLAY void IRAM_ATTR DisplayIRQ() { - xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, NULL); - portYIELD_FROM_ISR(); + BaseType_t xHigherPriorityTaskWoken; + xHigherPriorityTaskWoken = pdFALSE; + + xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, + &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken) + portYIELD_FROM_ISR(); } #endif #ifdef HAS_BUTTON void IRAM_ATTR ButtonIRQ() { - xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits, NULL); - portYIELD_FROM_ISR(); + BaseType_t xHigherPriorityTaskWoken; + xHigherPriorityTaskWoken = pdFALSE; + + xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits, + &xHigherPriorityTaskWoken); + + if (xHigherPriorityTaskWoken) + portYIELD_FROM_ISR(); } #endif diff --git a/src/main.cpp b/src/main.cpp index 345c54c2..74094336 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,17 +23,17 @@ licenses. Refer to LICENSE.txt file in repository for more details. //////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\ -Uused tasks and timers: +// Tasks and timers: Task Core Prio Purpose -==================================================================================== +------------------------------------------------------------------------------- ledloop 0 3 blinks LEDs spiloop 0 2 reads/writes data on spi interface IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer clockloop 1 4 generates realtime telegrams for external clock looptask 1 1 arduino core -> runs the LMIC LoRa stack -irqhandler 1 1 executes tasks triggered by hw irq, see table below +irqhandler 1 1 executes tasks triggered by timer irq gpsloop 1 2 reads data from GPS via serial or i2c bmeloop 1 1 reads data from BME sensor via i2c IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator @@ -43,16 +43,31 @@ Low priority numbers denote low priority tasks. Tasks using i2c bus all must have same priority, because using mutex semaphore (irqhandler, bmeloop) -ESP32 hardware irq timers -================================ - 0 triggers display refresh - 1 triggers DCF77 clock signal - 2 triggers send payload cycle - 3 triggers housekeeping cycle +// ESP32 hardware timers +------------------------------------------------------------------------------- + 0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS in paxcounter.conf) + 1 ppsIRQ -> pps clock irq -> 1sec + 2 unused + 3 unused - RTC hardware timer (if present) -================================ - triggers pps 1 sec impulse + +// Interrupt routines +------------------------------------------------------------------------------- + +fired by hardware +DisplayIRQ -> esp32 timer 0 -> irqhandler.cpp +CLOCKIRQ -> esp32 timer 1 -> timekeeper.cpp +ButtonIRQ -> external gpio -> irqhandler.cpp + +fired by software (Ticker.h) +TIMESYNC_IRQ -> timeSync() -> timerkeeper.cpp +CYLCIC_IRQ -> housekeeping() -> cyclic.cpp +SENDCYCLE_IRQ -> sendcycle() -> senddata.cpp + + +// External RTC timer (if present) +------------------------------------------------------------------------------- +triggers pps 1 sec impulse */ @@ -65,8 +80,7 @@ uint8_t volatile channel = 0; // channel rotation counter uint16_t volatile macs_total = 0, macs_wifi = 0, macs_ble = 0, batt_voltage = 0; // globals for display -hw_timer_t *sendCycle = NULL, *homeCycle = NULL, *clockCycle = NULL, - *displaytimer = NULL; +hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL; TaskHandle_t irqHandlerTask, ClockTask; SemaphoreHandle_t I2Caccess, TimePulse; @@ -306,11 +320,11 @@ void setup() { // setup display refresh trigger IRQ using esp32 hardware timer // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up - displaytimer = timerBegin(0, 80, true); + displayIRQ = timerBegin(0, 80, true); // interrupt handler DisplayIRQ, triggered by edge - timerAttachInterrupt(displaytimer, &DisplayIRQ, true); + timerAttachInterrupt(displayIRQ, &DisplayIRQ, true); // reload interrupt after each trigger of display refresh cycle - timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true); + timerAlarmWrite(displayIRQ, DISPLAYREFRESH_MS * 1000, true); #endif // show payload encoder @@ -385,9 +399,9 @@ void setup() { // start timer triggered interrupts ESP_LOGI(TAG, "Starting Timers..."); #ifdef HAS_DISPLAY - timerAlarmEnable(displaytimer); + timerAlarmEnable(displayIRQ); #endif - sendcycler.attach(SEND_CYCLE, sendcycle); + sendcycler.attach(SEND_CYCLE * 2, sendcycle); housekeeper.attach(HOMECYCLE, housekeeping); // start button interrupt diff --git a/src/paxcounter.conf b/src/paxcounter.conf index c60d0ee9..a4efffeb 100644 --- a/src/paxcounter.conf +++ b/src/paxcounter.conf @@ -10,7 +10,7 @@ #define VERBOSE 1 // comment out to silence the device, for mute use build option // Payload send cycle and encoding -#define SEND_CYCLE 30 // payload send cycle [seconds/2] -> 60 sec. +#define SEND_CYCLE 30 // payload send cycle [seconds/2], 0 .. 255 #define PAYLOAD_ENCODER 2 // payload encoder: 1=Plain, 2=Packed, 3=Cayenne LPP dynamic, 4=Cayenne LPP packed // Set this to include BLE counting and vendor filter functions diff --git a/src/payload.cpp b/src/payload.cpp index 8326d8a8..ea3faf5d 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -290,11 +290,12 @@ void PayloadConvert::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f, } /* ---------------- Cayenne LPP 2.0 format ---------- */ -// see specs +// see specs // http://community.mydevices.com/t/cayenne-lpp-2-0/7510 (LPP 2.0) -// https://github.com/myDevicesIoT/cayenne-docs/blob/master/docs/LORA.md (LPP 1.0) -// PAYLOAD_ENCODER == 3 -> Dynamic Sensor Payload, using channels -> FPort 1 -// PAYLOAD_ENCODER == 4 -> Packed Sensor Payload, not using channels -> FPort 2 +// https://github.com/myDevicesIoT/cayenne-docs/blob/master/docs/LORA.md +// (LPP 1.0) PAYLOAD_ENCODER == 3 -> Dynamic Sensor Payload, using channels -> +// FPort 1 PAYLOAD_ENCODER == 4 -> Packed Sensor Payload, not using channels -> +// FPort 2 #elif (PAYLOAD_ENCODER == 3 || PAYLOAD_ENCODER == 4) diff --git a/src/rcommand.cpp b/src/rcommand.cpp index 2873b9bf..a49dc1e8 100644 --- a/src/rcommand.cpp +++ b/src/rcommand.cpp @@ -58,9 +58,8 @@ void set_rssi(uint8_t val[]) { void set_sendcycle(uint8_t val[]) { cfg.sendcycle = val[0]; - // update send cycle interrupt - timerAlarmWrite(sendCycle, cfg.sendcycle * 2 * 10000, true); - // reload interrupt after each trigger of channel switch cycle + // update send cycle interrupt [seconds + sendcycler.attach(cfg.sendcycle * 2, sendcycle); ESP_LOGI(TAG, "Remote command: set send cycle to %d seconds", cfg.sendcycle * 2); } diff --git a/src/senddata.cpp b/src/senddata.cpp index 54efd4d2..36e8b278 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -3,7 +3,7 @@ Ticker sendcycler; -void sendcycle() { xTaskNotify(irqHandlerTask, SENDCOUNTER_IRQ, eSetBits); } +void sendcycle() { xTaskNotify(irqHandlerTask, SENDCYCLE_IRQ, eSetBits); } // put data to send in RTos Queues used for transmit over channels Lora and SPI void SendPayload(uint8_t port, sendprio_t prio) { diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 1a06bf2b..83a3bd8c 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -78,8 +78,8 @@ uint8_t timepulse_init() { #else // use ESP32 hardware timer as time base with adjustable frequency - clockCycle = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec - timerAlarmWrite(clockCycle, 10000, true); // 1000ms + ppsIRQ = timerBegin(1, 8000, true); // set 80 MHz prescaler to 1/10000 sec + timerAlarmWrite(ppsIRQ, 10000, true); // 1000ms ESP_LOGI(TAG, "Timepulse: internal (ESP32 hardware timer)"); return 1; // success @@ -92,8 +92,8 @@ void timepulse_start(void) { #elif defined RTC_INT // start external clock rtc attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING); #else // start internal clock esp32 hardware timer - timerAttachInterrupt(clockCycle, &CLOCKIRQ, true); - timerAlarmEnable(clockCycle); + timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true); + timerAlarmEnable(ppsIRQ); #endif }