Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit de8201d

Browse filesBrowse files
committed
Corrected use of Timer1 registers and add rationale to Timer1 use in comment.
Recalibrate for improved frequence downscaling @ 80MHz and 160MHz.
1 parent 38cee2b commit de8201d
Copy full SHA for de8201d

File tree

Expand file treeCollapse file tree

1 file changed

+32
-34
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+32
-34
lines changed

‎cores/esp8266/core_esp8266_waveform.cpp

Copy file name to clipboardExpand all lines: cores/esp8266/core_esp8266_waveform.cpp
+32-34Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,18 @@
4444
#include "ets_sys.h"
4545
#include <atomic>
4646

47-
extern "C" {
48-
49-
// Maximum delay between IRQs, 1Hz
50-
constexpr int32_t MAXIRQCCYS = microsecondsToClockCycles(10000);
47+
// Maximum delay between IRQs, Timer1, <= 2^23 / 80MHz
48+
constexpr int32_t MAXIRQTICKSCCYS = microsecondsToClockCycles(100000);
5149
// Maximum servicing time for any single IRQ
5250
constexpr uint32_t ISRTIMEOUTCCYS = microsecondsToClockCycles(14);
5351
// The SDK and hardware take some time to actually get to our NMI code, so
5452
// decrement the next IRQ's timer value by a bit so we can actually catch the
5553
// real CPU cycle count we want for the waveforms.
56-
constexpr int32_t DELTAIRQ = clockCyclesPerMicrosecond() == 160 ?
57-
microsecondsToClockCycles(1) >> 1 : microsecondsToClockCycles(1);
54+
constexpr int32_t DELTAIRQCCYS = clockCyclesPerMicrosecond() == 160 ?
55+
microsecondsToClockCycles(3) >> 1 : microsecondsToClockCycles(3);
5856
// The latency between in-ISR rearming of the timer and the earliest firing
59-
constexpr int32_t IRQLATENCY = clockCyclesPerMicrosecond() == 160 ?
60-
(microsecondsToClockCycles(5) / 2) >> 1 : (microsecondsToClockCycles(5) / 2);
57+
constexpr int32_t IRQLATENCYCCYS = clockCyclesPerMicrosecond() == 160 ?
58+
(microsecondsToClockCycles(3) / 2) >> 1 : microsecondsToClockCycles(3) / 2;
6159

6260
// Set/clear GPIO 0-15 by bitmask
6361
#define SetGPIO(a) do { GPOS = a; } while (0)
@@ -120,7 +118,7 @@ static void initTimer() {
120118
ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt);
121119
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
122120
waveform.timer1Running = true;
123-
timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste
121+
timer1_write(CPU2X & 1 ? microsecondsToClockCycles(1) >> 1 : microsecondsToClockCycles(1)); // Cause an interrupt post-haste
124122
}
125123

126124
static void ICACHE_RAM_ATTR deinitTimer() {
@@ -130,6 +128,8 @@ static void ICACHE_RAM_ATTR deinitTimer() {
130128
waveform.timer1Running = false;
131129
}
132130

131+
extern "C" {
132+
133133
// Set a callback. Pass in NULL to stop it
134134
void setTimer1Callback(uint32_t (*fn)()) {
135135
waveform.timer1CB = fn;
@@ -154,12 +154,12 @@ int startWaveform(uint8_t pin, uint32_t highUS, uint32_t lowUS,
154154
int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
155155
uint32_t runTimeCcys, int8_t alignPhase, uint32_t phaseOffsetCcys, bool autoPwm) {
156156
uint32_t periodCcys = highCcys + lowCcys;
157-
if (periodCcys < MAXIRQCCYS) {
157+
if (periodCcys < MAXIRQTICKSCCYS) {
158158
if (!highCcys) {
159-
periodCcys = (MAXIRQCCYS / periodCcys) * periodCcys;
159+
periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys;
160160
}
161161
else if (!lowCcys) {
162-
highCcys = periodCcys = (MAXIRQCCYS / periodCcys) * periodCcys;
162+
highCcys = periodCcys = (MAXIRQTICKSCCYS / periodCcys) * periodCcys;
163163
}
164164
}
165165
// sanity checks, including mixed signed/unsigned arithmetic safety
@@ -193,9 +193,9 @@ int startWaveformClockCycles(uint8_t pin, uint32_t highCcys, uint32_t lowCcys,
193193
if (!waveform.timer1Running) {
194194
initTimer();
195195
}
196-
else if (T1L > IRQLATENCY + DELTAIRQ) {
197-
// Must not interfere if Timer is due shortly, cluster phases to reduce interrupt load
198-
timer1_write(microsecondsToClockCycles(1));
196+
else if (((CPU2X & 1) ? T1V << 1 : T1V) > IRQLATENCYCCYS + DELTAIRQCCYS) {
197+
// Must not interfere if Timer is due shortly
198+
timer1_write(CPU2X & 1 ? microsecondsToClockCycles(1) >> 1 : microsecondsToClockCycles(1));
199199
}
200200
}
201201
else {
@@ -228,8 +228,8 @@ int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
228228
if (waveform.enabled & (1UL << pin)) {
229229
waveform.toDisable = pin;
230230
// Must not interfere if Timer is due shortly
231-
if (T1L > IRQLATENCY + DELTAIRQ) {
232-
timer1_write(microsecondsToClockCycles(1));
231+
if (((CPU2X & 1) ? T1V << 1 : T1V) > IRQLATENCYCCYS + DELTAIRQCCYS) {
232+
timer1_write(CPU2X & 1 ? microsecondsToClockCycles(1) >> 1 : microsecondsToClockCycles(1));
233233
}
234234
std::atomic_thread_fence(std::memory_order_acq_rel);
235235
while (waveform.toDisable >= 0) {
@@ -243,6 +243,8 @@ int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
243243
return true;
244244
}
245245

246+
};
247+
246248
// Speed critical bits
247249
#pragma GCC optimize ("O2")
248250

@@ -296,7 +298,7 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
296298
bool busy;
297299
if (!waveform.enabled) {
298300
busy = false;
299-
waveform.nextEventCcy = ESP.getCycleCount() + MAXIRQCCYS;
301+
waveform.nextEventCcy = ESP.getCycleCount() + MAXIRQTICKSCCYS;
300302
}
301303
else {
302304
busy = static_cast<int32_t>(isrTimeoutCcy - waveform.nextEventCcy) > 0;
@@ -311,7 +313,7 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
311313
do {
312314
now = ESP.getCycleCount();
313315
} while (static_cast<int32_t>(waveform.nextEventCcy - now) > 0);
314-
waveform.nextEventCcy = now + MAXIRQCCYS;
316+
waveform.nextEventCcy = now + MAXIRQTICKSCCYS;
315317
do {
316318
// If it's not on, ignore
317319
if (!(waveform.enabled & (1UL << pin)))
@@ -354,7 +356,7 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
354356
nextEdgeCcy = wave.endDutyCcy;
355357
}
356358
else if (wave.autoPwm && (overshootCcys << 6) > wave.periodCcys && wave.nextEventCcy == wave.endDutyCcy) {
357-
uint32_t adjPeriods = ((overshootCcys << 6) - 1) / wave.periodCcys;
359+
uint32_t adjPeriods = (overshootCcys << 6) / wave.periodCcys;
358360
wave.nextPeriodCcy += adjPeriods * wave.periodCcys;
359361
// adapt expiry such that it occurs during intended cycle
360362
if (WaveformMode::EXPIRES == wave.mode) {
@@ -431,24 +433,20 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
431433
}
432434

433435
// Firing timer too soon, the NMI occurs before ISR has returned.
434-
if (nextTimerCcys <= IRQLATENCY + DELTAIRQ) {
435-
nextTimerCcys = IRQLATENCY;
436+
if (nextTimerCcys <= IRQLATENCYCCYS + DELTAIRQCCYS) {
437+
nextTimerCcys = IRQLATENCYCCYS;
436438
}
437-
else if (nextTimerCcys >= MAXIRQCCYS) {
438-
nextTimerCcys = MAXIRQCCYS - DELTAIRQ;
439+
else if (nextTimerCcys >= MAXIRQTICKSCCYS + DELTAIRQCCYS) {
440+
nextTimerCcys = MAXIRQTICKSCCYS;
439441
}
440442
else {
441-
nextTimerCcys -= DELTAIRQ;
443+
nextTimerCcys -= DELTAIRQCCYS;
442444
}
443445

444-
// Do it here instead of global function to save time and because we know it's edge-IRQ
445-
if (CPU2X & 1) {
446-
T1L = nextTimerCcys >> 1;
447-
}
448-
else {
449-
T1L = nextTimerCcys;
450-
}
446+
// Register access is fast and edge IRQ was configured before.
447+
// Timer is 80MHz fixed. 160MHz binaries need scaling,
448+
// 80MHz binaries in 160MHz boost (SDK) need NMI scaling
449+
// to maintain duty/idle ratio.
450+
T1L = CPU2X & 1 ? nextTimerCcys >> 1 : nextTimerCcys;
451451
TEIE |= TEIE1; // Edge int enable
452452
}
453-
454-
};

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.