Refactor ISR logic into FreeRTOS tasks via semaphore and queue
This commit is contained in:
+125
-108
@@ -9,148 +9,165 @@
|
|||||||
|
|
||||||
#include "InterruptHandler.h"
|
#include "InterruptHandler.h"
|
||||||
|
|
||||||
|
#define LOOP_COUNTS_FOR_PAUSE 2u
|
||||||
|
#define RF_QUEUE_SIZE 32u
|
||||||
|
|
||||||
|
SemaphoreHandle_t beepSemaphore;
|
||||||
|
QueueHandle_t rfEventQueue;
|
||||||
|
|
||||||
#define LOOP_COUNTS_FOR_PAUSE (2u)
|
hw_timer_t *timer;
|
||||||
/*****************************************************/
|
|
||||||
|
|
||||||
IRAM_ATTR void timerIsr();
|
|
||||||
IRAM_ATTR void pinLevelChangeIsr(void);
|
|
||||||
|
|
||||||
/*****************************************************/
|
|
||||||
|
|
||||||
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)
|
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);
|
attachInterrupt(digitalPinToInterrupt(DIN_FUNK), pinLevelChangeIsr, CHANGE);
|
||||||
|
|
||||||
#if 1
|
timer = timerBegin(0, 80, true); /* prescaler 80 → 1 MHz */
|
||||||
timer = timerBegin(0, 80, true); /* 80 -> 1 Mhz */
|
|
||||||
timerAttachInterrupt(timer, &timerIsr, true);
|
timerAttachInterrupt(timer, &timerIsr, true);
|
||||||
timerAlarmWrite(timer, ISR_TIME_US, true);
|
timerAlarmWrite(timer, ISR_TIME_US, true);
|
||||||
timerAlarmEnable(timer);
|
timerAlarmEnable(timer);
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called every 10 ms
|
* Called every ISR_TIME_US (10 ms).
|
||||||
*
|
* Kept minimal: advance tDecis and wake beepTask via semaphore.
|
||||||
* used to update tDecis, and for beeping
|
|
||||||
*/
|
*/
|
||||||
IRAM_ATTR void timerIsr()
|
static IRAM_ATTR void timerIsr(void)
|
||||||
{
|
{
|
||||||
static uint32_t tshortPiepStartedMs = 0;
|
static uint8_t count = 0;
|
||||||
static uint8_t count = 0;
|
if (++count == MS_TO_ISR_COUNT(100uL))
|
||||||
static boolean toneOn = false;
|
{
|
||||||
uint32_t tMillis = millis();
|
count = 0;
|
||||||
|
tDecis++;
|
||||||
#if 0
|
}
|
||||||
static bool on = true;
|
BaseType_t woken = pdFALSE;
|
||||||
if (on) digitalWrite(DOUT_TEST_TIMER, HIGH);
|
xSemaphoreGiveFromISR(beepSemaphore, &woken);
|
||||||
else digitalWrite(DOUT_TEST_TIMER, LOW);
|
portYIELD_FROM_ISR(woken);
|
||||||
on = !on;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (++count == MS_TO_ISR_COUNT(100uL) )
|
|
||||||
{
|
|
||||||
/* increment tDecis every 100ms */
|
|
||||||
count = 0;
|
|
||||||
tDecis++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bRequestShortBeep)
|
|
||||||
{
|
|
||||||
bRequestShortBeep = false;
|
|
||||||
tshortPiepStartedMs = tMillis;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tshortPiepStartedMs > 0u)
|
|
||||||
{
|
|
||||||
if (tMillis < (tshortPiepStartedMs + 30uL))
|
|
||||||
{
|
|
||||||
if (false == toneOn)
|
|
||||||
{
|
|
||||||
TONE_REQUEST_ON(TONE_REQUEST_SOURCE_SHORTPIEP);
|
|
||||||
toneOn = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TONE_REQUEST_OFF(TONE_REQUEST_SOURCE_SHORTPIEP);
|
|
||||||
tshortPiepStartedMs = 0;
|
|
||||||
toneOn = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
piepPattern->TaskCyclic();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toneRequest != 0u)
|
|
||||||
{
|
|
||||||
digitalWrite(DOUT_PIEP_VCC, HIGH);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
digitalWrite(DOUT_PIEP_VCC, LOW);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IRAM_ATTR void InterruptHandler_Stop(void)
|
/**
|
||||||
|
* Called on every 433 MHz pin edge.
|
||||||
|
* Kept minimal: measure pulse width and push to rfEventQueue for rfDecodeTask.
|
||||||
|
*/
|
||||||
|
static IRAM_ATTR void pinLevelChangeIsr(void)
|
||||||
{
|
{
|
||||||
timerAlarmDisable(timer);
|
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));
|
detachInterrupt(digitalPinToInterrupt(DIN_FUNK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR void InterruptHandler_PauseReceive()
|
||||||
IRAM_ATTR void InterruptHandler_PauseReceive()
|
|
||||||
{
|
{
|
||||||
loopCountSincePause = 0u;
|
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.
|
||||||
*/
|
*/
|
||||||
IRAM_ATTR void pinLevelChangeIsr(void)
|
static void beepTask(void *pvParameters)
|
||||||
{
|
{
|
||||||
static bool lastVal = LOW;
|
static uint32_t tshortPiepStartedMs = 0;
|
||||||
static uint32_t lastMics = 0;
|
static bool toneOn = false;
|
||||||
static uint32_t MINIMAL_DT_MICROS_FOR_RECEIVERS = 100u;
|
|
||||||
|
|
||||||
uint32_t dtMicros = micros() - lastMics;
|
for (;;)
|
||||||
bool pinFunkVal = digitalRead(DIN_FUNK);
|
{
|
||||||
|
xSemaphoreTake(beepSemaphore, portMAX_DELAY);
|
||||||
|
|
||||||
if (lastVal == pinFunkVal)
|
const uint32_t tMillis = millis();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lastMics = micros();
|
|
||||||
|
|
||||||
lastVal = pinFunkVal;
|
if (bRequestShortBeep)
|
||||||
if (loopCountSincePause < LOOP_COUNTS_FOR_PAUSE)
|
{
|
||||||
{
|
bRequestShortBeep = false;
|
||||||
/* after receiving a key, wait for the main loop to run x times before activating receiving again */
|
tshortPiepStartedMs = tMillis;
|
||||||
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);
|
if (tshortPiepStartedMs > 0u)
|
||||||
}
|
{
|
||||||
}
|
if (tMillis < tshortPiepStartedMs + 30u)
|
||||||
|
{
|
||||||
|
if (!toneOn)
|
||||||
|
{
|
||||||
|
TONE_REQUEST_ON(TONE_REQUEST_SOURCE_SHORTPIEP);
|
||||||
|
toneOn = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TONE_REQUEST_OFF(TONE_REQUEST_SOURCE_SHORTPIEP);
|
||||||
|
tshortPiepStartedMs = 0;
|
||||||
|
toneOn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
piepPattern->TaskCyclic();
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(DOUT_PIEP_VCC, toneRequest != 0u ? HIGH : LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static void rfDecodeTask(void *pvParameters)
|
||||||
|
{
|
||||||
|
RfEvent_t ev;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (xQueueReceive(rfEventQueue, &ev, portMAX_DELAY) == pdTRUE)
|
||||||
|
{
|
||||||
|
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