Skip to content

Commit 78fba4c

Browse files
Optimize IRAM and CPU usage in IRQ
Try and minimize the IRAM needed to run the IRQ while keeping performance at or better than before.
1 parent 99af25c commit 78fba4c

File tree

1 file changed

+22
-31
lines changed

1 file changed

+22
-31
lines changed

cores/esp8266/core_esp8266_waveform.c

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
// Waveform generator can create tones, PWM, and servos
5858
typedef struct {
5959
uint32_t nextServiceCycle; // ESP cycle timer when a transition required
60-
uint32_t timeLeftCycles; // For time-limited waveform, how many ESP cycles left
60+
uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop
6161
uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform
6262
uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform
6363
} Waveform;
@@ -86,13 +86,11 @@ static inline ICACHE_RAM_ATTR uint32_t GetCycleCount() {
8686
// Interrupt on/off control
8787
static ICACHE_RAM_ATTR void timer1Interrupt();
8888
static bool timerRunning = false;
89-
static uint32_t lastCycleCount = 0; // Last ESP cycle counter on running the interrupt routine
9089

9190
static void initTimer() {
9291
timer1_disable();
9392
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
9493
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
95-
lastCycleCount = GetCycleCount();
9694
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
9795
timerRunning = true;
9896
}
@@ -130,7 +128,11 @@ int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t
130128
wave->nextTimeHighCycles = MicrosecondsToCycles(timeHighUS) > 280 ? MicrosecondsToCycles(timeHighUS) - 280 : MicrosecondsToCycles(timeHighUS); // Take out some time for IRQ codepath
131129
wave->nextTimeLowCycles = MicrosecondsToCycles(timeLowUS) > 280 ? MicrosecondsToCycles(timeLowUS)- 280 : MicrosecondsToCycles(timeLowUS); // Take out some time for IRQ codepath
132130
#endif
133-
wave->timeLeftCycles = MicrosecondsToCycles(runTimeUS);
131+
wave->expiryCycle = runTimeUS ? GetCycleCount() + MicrosecondsToCycles(runTimeUS) : 0;
132+
if (runTimeUS && !wave->expiryCycle) {
133+
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
134+
}
135+
134136
uint32_t mask = 1<<pin;
135137
if (!waveformEnabled && mask) {
136138
// Actually set the pin high or low in the IRQ service to guarantee times
@@ -193,9 +195,9 @@ int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
193195
static ICACHE_RAM_ATTR void timer1Interrupt() {
194196
uint32_t nextEventCycles;
195197
#if F_CPU == 160000000
196-
uint8_t cnt = 20;
198+
int cnt = 20;
197199
#else
198-
uint8_t cnt = 5;
200+
int cnt = 10;
199201
#endif
200202

201203
// Handle enable/disable requests from main app.
@@ -215,10 +217,21 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
215217
}
216218

217219
Waveform *wave = &waveform[i];
218-
uint32_t now;
220+
uint32_t now = GetCycleCountIRQ();
221+
222+
// Disable any waveforms that are done
223+
if (wave->expiryCycle) {
224+
int32_t expiryToGo = wave->expiryCycle - now;
225+
if (expiryToGo < 0) {
226+
// Done, remove!
227+
waveformEnabled &= ~mask;
228+
if (i==16) GP16O &= ~1;
229+
else ClearGPIO(mask);
230+
continue;
231+
}
232+
}
219233

220234
// Check for toggles
221-
now = GetCycleCountIRQ();
222235
int32_t cyclesToGo = wave->nextServiceCycle - now;
223236
if (cyclesToGo < 0) {
224237
waveformState ^= mask;
@@ -242,28 +255,6 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
242255
}
243256
} while (--cnt && (nextEventCycles < MicrosecondsToCycles(4)));
244257

245-
uint32_t curCycleCount = GetCycleCountIRQ();
246-
uint32_t deltaCycles = curCycleCount - lastCycleCount;
247-
lastCycleCount = curCycleCount;
248-
249-
// Check for timed-out waveforms out of the high-frequency toggle loop
250-
for (size_t i = 0; i <= 16; i++) {
251-
Waveform *wave = &waveform[i];
252-
uint32_t mask = 1<<i;
253-
if ((waveformEnabled & mask) && wave->timeLeftCycles) {
254-
// Check for unsigned underflow with new > old
255-
if (deltaCycles >= wave->timeLeftCycles) {
256-
// Done, remove!
257-
waveformEnabled &= ~mask;
258-
if (i==16) GP16O &= ~1;
259-
else ClearGPIO(mask);
260-
} else {
261-
uint32_t newTimeLeftCycles = wave->timeLeftCycles - deltaCycles;
262-
wave->timeLeftCycles = newTimeLeftCycles;
263-
}
264-
}
265-
}
266-
267258
if (timer1CB) {
268259
nextEventCycles = min_u32(nextEventCycles, timer1CB());
269260
}
@@ -284,6 +275,6 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
284275
#endif
285276

286277
// Do it here instead of global function to save time and because we know it's edge-IRQ
287-
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
288278
TEIE |= TEIE1; //edge int enable
279+
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
289280
}

0 commit comments

Comments
 (0)