timer irqs refactored

This commit is contained in:
Verkehrsrot 2019-03-03 12:57:00 +01:00
parent b516cbbbce
commit 51917b79d3
9 changed files with 70 additions and 44 deletions

View File

@ -111,7 +111,7 @@ 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 *sendCycle, *displaytimer, *clockCycle; extern hw_timer_t *displayIRQ, *ppsIRQ;
extern SemaphoreHandle_t I2Caccess, TimePulse; extern SemaphoreHandle_t I2Caccess, TimePulse;
extern TaskHandle_t irqHandlerTask, ClockTask; extern TaskHandle_t irqHandlerTask, ClockTask;
extern TimerHandle_t WifiChanTimer; extern TimerHandle_t WifiChanTimer;

View File

@ -3,7 +3,7 @@
#define DISPLAY_IRQ 0x01 #define DISPLAY_IRQ 0x01
#define BUTTON_IRQ 0x02 #define BUTTON_IRQ 0x02
#define SENDCOUNTER_IRQ 0x04 #define SENDCYCLE_IRQ 0x04
#define CYCLIC_IRQ 0x08 #define CYCLIC_IRQ 0x08
#define TIMESYNC_IRQ 0x10 #define TIMESYNC_IRQ 0x10

View File

@ -30,17 +30,17 @@ void irqHandler(void *pvParameters) {
#endif #endif
// are cyclic tasks due? // are cyclic tasks due?
if (InterruptStatus & CYCLIC_IRQ) { if (InterruptStatus & CYCLIC_IRQ)
doHousekeeping(); doHousekeeping();
}
// time to be synced? #ifdef TIME_SYNC_INTERVAL
if (InterruptStatus & TIMESYNC_IRQ) { // is time to be synced?
if (InterruptStatus & TIMESYNC_IRQ)
setTime(timeProvider()); setTime(timeProvider());
} #endif
// is time to send the payload? // is time to send the payload?
if (InterruptStatus & SENDCOUNTER_IRQ) if (InterruptStatus & SENDCYCLE_IRQ)
sendCounter(); sendCounter();
} }
vTaskDelete(NULL); // shoud never be reached vTaskDelete(NULL); // shoud never be reached
@ -51,14 +51,26 @@ void irqHandler(void *pvParameters) {
#ifdef HAS_DISPLAY #ifdef HAS_DISPLAY
void IRAM_ATTR DisplayIRQ() { void IRAM_ATTR DisplayIRQ() {
xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits, NULL); BaseType_t xHigherPriorityTaskWoken;
portYIELD_FROM_ISR(); xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(irqHandlerTask, DISPLAY_IRQ, eSetBits,
&xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR();
} }
#endif #endif
#ifdef HAS_BUTTON #ifdef HAS_BUTTON
void IRAM_ATTR ButtonIRQ() { void IRAM_ATTR ButtonIRQ() {
xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits, NULL); BaseType_t xHigherPriorityTaskWoken;
portYIELD_FROM_ISR(); xHigherPriorityTaskWoken = pdFALSE;
xTaskNotifyFromISR(irqHandlerTask, BUTTON_IRQ, eSetBits,
&xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken)
portYIELD_FROM_ISR();
} }
#endif #endif

View File

@ -23,17 +23,17 @@ licenses. Refer to LICENSE.txt file in repository for more details.
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\ //////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
Uused tasks and timers: // Tasks and timers:
Task Core Prio Purpose Task Core Prio Purpose
==================================================================================== -------------------------------------------------------------------------------
ledloop 0 3 blinks LEDs ledloop 0 3 blinks LEDs
spiloop 0 2 reads/writes data on spi interface spiloop 0 2 reads/writes data on spi interface
IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer IDLE 0 0 ESP32 arduino scheduler -> runs wifi sniffer
clockloop 1 4 generates realtime telegrams for external clock clockloop 1 4 generates realtime telegrams for external clock
looptask 1 1 arduino core -> runs the LMIC LoRa stack 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 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
IDLE 1 0 ESP32 arduino scheduler -> runs wifi channel rotator 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 Tasks using i2c bus all must have same priority, because using mutex semaphore
(irqhandler, bmeloop) (irqhandler, bmeloop)
ESP32 hardware irq timers // ESP32 hardware timers
================================ -------------------------------------------------------------------------------
0 triggers display refresh 0 displayIRQ -> display refresh -> 40ms (DISPLAYREFRESH_MS in paxcounter.conf)
1 triggers DCF77 clock signal 1 ppsIRQ -> pps clock irq -> 1sec
2 triggers send payload cycle 2 unused
3 triggers housekeeping cycle 3 unused
RTC hardware timer (if present)
================================ // Interrupt routines
triggers pps 1 sec impulse -------------------------------------------------------------------------------
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, 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 *sendCycle = NULL, *homeCycle = NULL, *clockCycle = NULL, hw_timer_t *ppsIRQ = NULL, *displayIRQ = NULL;
*displaytimer = NULL;
TaskHandle_t irqHandlerTask, ClockTask; TaskHandle_t irqHandlerTask, ClockTask;
SemaphoreHandle_t I2Caccess, TimePulse; SemaphoreHandle_t I2Caccess, TimePulse;
@ -306,11 +320,11 @@ void setup() {
// setup display refresh trigger IRQ using esp32 hardware timer // setup display refresh trigger IRQ using esp32 hardware timer
// https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/ // https://techtutorialsx.com/2017/10/07/esp32-arduino-timer-interrupts/
// prescaler 80 -> divides 80 MHz CPU freq to 1 MHz, timer 0, count up // 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 // interrupt handler DisplayIRQ, triggered by edge
timerAttachInterrupt(displaytimer, &DisplayIRQ, true); timerAttachInterrupt(displayIRQ, &DisplayIRQ, true);
// reload interrupt after each trigger of display refresh cycle // reload interrupt after each trigger of display refresh cycle
timerAlarmWrite(displaytimer, DISPLAYREFRESH_MS * 1000, true); timerAlarmWrite(displayIRQ, DISPLAYREFRESH_MS * 1000, true);
#endif #endif
// show payload encoder // show payload encoder
@ -385,9 +399,9 @@ void setup() {
// start timer triggered interrupts // start timer triggered interrupts
ESP_LOGI(TAG, "Starting Timers..."); ESP_LOGI(TAG, "Starting Timers...");
#ifdef HAS_DISPLAY #ifdef HAS_DISPLAY
timerAlarmEnable(displaytimer); timerAlarmEnable(displayIRQ);
#endif #endif
sendcycler.attach(SEND_CYCLE, sendcycle); sendcycler.attach(SEND_CYCLE * 2, sendcycle);
housekeeper.attach(HOMECYCLE, housekeeping); housekeeper.attach(HOMECYCLE, housekeeping);
// start button interrupt // start button interrupt

View File

@ -10,7 +10,7 @@
#define VERBOSE 1 // comment out to silence the device, for mute use build option #define VERBOSE 1 // comment out to silence the device, for mute use build option
// Payload send cycle and encoding // 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 #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 // Set this to include BLE counting and vendor filter functions

View File

@ -290,11 +290,12 @@ void PayloadConvert::writeBitmap(bool a, bool b, bool c, bool d, bool e, bool f,
} }
/* ---------------- Cayenne LPP 2.0 format ---------- */ /* ---------------- Cayenne LPP 2.0 format ---------- */
// see specs // see specs
// http://community.mydevices.com/t/cayenne-lpp-2-0/7510 (LPP 2.0) // 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) // https://github.com/myDevicesIoT/cayenne-docs/blob/master/docs/LORA.md
// PAYLOAD_ENCODER == 3 -> Dynamic Sensor Payload, using channels -> FPort 1 // (LPP 1.0) PAYLOAD_ENCODER == 3 -> Dynamic Sensor Payload, using channels ->
// PAYLOAD_ENCODER == 4 -> Packed Sensor Payload, not using channels -> FPort 2 // FPort 1 PAYLOAD_ENCODER == 4 -> Packed Sensor Payload, not using channels ->
// FPort 2
#elif (PAYLOAD_ENCODER == 3 || PAYLOAD_ENCODER == 4) #elif (PAYLOAD_ENCODER == 3 || PAYLOAD_ENCODER == 4)

View File

@ -58,9 +58,8 @@ void set_rssi(uint8_t val[]) {
void set_sendcycle(uint8_t val[]) { void set_sendcycle(uint8_t val[]) {
cfg.sendcycle = val[0]; cfg.sendcycle = val[0];
// update send cycle interrupt // update send cycle interrupt [seconds
timerAlarmWrite(sendCycle, cfg.sendcycle * 2 * 10000, true); sendcycler.attach(cfg.sendcycle * 2, sendcycle);
// reload interrupt after each trigger of channel switch cycle
ESP_LOGI(TAG, "Remote command: set send cycle to %d seconds", ESP_LOGI(TAG, "Remote command: set send cycle to %d seconds",
cfg.sendcycle * 2); cfg.sendcycle * 2);
} }

View File

@ -3,7 +3,7 @@
Ticker sendcycler; 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 // put data to send in RTos Queues used for transmit over channels Lora and SPI
void SendPayload(uint8_t port, sendprio_t prio) { void SendPayload(uint8_t port, sendprio_t prio) {

View File

@ -78,8 +78,8 @@ uint8_t timepulse_init() {
#else #else
// use ESP32 hardware timer as time base with adjustable frequency // use ESP32 hardware timer as time base with adjustable frequency
clockCycle = 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(clockCycle, 10000, true); // 1000ms timerAlarmWrite(ppsIRQ, 10000, true); // 1000ms
ESP_LOGI(TAG, "Timepulse: internal (ESP32 hardware timer)"); ESP_LOGI(TAG, "Timepulse: internal (ESP32 hardware timer)");
return 1; // success return 1; // success
@ -92,8 +92,8 @@ void timepulse_start(void) {
#elif defined RTC_INT // start external clock rtc #elif defined RTC_INT // start external clock rtc
attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING); attachInterrupt(digitalPinToInterrupt(RTC_INT), CLOCKIRQ, FALLING);
#else // start internal clock esp32 hardware timer #else // start internal clock esp32 hardware timer
timerAttachInterrupt(clockCycle, &CLOCKIRQ, true); timerAttachInterrupt(ppsIRQ, &CLOCKIRQ, true);
timerAlarmEnable(clockCycle); timerAlarmEnable(ppsIRQ);
#endif #endif
} }