mirror of
https://github.com/wled/WLED.git
synced 2025-04-23 22:37:18 +00:00
Merge pull request #4244 from MoonModules/framerate_ac015
Improved framerate control code - strip.show(), strip.service()
This commit is contained in:
parent
b75a2de485
commit
f593d404cb
@ -75,7 +75,7 @@ static uint8_t soundAgc = 0; // Automagic gain control: 0 - n
|
||||
//static float volumeSmth = 0.0f; // either sampleAvg or sampleAgc depending on soundAgc; smoothed sample
|
||||
static float FFT_MajorPeak = 1.0f; // FFT: strongest (peak) frequency
|
||||
static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of peak frequency
|
||||
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
|
||||
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getFrameTime()
|
||||
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
|
||||
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
|
||||
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0};// Our calculated freq. channel result table to be used by effects
|
||||
@ -536,8 +536,8 @@ static void detectSamplePeak(void) {
|
||||
#endif
|
||||
|
||||
static void autoResetPeak(void) {
|
||||
uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay()); // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC
|
||||
if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed.
|
||||
uint16_t peakDelay = max(uint16_t(50), strip.getFrameTime());
|
||||
if (millis() - timeOfPeak > peakDelay) { // Auto-reset of samplePeak after at least one complete frame has passed.
|
||||
samplePeak = false;
|
||||
if (audioSyncEnabled == 0) udpSamplePeak = false; // this is normally reset by transmitAudioData
|
||||
}
|
||||
|
14
wled00/FX.h
14
wled00/FX.h
@ -46,6 +46,14 @@
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||
#define FRAMETIME strip.getFrameTime()
|
||||
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define MIN_FRAME_DELAY 3 // S2/C3 are slower than normal esp32, and only have one core
|
||||
#else
|
||||
#define MIN_FRAME_DELAY 8 // 8266 legacy MIN_SHOW_DELAY
|
||||
#endif
|
||||
#define FPS_UNLIMITED 0
|
||||
|
||||
// FPS calculation (can be defined as compile flag for debugging)
|
||||
#ifndef FPS_CALC_AVG
|
||||
@ -77,8 +85,6 @@
|
||||
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 ? 8 : 15)
|
||||
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT strip._segments[strip.getCurrSegmentId()]
|
||||
#define SEGENV strip._segments[strip.getCurrSegmentId()]
|
||||
@ -748,6 +754,7 @@ class WS2812FX { // 96 bytes
|
||||
customMappingTable(nullptr),
|
||||
customMappingSize(0),
|
||||
_lastShow(0),
|
||||
_lastServiceShow(0),
|
||||
_segment_index(0),
|
||||
_mainSegment(0)
|
||||
{
|
||||
@ -846,7 +853,7 @@ class WS2812FX { // 96 bytes
|
||||
getMappedPixelIndex(uint16_t index) const;
|
||||
|
||||
inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
|
||||
inline uint16_t getMinShowDelay() const { return MIN_SHOW_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
||||
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
|
||||
|
||||
@ -958,6 +965,7 @@ class WS2812FX { // 96 bytes
|
||||
uint16_t customMappingSize;
|
||||
|
||||
unsigned long _lastShow;
|
||||
unsigned long _lastServiceShow;
|
||||
|
||||
uint8_t _segment_index;
|
||||
uint8_t _mainSegment;
|
||||
|
@ -1304,7 +1304,14 @@ void WS2812FX::finalizeInit() {
|
||||
void WS2812FX::service() {
|
||||
unsigned long nowUp = millis(); // Be aware, millis() rolls over every 49 days
|
||||
now = nowUp + timebase;
|
||||
if (nowUp - _lastShow < MIN_SHOW_DELAY || _suspend) return;
|
||||
if (_suspend) return;
|
||||
unsigned long elapsed = nowUp - _lastServiceShow;
|
||||
|
||||
if (elapsed <= MIN_FRAME_DELAY) return; // keep wifi alive - no matter if triggered or unlimited
|
||||
if ( !_triggered && (_targetFps != FPS_UNLIMITED)) { // unlimited mode = no frametime
|
||||
if (elapsed < _frametime) return; // too early for service
|
||||
}
|
||||
|
||||
bool doShow = false;
|
||||
|
||||
_isServicing = true;
|
||||
@ -1321,7 +1328,7 @@ void WS2812FX::service() {
|
||||
if (!seg.isActive()) continue;
|
||||
|
||||
// last condition ensures all solid segments are updated at the same time
|
||||
if (nowUp > seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
|
||||
if (nowUp >= seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC))
|
||||
{
|
||||
doShow = true;
|
||||
unsigned frameDelay = FRAMETIME;
|
||||
@ -1371,15 +1378,16 @@ void WS2812FX::service() {
|
||||
_triggered = false;
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow effects %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
#endif
|
||||
if (doShow) {
|
||||
yield();
|
||||
Segment::handleRandomPalette(); // slowly transition random palette; move it into for loop when each segment has individual random palette
|
||||
show();
|
||||
_lastServiceShow = nowUp; // update timestamp, for precise FPS control
|
||||
}
|
||||
#ifdef WLED_DEBUG
|
||||
if (millis() - nowUp > _frametime) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
if ((_targetFps != FPS_UNLIMITED) && (millis() - nowUp > _frametime)) DEBUG_PRINTF_P(PSTR("Slow strip %u/%d.\n"), (unsigned)(millis()-nowUp), (int)_frametime);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1399,13 +1407,13 @@ void WS2812FX::show() {
|
||||
// avoid race condition, capture _callback value
|
||||
show_callback callback = _callback;
|
||||
if (callback) callback();
|
||||
unsigned long showNow = millis();
|
||||
|
||||
// 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
|
||||
BusManager::show();
|
||||
|
||||
unsigned long showNow = millis();
|
||||
size_t diff = showNow - _lastShow;
|
||||
|
||||
if (diff > 0) { // skip calculation if no time has passed
|
||||
@ -1433,8 +1441,9 @@ uint16_t WS2812FX::getFps() const {
|
||||
}
|
||||
|
||||
void WS2812FX::setTargetFps(uint8_t fps) {
|
||||
if (fps > 0 && fps <= 120) _targetFps = fps;
|
||||
_frametime = 1000 / _targetFps;
|
||||
if (fps <= 250) _targetFps = fps;
|
||||
if (_targetFps > 0) _frametime = 1000 / _targetFps;
|
||||
else _frametime = MIN_FRAME_DELAY; // unlimited mode
|
||||
}
|
||||
|
||||
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||
@ -1482,7 +1491,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
|
||||
BusManager::setBrightness(b);
|
||||
if (!direct) {
|
||||
unsigned long t = millis();
|
||||
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger(); //apply brightness change immediately if no refresh soon
|
||||
if (_segments[0].next_time > t + 22 && t - _lastShow > MIN_FRAME_DELAY) trigger(); //apply brightness change immediately if no refresh soon
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,6 +379,11 @@
|
||||
gId('psu').innerHTML = s;
|
||||
gId('psu2').innerHTML = s2;
|
||||
gId("json").style.display = d.Sf.IT.value==8 ? "" : "none";
|
||||
|
||||
// show/hide FPS warning messages
|
||||
gId('fpsNone').style.display = (d.Sf.FR.value == 0) ? 'block':'none';
|
||||
gId('fpsWarn').style.display = (d.Sf.FR.value == 0) || (d.Sf.FR.value >= 80) ? 'block':'none';
|
||||
gId('fpsHigh').style.display = (d.Sf.FR.value >= 80) ? 'block':'none';
|
||||
}
|
||||
function lastEnd(i) {
|
||||
if (i-- < 1) return 0;
|
||||
@ -869,7 +874,10 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
<option value="2">Linear (never wrap)</option>
|
||||
<option value="3">None (not recommended)</option>
|
||||
</select><br>
|
||||
Target refresh rate: <input type="number" class="s" min="1" max="120" name="FR" required> FPS
|
||||
Target refresh rate: <input type="number" class="s" min="0" max="250" name="FR" oninput="UI()" required> FPS
|
||||
<div id="fpsNone" class="warn" style="display: none;">⚠ Unlimited FPS Mode is experimental ⚠<br></div>
|
||||
<div id="fpsHigh" class="warn" style="display: none;">⚠ High FPS Mode is experimental.<br></div>
|
||||
<div id="fpsWarn" class="warn" style="display: none;">Please <a class="lnk" href="sec#backup">backup</a> WLED configuration and presets first!<br></div>
|
||||
<hr class="sml">
|
||||
<div id="cfg">Config template: <input type="file" name="data2" accept=".json"><button type="button" class="sml" onclick="loadCfg(d.Sf.data2)">Apply</button><br></div>
|
||||
<hr>
|
||||
|
@ -57,7 +57,7 @@
|
||||
<h3>Software Update</h3>
|
||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||
Enable ArduinoOTA: <input type="checkbox" name="AO">
|
||||
<hr>
|
||||
<hr id="backup">
|
||||
<h3>Backup & Restore</h3>
|
||||
<div class="warn">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||
Incorrect upload or configuration may require a factory reset or re-flashing of your ESP.<br>
|
||||
|
Loading…
x
Reference in New Issue
Block a user