From 7c0ecdf7c44a115eeca7cd6624af7139368f0b06 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:51:12 +0100 Subject: [PATCH] make "target FPS" work --- wled00/FX.h | 8 +++++--- wled00/FX_fcn.cpp | 37 ++++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index cec8e5d2..c8a9d539 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -43,13 +43,14 @@ bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented #endif /* Not used in all effects yet */ +#define FPS_UNLIMITED 249 #if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_FASTPATH) // WLEDMM go faster on ESP32 #define WLED_FPS 120 #define FRAMETIME_FIXED (strip.getFrameTime() < 10 ? 12 : 24) #define WLED_FPS_SLOW 60 #define FRAMETIME_FIXED_SLOW (15) // = 66 FPS => 1000/66 -//#define FRAMETIME _frametime #define FRAMETIME strip.getFrameTime() +#define MIN_SHOW_DELAY (max(2, (_frametime*5)/8)) // WLEDMM support higher framerates (up to 250fps) -- 5/8 = 62% #else #define WLED_FPS 42 #define FRAMETIME_FIXED (1000/WLED_FPS) @@ -57,6 +58,7 @@ bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented #define FRAMETIME_FIXED_SLOW (1000/WLED_FPS_SLOW) //#define FRAMETIME _frametime #define FRAMETIME strip.getFrameTime() +#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) #endif /* each segment uses 52 bytes of SRAM memory, so if you're application fails because of @@ -82,8 +84,6 @@ bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented assuming each segment uses the same amount of data. 256 for ESP8266, 640 for ESP32. */ #define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / strip.getMaxSegments()) -#define MIN_SHOW_DELAY (_frametime < 16 ? (_frametime <8? (_frametime <7? (_frametime <6 ? 2 :3) :4) : 8) : 15) // WLEDMM support higher framerates (up to 250fps) - #define NUM_COLORS 3 /* number of colors per segment */ #define SEGMENT strip._segments[strip.getCurrSegmentId()] #define SEGENV strip._segments[strip.getCurrSegmentId()] @@ -852,6 +852,7 @@ class WS2812FX { // 96 bytes customMappingTableSize(0), //WLEDMM customMappingSize(0), _lastShow(0), + _lastServiceShow(0), _segment_index(0), _mainSegment(0) { @@ -1097,6 +1098,7 @@ class WS2812FX { // 96 bytes uint16_t customMappingSize; /*uint32_t*/ unsigned long _lastShow; // WLEDMM avoid losing precision + unsigned long _lastServiceShow; // WLEDMM last call of strip.show (timestamp) uint8_t _segment_index; uint8_t _mainSegment; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 54c21b63..6760c2c2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1873,13 +1873,19 @@ void WS2812FX::service() { if (OTAisRunning) return; // WLEDMM avoid flickering during OTA now = nowUp + timebase; - #if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_FASTPATH) - if ((_frametime > 2) && (_frametime < 32) && (nowUp - _lastShow) < (_frametime/2)) return; // WLEDMM experimental - stabilizes frametimes but increases CPU load - else if (nowUp - _lastShow < MIN_SHOW_DELAY) return; // WLEDMM fallback - #else - if (nowUp - _lastShow < MIN_SHOW_DELAY) return; + unsigned long elapsed = nowUp - _lastServiceShow; + #if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_FASTPATH) // WLEDMM go faster on ESP32 + //if (_suspend) return; + if (elapsed < 2) return; // keep wifi alive + if ( !_triggered && (_targetFps < FPS_UNLIMITED) && (_targetFps > 0)) { + if (elapsed < MIN_SHOW_DELAY) return; // WLEDMM too early for service + } + #else // legacy + if (elapsed < MIN_SHOW_DELAY) return; #endif + bool doShow = false; + unsigned speedLimit = (_targetFps < FPS_UNLIMITED) ? (0.85f * FRAMETIME) : 1; // WLEDMM lower limit for effect frametime _isServicing = true; _segment_index = 0; @@ -1914,6 +1920,8 @@ void WS2812FX::service() { // actual code may be a bit more involved as effects have runtime data including allocated memory //if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress()); frameDelay = (*_mode[seg.currentMode(seg.mode)])(); + + if (frameDelay < speedLimit) frameDelay = FRAMETIME; // WLEDMM limit effects that want to go faster than target FPS if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++; if (seg.transitional && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition @@ -1929,6 +1937,7 @@ void WS2812FX::service() { if(doShow) { yield(); show(); + _lastServiceShow = nowUp; // WLEDMM use correct timestamp } _triggered = false; _isServicing = false; @@ -2053,25 +2062,30 @@ void WS2812FX::show(void) { estimateCurrentAndLimitBri(); #if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_FASTPATH) - unsigned long b4show = millis(); // WLEDMM the time before calling "show" + unsigned long now = millis(); + #ifdef ARDUINO_ARCH_ESP32 // WLEDMM more accurate FPS measurement for ESP32 + uint64_t now500 = esp_timer_get_time() / 2; // native timer; micros /2 -> millis * 500 #endif + #endif + // some buses send asynchronously and this method will return before // all of the data has been sent. // See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods busses.show(); unsigned long now = millis(); + #ifdef ARDUINO_ARCH_ESP32 // WLEDMM more accurate FPS measurement for ESP32 + uint64_t now500 = esp_timer_get_time() / 2; // native timer; micros /2 -> millis * 500 + #endif + #endif + unsigned long diff = now - _lastShow; uint16_t fpsCurr = 200; if (diff > 0) fpsCurr = 1000 / diff; _cumulativeFps = (3 * _cumulativeFps + fpsCurr +2) >> 2; // "+2" for proper rounding (2/4 = 0.5) - #if defined(ARDUINO_ARCH_ESP32) && defined(WLEDMM_FASTPATH) - _lastShow = b4show; // WLEDMM this is more accurate, however it also increases CPU load - strip.service will run more frequently - #else _lastShow = now; - #endif + _lastServiceShow = now; #ifdef ARDUINO_ARCH_ESP32 // WLEDMM more accurate FPS measurement for ESP32 - uint64_t now500 = esp_timer_get_time() / 2; // native timer; micros /2 -> millis * 500 int64_t diff500 = now500 - _lastShow500; if ((diff500 > 300) && (diff500 < 800000)) { // exclude stupid values (timer rollover, major hickups) float fpcCurr500 = 500000.0f / float(diff500); @@ -2107,6 +2121,7 @@ void WS2812FX::setTargetFps(uint8_t fps) { if (fps > 0 && fps <= 251) _targetFps = fps; // WLEDMM allow higher framerates _frametime = 1000 / _targetFps; if (_frametime < 1) _frametime = 1; // WLEDMM better safe than sorry + if (fps >= FPS_UNLIMITED) _frametime = 3; // WLEDMM unlimited mode } void WS2812FX::setMode(uint8_t segid, uint8_t m) {