Refactor ISR logic into FreeRTOS tasks via semaphore and queue
This commit is contained in:
+98
-81
@@ -9,62 +9,115 @@
|
||||
|
||||
#include "InterruptHandler.h"
|
||||
|
||||
#define LOOP_COUNTS_FOR_PAUSE 2u
|
||||
#define RF_QUEUE_SIZE 32u
|
||||
|
||||
|
||||
#define LOOP_COUNTS_FOR_PAUSE (2u)
|
||||
/*****************************************************/
|
||||
|
||||
IRAM_ATTR void timerIsr();
|
||||
IRAM_ATTR void pinLevelChangeIsr(void);
|
||||
|
||||
/*****************************************************/
|
||||
SemaphoreHandle_t beepSemaphore;
|
||||
QueueHandle_t rfEventQueue;
|
||||
|
||||
hw_timer_t *timer;
|
||||
|
||||
static IRAM_ATTR void timerIsr(void);
|
||||
static IRAM_ATTR void pinLevelChangeIsr(void);
|
||||
static void beepTask(void *pvParameters);
|
||||
static void rfDecodeTask(void *pvParameters);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void InterruptHandler_Init(void)
|
||||
{
|
||||
/* setup interrupt */
|
||||
beepSemaphore = xSemaphoreCreateBinary();
|
||||
rfEventQueue = xQueueCreate(RF_QUEUE_SIZE, sizeof(RfEvent_t));
|
||||
|
||||
/* beepTask: replaces beep logic that was in timerIsr — high priority so it responds within one tick */
|
||||
xTaskCreatePinnedToCore(beepTask, "beepTask", 2048, NULL, 5, NULL, 1);
|
||||
/* rfDecodeTask: replaces receiver ISR calls that were in pinLevelChangeIsr */
|
||||
xTaskCreatePinnedToCore(rfDecodeTask, "rfTask", 3072, NULL, 4, NULL, 1);
|
||||
|
||||
attachInterrupt(digitalPinToInterrupt(DIN_FUNK), pinLevelChangeIsr, CHANGE);
|
||||
|
||||
#if 1
|
||||
timer = timerBegin(0, 80, true); /* 80 -> 1 Mhz */
|
||||
timer = timerBegin(0, 80, true); /* prescaler 80 → 1 MHz */
|
||||
timerAttachInterrupt(timer, &timerIsr, true);
|
||||
timerAlarmWrite(timer, ISR_TIME_US, true);
|
||||
timerAlarmEnable(timer);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* called every 10 ms
|
||||
*
|
||||
* used to update tDecis, and for beeping
|
||||
* Called every ISR_TIME_US (10 ms).
|
||||
* Kept minimal: advance tDecis and wake beepTask via semaphore.
|
||||
*/
|
||||
IRAM_ATTR void timerIsr()
|
||||
static IRAM_ATTR void timerIsr(void)
|
||||
{
|
||||
static uint32_t tshortPiepStartedMs = 0;
|
||||
static uint8_t count = 0;
|
||||
static boolean toneOn = false;
|
||||
uint32_t tMillis = millis();
|
||||
|
||||
#if 0
|
||||
static bool on = true;
|
||||
if (on) digitalWrite(DOUT_TEST_TIMER, HIGH);
|
||||
else digitalWrite(DOUT_TEST_TIMER, LOW);
|
||||
on = !on;
|
||||
#endif
|
||||
|
||||
if (++count == MS_TO_ISR_COUNT(100uL))
|
||||
{
|
||||
/* increment tDecis every 100ms */
|
||||
count = 0;
|
||||
tDecis++;
|
||||
}
|
||||
BaseType_t woken = pdFALSE;
|
||||
xSemaphoreGiveFromISR(beepSemaphore, &woken);
|
||||
portYIELD_FROM_ISR(woken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on every 433 MHz pin edge.
|
||||
* Kept minimal: measure pulse width and push to rfEventQueue for rfDecodeTask.
|
||||
*/
|
||||
static IRAM_ATTR void pinLevelChangeIsr(void)
|
||||
{
|
||||
static bool lastVal = LOW;
|
||||
static uint32_t lastMics = 0;
|
||||
|
||||
const uint32_t now = micros();
|
||||
const uint32_t dtMicros = now - lastMics;
|
||||
const bool pinVal = digitalRead(DIN_FUNK);
|
||||
|
||||
if (lastVal == pinVal)
|
||||
return;
|
||||
|
||||
lastMics = now;
|
||||
lastVal = pinVal;
|
||||
|
||||
if (loopCountSincePause < LOOP_COUNTS_FOR_PAUSE || dtMicros < 100u)
|
||||
return;
|
||||
|
||||
RfEvent_t ev = {dtMicros, pinVal};
|
||||
BaseType_t woken = pdFALSE;
|
||||
xQueueSendFromISR(rfEventQueue, &ev, &woken);
|
||||
portYIELD_FROM_ISR(woken);
|
||||
}
|
||||
|
||||
IRAM_ATTR void InterruptHandler_Stop(void)
|
||||
{
|
||||
timerAlarmDisable(timer);
|
||||
detachInterrupt(digitalPinToInterrupt(DIN_FUNK));
|
||||
}
|
||||
|
||||
IRAM_ATTR void InterruptHandler_PauseReceive()
|
||||
{
|
||||
loopCountSincePause = 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Woken every 10 ms by timerIsr via beepSemaphore.
|
||||
* Handles short-beep timing and the PiepPattern state machine,
|
||||
* then drives the buzzer supply pin — work that was previously in timerIsr.
|
||||
*
|
||||
* Both tasks (beepTask and loop) run on Core 1, so they interleave only at
|
||||
* scheduling points and there is no true parallel access to piepPattern or
|
||||
* bRequestShortBeep.
|
||||
*/
|
||||
static void beepTask(void *pvParameters)
|
||||
{
|
||||
static uint32_t tshortPiepStartedMs = 0;
|
||||
static bool toneOn = false;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
xSemaphoreTake(beepSemaphore, portMAX_DELAY);
|
||||
|
||||
const uint32_t tMillis = millis();
|
||||
|
||||
if (bRequestShortBeep)
|
||||
{
|
||||
@@ -74,9 +127,9 @@ IRAM_ATTR void timerIsr()
|
||||
|
||||
if (tshortPiepStartedMs > 0u)
|
||||
{
|
||||
if (tMillis < (tshortPiepStartedMs + 30uL))
|
||||
if (tMillis < tshortPiepStartedMs + 30u)
|
||||
{
|
||||
if (false == toneOn)
|
||||
if (!toneOn)
|
||||
{
|
||||
TONE_REQUEST_ON(TONE_REQUEST_SOURCE_SHORTPIEP);
|
||||
toneOn = true;
|
||||
@@ -94,63 +147,27 @@ IRAM_ATTR void timerIsr()
|
||||
piepPattern->TaskCyclic();
|
||||
}
|
||||
|
||||
if (toneRequest != 0u)
|
||||
{
|
||||
digitalWrite(DOUT_PIEP_VCC, HIGH);
|
||||
digitalWrite(DOUT_PIEP_VCC, toneRequest != 0u ? HIGH : LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(DOUT_PIEP_VCC, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void InterruptHandler_Stop(void)
|
||||
{
|
||||
timerAlarmDisable(timer);
|
||||
detachInterrupt(digitalPinToInterrupt(DIN_FUNK));
|
||||
}
|
||||
|
||||
|
||||
IRAM_ATTR void InterruptHandler_PauseReceive()
|
||||
{
|
||||
loopCountSincePause = 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Drains rfEventQueue and runs all receiver state machines.
|
||||
* Runs on Core 1 at priority 4 (above loop priority 1), so it pre-empts
|
||||
* the loop task when RF edges arrive but never runs in true parallel with it.
|
||||
*/
|
||||
IRAM_ATTR void pinLevelChangeIsr(void)
|
||||
static void rfDecodeTask(void *pvParameters)
|
||||
{
|
||||
static bool lastVal = LOW;
|
||||
static uint32_t lastMics = 0;
|
||||
static uint32_t MINIMAL_DT_MICROS_FOR_RECEIVERS = 100u;
|
||||
|
||||
uint32_t dtMicros = micros() - lastMics;
|
||||
bool pinFunkVal = digitalRead(DIN_FUNK);
|
||||
|
||||
if (lastVal == pinFunkVal)
|
||||
RfEvent_t ev;
|
||||
for (;;)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
if (xQueueReceive(rfEventQueue, &ev, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
lastMics = micros();
|
||||
|
||||
lastVal = pinFunkVal;
|
||||
if (loopCountSincePause < LOOP_COUNTS_FOR_PAUSE)
|
||||
{
|
||||
/* after receiving a key, wait for the main loop to run x times before activating receiving again */
|
||||
return;
|
||||
}
|
||||
else if (dtMicros > MINIMAL_DT_MICROS_FOR_RECEIVERS)
|
||||
{
|
||||
receiverSw.Isr(dtMicros, pinFunkVal);
|
||||
receiverAiggend.Isr(dtMicros, pinFunkVal);
|
||||
receiverOval.Isr(dtMicros, pinFunkVal);
|
||||
receiverKerui.Isr(dtMicros, pinFunkVal);
|
||||
receiverThermo.Isr(dtMicros, pinFunkVal);
|
||||
|
||||
//digitalWrite(LED_BUILTIN, pinFunkVal);
|
||||
receiverSw.Isr(ev.dtMicros, ev.pinValue);
|
||||
receiverAiggend.Isr(ev.dtMicros, ev.pinValue);
|
||||
receiverOval.Isr(ev.dtMicros, ev.pinValue);
|
||||
receiverKerui.Isr(ev.dtMicros, ev.pinValue);
|
||||
receiverThermo.Isr(ev.dtMicros, ev.pinValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user