diff --git a/CHANGELOG.md b/CHANGELOG.md index dadc3c20..8decb2fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ ## WLED changelog +### Development versions after 0.10.0 release + +#### Build 2005090 + +- Default to ESP8266 Arduino core v2.7.1 in PlatformIO +- Fixed Preset Slot 16 always indicating as empty (#891) +- Disabled Alexa emulation by default (causes bootloop for some users) +- Added BWLT11 and SHOJO_PCB defines to NpbWrapper +- Merged pull request #898 adding Solid Glitter effect + ### WLED version 0.10.0 #### Build 2005030 diff --git a/platformio.ini b/platformio.ini index 492799df..32c438e3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -54,6 +54,7 @@ default_envs = d1_mini, esp01, esp01_1m_ota, esp32dev # arduino core 2.6.1 = platformIO 2.3.0 # arduino core 2.6.2 = platformIO 2.3.1 # arduino core 2.6.3 = platformIO 2.3.2 +# arduino core 2.7.0 = platformIO 2.5.0 # ------------------------------------------------------------------------------ arduino_core_2_3_0 = espressif8266@1.5.0 arduino_core_2_4_0 = espressif8266@1.6.0 @@ -65,13 +66,14 @@ arduino_core_2_5_2 = espressif8266@2.2.3 arduino_core_2_6_1 = espressif8266@2.3.0 arduino_core_2_6_2 = espressif8266@2.3.1 arduino_core_2_6_3 = espressif8266@2.3.3 +arduino_core_2_7_1 = espressif8266@2.5.1 # Development platforms arduino_core_develop = https://github.com/platformio/platform-espressif8266#develop arduino_core_git = https://github.com/platformio/platform-espressif8266#feature/stage -platform = ${common.arduino_core_2_4_2} -platform_latest = ${common.arduino_core_2_6_3} +# Platform to use for ESP8266 +platform_latest = ${common.arduino_core_2_7_1} # ------------------------------------------------------------------------------ # FLAGS: DEBUG @@ -245,7 +247,7 @@ build_flags = ${common.build_flags_esp8266} -D WLED_DISABLE_HUESYNC -D WLED_USE_ board = d1_mini platform = ${common.platform_latest} board_build.ldscript = ${common.ldscript_4m1m} -build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D SHOJO_PCB -D WLED_ENABLE_5CH_LEDS +build_flags = ${common.build_flags_esp8266} -D WLED_USE_ANALOG_LEDS -D WLED_USE_SHOJO_PCB -D WLED_ENABLE_5CH_LEDS # ------------------------------------------------------------------------------ # DEVELOPMENT BOARDS diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h index faee293a..8a3f9544 100644 --- a/wled00/NpbWrapper.h +++ b/wled00/NpbWrapper.h @@ -14,6 +14,8 @@ //#define WLED_USE_ANALOG_LEDS //Uncomment for using "dumb" PWM controlled LEDs (see pins below, default R: gpio5, G: 12, B: 15, W: 13) //#define WLED_USE_H801 //H801 controller. Please uncomment #define WLED_USE_ANALOG_LEDS as well //#define WLED_USE_5CH_LEDS //5 Channel H801 for cold and warm white +//#define WLED_USE_BWLT11 +//#define WLED_USE_SHOJO_PCB #ifndef BTNPIN #define BTNPIN 0 //button pin. Needs to have pullup (gpio0 recommended) @@ -62,7 +64,7 @@ #define GPIN 4 //G pin for analog LED strip #define BPIN 14 //B pin for analog LED strip #define WPIN 5 //W pin for analog LED strip - #elif defined(SHOJO_PCB) + #elif defined(WLED_USE_SHOJO_PCB) //PWM pins - to use with Shojo PCB (https://www.bastelbunker.de/esp-rgbww-wifi-led-controller-vbs-edition/) #define RPIN 14 //R pin for analog LED strip #define GPIN 4 //G pin for analog LED strip diff --git a/wled00/src/dependencies/arduino/core_esp8266_waveform.cpp b/wled00/src/dependencies/arduino/core_esp8266_waveform.cpp deleted file mode 100644 index 57b3c315..00000000 --- a/wled00/src/dependencies/arduino/core_esp8266_waveform.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - esp8266_waveform - General purpose waveform generation and control, - supporting outputs on all pins in parallel. - - Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. - - The core idea is to have a programmable waveform generator with a unique - high and low period (defined in microseconds). TIMER1 is set to 1-shot - mode and is always loaded with the time until the next edge of any live - waveforms. - - Up to one waveform generator per pin supported. - - Each waveform generator is synchronized to the ESP cycle counter, not the - timer. This allows for removing interrupt jitter and delay as the counter - always increments once per 80MHz clock. Changes to a waveform are - contiguous and only take effect on the next waveform transition, - allowing for smooth transitions. - - This replaces older tone(), analogWrite(), and the Servo classes. - - Everywhere in the code where "cycles" is used, it means ESP.getCycleTime() - cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz). - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifdef ESP8266 -#include -#include "ets_sys.h" -#include "core_esp8266_waveform.h" - -extern "C" { - -// Maximum delay between IRQs -#define MAXIRQUS (10000) - -// Set/clear GPIO 0-15 by bitmask -#define SetGPIO(a) do { GPOS = a; } while (0) -#define ClearGPIO(a) do { GPOC = a; } while (0) - -// Waveform generator can create tones, PWM, and servos -typedef struct { - uint32_t nextServiceCycle; // ESP cycle timer when a transition required - uint32_t expiryCycle; // For time-limited waveform, the cycle when this waveform must stop - uint32_t nextTimeHighCycles; // Copy over low->high to keep smooth waveform - uint32_t nextTimeLowCycles; // Copy over high->low to keep smooth waveform -} Waveform; - -static Waveform waveform[17]; // State of all possible pins -static volatile uint32_t waveformState = 0; // Is the pin high or low, updated in NMI so no access outside the NMI code -static volatile uint32_t waveformEnabled = 0; // Is it actively running, updated in NMI so no access outside the NMI code - -// Enable lock-free by only allowing updates to waveformState and waveformEnabled from IRQ service routine -static volatile uint32_t waveformToEnable = 0; // Message to the NMI handler to start a waveform on a inactive pin -static volatile uint32_t waveformToDisable = 0; // Message to the NMI handler to disable a pin from waveform generation - -static uint32_t (*timer1CB)() = NULL; - - -// Non-speed critical bits -#pragma GCC optimize ("Os") - -static inline ICACHE_RAM_ATTR uint32_t GetCycleCount() { - uint32_t ccount; - __asm__ __volatile__("esync; rsr %0,ccount":"=a"(ccount)); - return ccount; -} - -// Interrupt on/off control -static ICACHE_RAM_ATTR void timer1Interrupt(); -static bool timerRunning = false; - -static void initTimer() { - timer1_disable(); - ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL); - ETS_FRC_TIMER1_NMI_INTR_ATTACH(timer1Interrupt); - timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE); - timerRunning = true; -} - -static void ICACHE_RAM_ATTR deinitTimer() { - ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL); - timer1_disable(); - timer1_isr_init(); - timerRunning = false; -} - -// Set a callback. Pass in NULL to stop it -void setTimer1Callback(uint32_t (*fn)()) { - timer1CB = fn; - if (!timerRunning && fn) { - initTimer(); - timer1_write(microsecondsToClockCycles(1)); // Cause an interrupt post-haste - } else if (timerRunning && !fn && !waveformEnabled) { - deinitTimer(); - } -} - -// 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. -int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS) { - if ((pin > 16) || isFlashInterfacePin(pin)) { - return false; - } - Waveform *wave = &waveform[pin]; - // Adjust to shave off some of the IRQ time, approximately - wave->nextTimeHighCycles = microsecondsToClockCycles(timeHighUS); - wave->nextTimeLowCycles = microsecondsToClockCycles(timeLowUS); - wave->expiryCycle = runTimeUS ? GetCycleCount() + microsecondsToClockCycles(runTimeUS) : 0; - if (runTimeUS && !wave->expiryCycle) { - wave->expiryCycle = 1; // expiryCycle==0 means no timeout, so avoid setting it - } - - uint32_t mask = 1<nextServiceCycle = GetCycleCount() + microsecondsToClockCycles(1); - waveformToEnable |= mask; - if (!timerRunning) { - initTimer(); - timer1_write(microsecondsToClockCycles(10)); - } else { - // Ensure timely service.... - if (T1L > microsecondsToClockCycles(10)) { - timer1_write(microsecondsToClockCycles(10)); - } - } - while (waveformToEnable) { - delay(0); // Wait for waveform to update - } - } - - return true; -} - -// Speed critical bits -#pragma GCC optimize ("O2") -// Normally would not want two copies like this, but due to different -// optimization levels the inline attribute gets lost if we try the -// other version. - -static inline ICACHE_RAM_ATTR uint32_t GetCycleCountIRQ() { - uint32_t ccount; - __asm__ __volatile__("rsr %0,ccount":"=a"(ccount)); - return ccount; -} - -static inline ICACHE_RAM_ATTR uint32_t min_u32(uint32_t a, uint32_t b) { - if (a < b) { - return a; - } - return b; -} - -// 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 - if (!timerRunning) { - return false; - } - // 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< microsecondsToClockCycles(10)) { - timer1_write(microsecondsToClockCycles(10)); - } - while (waveformToDisable) { - /* no-op */ // Can't delay() since stopWaveform may be called from an IRQ - } - if (!waveformEnabled && !timer1CB) { - deinitTimer(); - } - return true; -} - -// The SDK and hardware take some time to actually get to our NMI code, so -// decrement the next IRQ's timer value by a bit so we can actually catch the -// real CPU cycle counter we want for the waveforms. -#if F_CPU == 80000000 - #define DELTAIRQ (microsecondsToClockCycles(3)) -#else - #define DELTAIRQ (microsecondsToClockCycles(2)) -#endif - - -static ICACHE_RAM_ATTR void timer1Interrupt() { - // Optimize the NMI inner loop by keeping track of the min and max GPIO that we - // are generating. In the common case (1 PWM) these may be the same pin and - // we can avoid looking at the other pins. - static int startPin = 0; - static int endPin = 0; - - uint32_t nextEventCycles = microsecondsToClockCycles(MAXIRQUS); - uint32_t timeoutCycle = GetCycleCountIRQ() + microsecondsToClockCycles(14); - - if (waveformToEnable || waveformToDisable) { - // Handle enable/disable requests from main app. - waveformEnabled = (waveformEnabled & ~waveformToDisable) | waveformToEnable; // Set the requested waveforms on/off - waveformState &= ~waveformToEnable; // And clear the state of any just started - waveformToEnable = 0; - waveformToDisable = 0; - // Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t) - startPin = __builtin_ffs(waveformEnabled) - 1; - // Find the last bit by subtracting off GCC's count-leading-zeros (no offset in this one) - endPin = 32 - __builtin_clz(waveformEnabled); - } - - bool done = false; - if (waveformEnabled) { - do { - nextEventCycles = microsecondsToClockCycles(MAXIRQUS); - for (int i = startPin; i <= endPin; i++) { - uint32_t mask = 1<expiryCycle) { - int32_t expiryToGo = wave->expiryCycle - now; - if (expiryToGo < 0) { - // Done, remove! - waveformEnabled &= ~mask; - if (i == 16) { - GP16O &= ~1; - } else { - ClearGPIO(mask); - } - continue; - } - } - - // 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)}; - waveformState ^= mask; - if (waveformState & mask) { - if (i == 16) { - GP16O |= 1; // GPIO16 write slow as it's RMW - } else { - SetGPIO(mask); - } - wave->nextServiceCycle = now + wave->nextTimeHighCycles + cyclesToGo; - nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeHighCycles + cyclesToGo, 1)); - } else { - if (i == 16) { - GP16O &= ~1; // GPIO16 write slow as it's RMW - } else { - ClearGPIO(mask); - } - wave->nextServiceCycle = now + wave->nextTimeLowCycles + cyclesToGo; - nextEventCycles = min_u32(nextEventCycles, min_u32(wave->nextTimeLowCycles + cyclesToGo, 1)); - } - } else { - uint32_t deltaCycles = wave->nextServiceCycle - now; - nextEventCycles = min_u32(nextEventCycles, deltaCycles); - } - } - - // 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(); - int32_t cycleDeltaNextEvent = timeoutCycle - (now + nextEventCycles); - int32_t cyclesLeftTimeout = timeoutCycle - now; - done = (cycleDeltaNextEvent < 0) || (cyclesLeftTimeout < 0); - } while (!done); - } // if (waveformEnabled) - - if (timer1CB) { - nextEventCycles = min_u32(nextEventCycles, timer1CB()); - } - - if (nextEventCycles < microsecondsToClockCycles(10)) { - nextEventCycles = microsecondsToClockCycles(10); - } - nextEventCycles -= DELTAIRQ; - - // Do it here instead of global function to save time and because we know it's edge-IRQ -#if F_CPU == 160000000 - T1L = nextEventCycles >> 1; // Already know we're in range by MAXIRQUS -#else - T1L = nextEventCycles; // Already know we're in range by MAXIRQUS -#endif - TEIE |= TEIE1; // Edge int enable -} - -}; -#endif diff --git a/wled00/src/dependencies/arduino/core_esp8266_waveform.h b/wled00/src/dependencies/arduino/core_esp8266_waveform.h deleted file mode 100644 index 24ce91fb..00000000 --- a/wled00/src/dependencies/arduino/core_esp8266_waveform.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - esp8266_waveform - General purpose waveform generation and control, - supporting outputs on all pins in parallel. - - Copyright (c) 2018 Earle F. Philhower, III. All rights reserved. - - The core idea is to have a programmable waveform generator with a unique - high and low period (defined in microseconds). TIMER1 is set to 1-shot - mode and is always loaded with the time until the next edge of any live - waveforms. - - Up to one waveform generator per pin supported. - - Each waveform generator is synchronized to the ESP cycle counter, not the - timer. This allows for removing interrupt jitter and delay as the counter - always increments once per 80MHz clock. Changes to a waveform are - contiguous and only take effect on the next waveform transition, - allowing for smooth transitions. - - This replaces older tone(), analogWrite(), and the Servo classes. - - Everywhere in the code where "cycles" is used, it means ESP.getCycleTime() - cycles, not TIMER1 cycles (which may be 2 CPU clocks @ 160MHz). - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include - -#ifndef __ESP8266_WAVEFORM_H -#define __ESP8266_WAVEFORM_H - -#ifdef __cplusplus -extern "C" { -#endif - -// Start or change a waveform of the specified high and low times on specific pin. -// If runtimeUS > 0 then automatically stop it after that many usecs. -// Returns true or false on success or failure. -int startWaveform(uint8_t pin, uint32_t timeHighUS, uint32_t timeLowUS, uint32_t runTimeUS); -// Stop a waveform, if any, on the specified pin. -// Returns true or false on success or failure. -int stopWaveform(uint8_t pin); - -// Add a callback function to be called on *EVERY* timer1 trigger. The -// callback returns the number of microseconds until the next desired call. -// However, since it is called every timer1 interrupt, it may be called -// again before this period. It should therefore use the ESP Cycle Counter -// to determine whether or not to perform an operation. -// Pass in NULL to disable the callback and, if no other waveforms being -// generated, stop the timer as well. -// Make sure the CB function has the ICACHE_RAM_ATTR decorator. -void setTimer1Callback(uint32_t (*fn)()); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/wled00/wled.h b/wled00/wled.h index c791f4ee..a2f4288d 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2005030 +#define VERSION 2005090 // ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.4.2 and the setting 512K(No SPIFFS). @@ -109,10 +109,10 @@ #include #endif -// remove flicker because PWM signal of RGB channels can become out of phase -#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266) - #include "src/dependencies/arduino/core_esp8266_waveform.h" -#endif +// remove flicker because PWM signal of RGB channels can become out of phase (part of core as of Arduino core v2.7.0) +//#if defined(WLED_USE_ANALOG_LEDS) && defined(ESP8266) +// #include "src/dependencies/arduino/core_esp8266_waveform.h" +//#endif // enable additional debug output #ifdef WLED_DEBUG @@ -216,7 +216,7 @@ WLED_GLOBAL bool notifyMacro _INIT(false); // send notifi WLED_GLOBAL bool notifyHue _INIT(true); // send notification if Hue light changes WLED_GLOBAL bool notifyTwice _INIT(false); // notifications use UDP: enable if devices don't sync reliably -WLED_GLOBAL bool alexaEnabled _INIT(true); // enable device discovery by Amazon Echo +WLED_GLOBAL bool alexaEnabled _INIT(false); // enable device discovery by Amazon Echo WLED_GLOBAL char alexaInvocationName[33] _INIT("Light"); // speech control name of device. Choose something voice-to-text can understand WLED_GLOBAL char blynkApiKey[36] _INIT(""); // Auth token for Blynk server. If empty, no connection will be made diff --git a/wled00/wled_eeprom.cpp b/wled00/wled_eeprom.cpp index 807d3a44..26871326 100644 --- a/wled00/wled_eeprom.cpp +++ b/wled00/wled_eeprom.cpp @@ -594,7 +594,7 @@ void savedToPresets() savedPresets &= ~(0x01 << (index-1)); } } - if (EEPROM.read(700) == 2) { + if (EEPROM.read(700) == 2 || EEPROM.read(700) == 3) { savedPresets |= 0x01 << 15; } else {