optimise mavlink SS packet size (#3029)
[ExpressLRS.git] / src / lib / HWTIMER / ESP32_hwTimer.cpp
blob3e1b28a6a426eb788ba4f5cd9e92203289230fa4
1 #if defined(PLATFORM_ESP32)
2 #include "hwTimer.h"
3 #include "logging.h"
5 void (*hwTimer::callbackTick)() = nullptr;
6 void (*hwTimer::callbackTock)() = nullptr;
8 volatile bool hwTimer::running = false;
9 volatile bool hwTimer::isTick = false;
11 volatile uint32_t hwTimer::HWtimerInterval = TimerIntervalUSDefault;
12 volatile int32_t hwTimer::PhaseShift = 0;
13 volatile int32_t hwTimer::FreqOffset = 0;
15 // Internal implementation specific variables
16 static hw_timer_t *timer = NULL;
17 static portMUX_TYPE isrMutex = portMUX_INITIALIZER_UNLOCKED;
19 #if defined(TARGET_RX)
20 #define HWTIMER_TICKS_PER_US 5
21 #else
22 #define HWTIMER_TICKS_PER_US 1
23 #endif
25 void ICACHE_RAM_ATTR hwTimer::init(void (*callbackTick)(), void (*callbackTock)())
28 if (!timer)
30 hwTimer::callbackTick = callbackTick;
31 hwTimer::callbackTock = callbackTock;
32 timer = timerBegin(0, (APB_CLK_FREQ / 1000000 / HWTIMER_TICKS_PER_US), true);
33 timerAttachInterrupt(timer, hwTimer::callback, true);
34 DBGLN("hwTimer Init");
38 void ICACHE_RAM_ATTR hwTimer::stop()
40 if (timer && running)
42 running = false;
43 timerAlarmDisable(timer);
44 DBGLN("hwTimer stop");
48 void ICACHE_RAM_ATTR hwTimer::resume()
50 if (timer && !running)
52 // The timer must be restarted so that the new timerAlarmWrite() period is set.
53 timerRestart(timer);
54 #if defined(TARGET_TX)
55 timerAlarmWrite(timer, HWtimerInterval, true);
56 #else
57 // We want the timer to fire tock() ASAP after enabling
58 // tock() should always be the first event to maintain consistency
59 isTick = false;
60 // When using EDGE triggered timer, enabling the timer causes an edge so the interrupt
61 // is fired immediately
62 // Unlike the 8266 timer, the ESP32 timer can be started without delay.
63 // It does not interrupt the currently running IsrCallback(), but triggers immediately once it has completed.
64 timerAlarmWrite(timer, 0 * HWTIMER_TICKS_PER_US, true);
65 #endif
66 running = true;
67 timerAlarmEnable(timer);
68 DBGLN("hwTimer resume");
72 void ICACHE_RAM_ATTR hwTimer::updateInterval(uint32_t time)
74 // timer should not be running when updateInterval() is called
75 HWtimerInterval = time * HWTIMER_TICKS_PER_US;
76 if (timer)
78 DBGLN("hwTimer interval: %d", time);
79 timerAlarmWrite(timer, HWtimerInterval, true);
83 void ICACHE_RAM_ATTR hwTimer::phaseShift(int32_t newPhaseShift)
85 int32_t minVal = -(HWtimerInterval >> 2);
86 int32_t maxVal = (HWtimerInterval >> 2);
88 // phase shift is in microseconds
89 PhaseShift = constrain(newPhaseShift, minVal, maxVal) * HWTIMER_TICKS_PER_US;
92 void ICACHE_RAM_ATTR hwTimer::callback(void)
94 if (running)
96 portENTER_CRITICAL_ISR(&isrMutex);
97 #if defined(TARGET_TX)
98 callbackTock();
99 #else
100 uint32_t NextInterval = (HWtimerInterval >> 1) + FreqOffset;
101 if (hwTimer::isTick)
103 timerAlarmWrite(timer, NextInterval, true);
104 hwTimer::callbackTick();
106 else
108 NextInterval += PhaseShift;
109 timerAlarmWrite(timer, NextInterval, true);
110 PhaseShift = 0;
111 hwTimer::callbackTock();
113 hwTimer::isTick = !hwTimer::isTick;
114 #endif
115 portEXIT_CRITICAL_ISR(&isrMutex);
119 #endif