From 66998e173252c4c0a9e6e0e89010761f56ec9ff2 Mon Sep 17 00:00:00 2001 From: Paul Kendall Date: Sat, 23 Mar 2024 15:12:34 +1300 Subject: [PATCH] PWM testing/fixes (#2588) * Revert "Fix for 10KHz 0% and 100% on 8285 receviers (#2496)" This reverts commit 12659fb2b4dfb04154719f26e1b9ef2eef6a4b6c. * Much simpler handling of 0 high/low times * Optimisation of timing in PWM timer interrupt t * Extend minimum time for next NMI * Rename pin/i to gpio as thats what it really is. --- src/lib/PWM/PWM_ESP8266.cpp | 12 ++++----- src/lib/PWM/waveform_8266.cpp | 57 ++++++++++++++++++++----------------------- src/lib/PWM/waveform_8266.h | 4 +-- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/lib/PWM/PWM_ESP8266.cpp b/src/lib/PWM/PWM_ESP8266.cpp index 4b34f765..9a3bad57 100644 --- a/src/lib/PWM/PWM_ESP8266.cpp +++ b/src/lib/PWM/PWM_ESP8266.cpp @@ -43,15 +43,13 @@ void PWMController::setDuty(pwm_channel_t channel, uint16_t duty) void PWMController::setMicroseconds(pwm_channel_t channel, uint16_t microseconds) { int8_t pin = pwm_gpio[channel]; - if (microseconds > 0) { - startWaveform8266(pin, microseconds, refreshInterval[channel] - microseconds); - } - else { - // startWaveform8266 does not handle 0 properly, there's still a 1.2 microsecond pulse - // so we have to explicitly stop the waveform generation + if (microseconds == 0 || microseconds==refreshInterval[channel]) + { stopWaveform8266(pin); - digitalWrite(pin, LOW); + digitalWrite(pin, microseconds == 0 ? HIGH : LOW); + return; } + startWaveform8266(pin, microseconds, refreshInterval[channel] - microseconds); } #endif \ No newline at end of file diff --git a/src/lib/PWM/waveform_8266.cpp b/src/lib/PWM/waveform_8266.cpp index 8c5d851e..657b4570 100644 --- a/src/lib/PWM/waveform_8266.cpp +++ b/src/lib/PWM/waveform_8266.cpp @@ -93,7 +93,7 @@ static WVFState wvfState; #pragma GCC optimize ("Os") // Interrupt on/off control -static IRAM_ATTR void timer1Interrupt(); +static void timer1Interrupt(); static bool timerRunning = false; static __attribute__((noinline)) void initTimer() { @@ -127,13 +127,13 @@ static void disableIdleTimer() { // Start up a waveform on a pin, or change the current one. Will change to the new // waveform smoothly on next low->high transition. For immediate change, stopWaveform() // first, then it will immediately begin. -void startWaveform8266(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS) { - if ((pin > 16) || isFlashInterfacePin(pin)) { +void startWaveform8266(uint8_t gpio, uint32_t timeHighUS, uint32_t timeLowUS) { + if ((gpio > 16) || isFlashInterfacePin(gpio)) { return; } - Waveform *wave = &wvfState.waveform[pin]; + Waveform *wave = &wvfState.waveform[gpio]; - uint32_t mask = 1<nextHighLowUs = (timeHighUS << 16) | timeLowUS; @@ -157,14 +157,14 @@ void startWaveform8266(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS) { } // Stops a waveform on a pin -void stopWaveform8266(uint8_t pin) { +void stopWaveform8266(uint8_t gpio) { // Can't possibly need to stop anything if there is no timer active if (!timerRunning) { return; } // If user sends in a pin >16 but <32, this will always point to a 0 bit // If they send >=32, then the shift will result in 0 and it will also return false - uint32_t mask = 1<nextServiceCycle - now; @@ -257,20 +257,19 @@ static IRAM_ATTR void timer1Interrupt() { uint32_t desired = 0; uint32_t *timeToUpdate; wvfState.waveformState ^= mask; - if (wvfState.waveformState & mask && wave->nextHighLowUs != 0) { + if (wvfState.waveformState & mask) { + if (gpio == 16) { // Special handling for GPIO16 + GP16O = 1; + } + GPOS = mask; + + if (wave->nextHighLowUs != 0) { // Copy over next full-cycle timings uint32_t next = wave->nextHighLowUs; wave->nextHighLowUs = 0; // indicate the change has taken place wave->timeHighCycles = wave->desiredHighCycles = microsecondsToClockCycles(next >> 16); wave->timeLowCycles = wave->desiredLowCycles = microsecondsToClockCycles(next & 0xffff); wave->lastEdge = 0; - } - if (wvfState.waveformState & mask) { - if (wave->timeHighCycles != 0) { - if (i == 16) { - GP16O = 1; - } - GPOS = mask; } if (wave->lastEdge) { desired = wave->desiredLowCycles; @@ -278,12 +277,10 @@ static IRAM_ATTR void timer1Interrupt() { } nextEdgeCycles = wave->timeHighCycles; } else { - if (wave->timeLowCycles != 0) { - if (i == 16) { - GP16O = 0; - } - GPOC = mask; + if (gpio == 16) { // Special handling for GPIO16 + GP16O = 0; } + GPOC = mask; desired = wave->desiredHighCycles; timeToUpdate = &wave->timeHighCycles; nextEdgeCycles = wave->timeLowCycles; @@ -304,14 +301,14 @@ static IRAM_ATTR void timer1Interrupt() { } // Exit the loop if we've hit the fixed runtime limit or the next event is known to be after that timeout would occur - uint32_t now = GetCycleCountIRQ(); + now = GetCycleCountIRQ(); int32_t cycleDeltaNextEvent = nextEventCycle - now; int32_t cyclesLeftTimeout = timeoutCycle - now; - done = (cycleDeltaNextEvent > MINIRQTIME) || (cyclesLeftTimeout < 0); + done = (cycleDeltaNextEvent > cyclesLeftTimeout) || (cyclesLeftTimeout < 0); } while (!done); } // if (wvfState.waveformEnabled) - int32_t nextEventCycles = nextEventCycle - GetCycleCountIRQ(); + int32_t nextEventCycles = nextEventCycle - now; if (nextEventCycles < MINIRQTIME) { nextEventCycles = MINIRQTIME; diff --git a/src/lib/PWM/waveform_8266.h b/src/lib/PWM/waveform_8266.h index 91f8c9c4..5cde2ea0 100644 --- a/src/lib/PWM/waveform_8266.h +++ b/src/lib/PWM/waveform_8266.h @@ -1,7 +1,7 @@ #pragma once -void startWaveform8266(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS); -void stopWaveform8266(uint8_t pin); +void startWaveform8266(uint8_t gpio, uint32_t timeHighUS, uint32_t timeLowUS); +void stopWaveform8266(uint8_t gpio); #define startWaveform DO_NOT_USE #define startWaveformClockCycles DO_NOT_USE -- 2.11.4.GIT