Skip to content

Commit 1d2c939

Browse files
Avoid WDT errors, optimize pin scans
Calculate first and last pins to scan for PWM, significantly increasing accuracy for pulses under 10us at 80MHz. Now if you are using a single PWM channel at 80MHz you can generate a 1.125us pulse (down from ~4us). Rework the IRQ logic to avoid potential WDT errors. When at 80MHz it appears that interrupts occuring faster than 10us apart on the timer cause WDT errors. Avoid it by increasing the minimum delay between IRQs on the timer accordingly. Torture test below passed @ 80 and 160Mhz: void loop() { int pin = rand() % 8; int val = rand() % 1000; switch(pin) { case 0: pin = D1; break; case 1: pin = D2; break; case 2: pin = D3; break; case 3: pin = D4; break; case 4: pin = D5; break; case 5: pin = D6; break; case 6: pin = D7; break; case 7: pin = D8; break; } analogWrite(pin, val); delay(30); }
1 parent 409fc91 commit 1d2c939

File tree

1 file changed

+39
-31
lines changed

1 file changed

+39
-31
lines changed

cores/esp8266/core_esp8266_waveform.c

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,8 @@ int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t
119119
}
120120
Waveform *wave = &waveform[pin];
121121
// Adjust to shave off some of the IRQ time, approximately
122-
uint32_t delta = 0;
123-
#if F_CPU == 80000000
124-
if (timeHighUS > 2) {
125-
delta = MicrosecondsToCycles(1) + MicrosecondsToCycles(2)/3;
126-
}
127-
#else // 160000000
128-
delta = MicrosecondsToCycles(1) >> 1; // 0.5 us off each edge
129-
#endif
130-
wave->nextTimeHighCycles = MicrosecondsToCycles(timeHighUS) - delta;
131-
wave->nextTimeLowCycles = MicrosecondsToCycles(timeLowUS) - delta;
122+
wave->nextTimeHighCycles = MicrosecondsToCycles(timeHighUS);
123+
wave->nextTimeLowCycles = MicrosecondsToCycles(timeLowUS);
132124
wave->expiryCycle = runTimeUS ? GetCycleCount() + MicrosecondsToCycles(runTimeUS) : 0;
133125
if (runTimeUS && !wave->expiryCycle) {
134126
wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it
@@ -142,7 +134,7 @@ int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t
142134
if (!timerRunning) {
143135
initTimer();
144136
}
145-
timer1_write(MicrosecondsToCycles(1)); // Cause an interrupt post-haste
137+
timer1_write(MicrosecondsToCycles(10)); // Cause an interrupt post-haste
146138
while (waveformToEnable) {
147139
delay(0); // Wait for waveform to update
148140
}
@@ -159,7 +151,7 @@ int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t
159151

160152
static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ() {
161153
uint32_t ccount;
162-
__asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount));
154+
__asm__ __volatile__("rsr %0,ccount":"=a"(ccount));
163155
return ccount;
164156
}
165157

@@ -183,7 +175,10 @@ int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
183175
return false; //It's not running, nothing to do here
184176
}
185177
waveformToDisable |= mask;
186-
timer1_write(MicrosecondsToCycles(1));
178+
// Ensure tiomely service....
179+
if (T1L > MicrosecondsToCycles(10)) {
180+
timer1_write(MicrosecondsToCycles(10));
181+
}
187182
while (waveformToDisable) {
188183
delay(1); // Wait for IRQ to update
189184
}
@@ -194,25 +189,32 @@ int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) {
194189
}
195190

196191
#if F_CPU == 80000000
197-
#define MINCYCLE MicrosecondsToCycles(6)
198-
#define DELTAIRQ MicrosecondsToCycles(5)
192+
#define DELTAIRQ (MicrosecondsToCycles(3))
199193
#else
200-
#define MINCYCLE MicrosecondsToCycles(4)
201-
#define DELTAIRQ (MicrosecondsToCycles(2) + MicrosecondsToCycles(3)/4)
194+
#define DELTAIRQ (MicrosecondsToCycles(2))
202195
#endif
203196

204-
static ICACHE_RAM_ATTR void timer1Interrupt() {
205-
uint32_t nextEventCycles;
197+
static int startPin = 0;
198+
static int endPin = 0;
206199

207-
// Handle enable/disable requests from main app.
208-
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
209-
waveformState &= ~waveformToEnable; // And clear the state of any just started
210-
waveformToEnable = 0;
211-
waveformToDisable = 0;
200+
static ICACHE_RAM_ATTR void timer1Interrupt() {
201+
uint32_t nextEventCycles = MicrosecondsToCycles(MAXIRQUS);
202+
uint32_t timeoutCycle = GetCycleCountIRQ() + MicrosecondsToCycles(14);
203+
204+
if (waveformToEnable || waveformToDisable) {
205+
// Handle enable/disable requests from main app.
206+
waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off
207+
waveformState &= ~waveformToEnable; // And clear the state of any just started
208+
waveformToEnable = 0;
209+
waveformToDisable = 0;
210+
startPin = __builtin_ffs(waveformEnabled) - 1;
211+
endPin = 32 - __builtin_clz(waveformEnabled);
212+
}
212213

213-
do {
214+
bool done = false;
215+
if (waveformEnabled) do {
214216
nextEventCycles = MicrosecondsToCycles(MAXIRQUS);
215-
for (size_t i = 0; i <= 16; i++) {
217+
for (int i = startPin; i <= endPin; i++) {
216218
uint32_t mask = 1<<i;
217219

218220
// If it's not on, ignore!
@@ -257,21 +259,27 @@ static ICACHE_RAM_ATTR void timer1Interrupt() {
257259
nextEventCycles = min_u32(nextEventCycles, deltaCycles);
258260
}
259261
}
260-
} while (nextEventCycles < MINCYCLE);
262+
uint32_t now = GetCycleCountIRQ();
263+
done = false;
264+
int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles);
265+
if (cycleDeltaNextEvent < 0) done = true;
266+
int32_t cyclesLeftTimeout = timeoutCycle - now;
267+
if (cyclesLeftTimeout < 0) done = true;
268+
} while (!done);
261269

262270
if (timer1CB) {
263271
nextEventCycles = min_u32(nextEventCycles, timer1CB());
264-
if (nextEventCycles < MINCYCLE) {
265-
nextEventCycles = MINCYCLE;
266-
}
272+
}
273+
if (nextEventCycles < MicrosecondsToCycles(10)) {
274+
nextEventCycles = MicrosecondsToCycles(10);
267275
}
268276
nextEventCycles -= DELTAIRQ;
269277

270278
// Do it here instead of global function to save time and because we know it's edge-IRQ
271-
TEIE |= TEIE1; //edge int enable
272279
#if F_CPU == 160000000
273280
T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS
274281
#else
275282
T1L = nextEventCycles; // Already know we're in range by MAXIRQUS
276283
#endif
284+
TEIE |= TEIE1; //edge int enable
277285
}

0 commit comments

Comments
 (0)