diff --git a/cores/esp8266/core_esp8266_waveform.cpp b/cores/esp8266/core_esp8266_waveform.cpp index 597a8e88ab..0338dbc952 100644 --- a/cores/esp8266/core_esp8266_waveform.cpp +++ b/cores/esp8266/core_esp8266_waveform.cpp @@ -170,6 +170,13 @@ static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) { return b; } +static inline ICACHE_RAM_ATTR int32_t max_32(int32_t a, int32_t b) { + if (a < b) { + return b; + } + return a; +} + // Stops a waveform on a pin int ICACHE_RAM_ATTR stopWaveform(uint8_t pin) { // Can't possibly need to stop anything if there is no timer active @@ -259,6 +266,17 @@ static ICACHE_RAM_ATTR void timer1Interrupt() { // Check for toggles int32_t cyclesToGo = wave->nextServiceCycle - now; if (cyclesToGo < 0) { + // See #7057 + // The following is a no-op unless we have overshot by an entire waveform cycle. + // As modulus is an expensive operation, this code is removed for now: + // cyclesToGo = -((-cyclesToGo) % (wave->nextTimeHighCycles + wave->nextTimeLowCycles)); + // + // Alternative version with lower CPU impact: + // while (-cyclesToGo > wave->nextTimeHighCycles + wave->nextTimeLowCycles) { cyclesToGo += wave->nextTimeHighCycles + wave->nextTimeLowCycles); } + // + // detect interrupt storm, for example during wifi connection. + // if we overshoot the cycle by more than 25%, we forget phase and keep PWM duration + int32_t overshoot = ((uint32_t)-cyclesToGo) > ((wave->nextTimeHighCycles + wave->nextTimeLowCycles) >> 2); waveformState ^= mask; if (waveformState & mask) { if (i == 16) { @@ -266,16 +284,26 @@ static ICACHE_RAM_ATTR void timer1Interrupt() { } else { SetGPIO(mask); } - wave->nextServiceCycle = now + wave->nextTimeHighCycles; - nextEventCycles = min_u32(nextEventCycles, wave->nextTimeHighCycles); + if (overshoot) { + wave->nextServiceCycle = now + wave->nextTimeHighCycles; + nextEventCycles = min_u32(nextEventCycles, wave->nextTimeHighCycles); + } else { + wave->nextServiceCycle += wave->nextTimeHighCycles; + nextEventCycles = min_u32(nextEventCycles, max_32(wave->nextTimeHighCycles + cyclesToGo, microsecondsToClockCycles(1))); + } } else { if (i == 16) { GP16O &= ~1; // GPIO16 write slow as it's RMW } else { ClearGPIO(mask); } - wave->nextServiceCycle = now + wave->nextTimeLowCycles; - nextEventCycles = min_u32(nextEventCycles, wave->nextTimeLowCycles); + if (overshoot) { + wave->nextServiceCycle = now + wave->nextTimeLowCycles; + nextEventCycles = min_u32(nextEventCycles, wave->nextTimeLowCycles); + } else { + wave->nextServiceCycle += wave->nextTimeLowCycles; + nextEventCycles = min_u32(nextEventCycles, max_32(wave->nextTimeLowCycles + cyclesToGo, microsecondsToClockCycles(1))); + } } } else { uint32_t deltaCycles = wave->nextServiceCycle - now;
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: