From 325d9db499c4a5b346cab750fa491f656eaaf3ea Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 11 Apr 2026 22:56:59 -1000 Subject: [PATCH] [esp8266] Replace delay() with yield loop to allow GC of original millis Arduino's ::delay() is implemented in core_esp8266_wiring.cpp alongside millis(). Because __delay calls millis() within the same compilation unit, --wrap=millis can't intercept that intra-object reference, which prevents the linker from garbage-collecting the original millis body (~80 bytes of IRAM). Replace esphome::delay() with a simple yield loop that uses our fast millis() accumulator. This has the same behavior as Arduino's delay: feeds the watchdog and processes SDK tasks via yield(), keeping WiFi alive. With __delay unreferenced, the linker can now GC both __delay and the original millis function. --- esphome/components/esp8266/core.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp8266/core.cpp b/esphome/components/esp8266/core.cpp index 0cbb4a008d..68ca8a903b 100644 --- a/esphome/components/esp8266/core.cpp +++ b/esphome/components/esp8266/core.cpp @@ -54,7 +54,17 @@ static uint32_t IRAM_ATTR HOT millis_accumulator() { } uint32_t IRAM_ATTR HOT millis() { return millis_accumulator(); } uint64_t millis_64() { return Millis64Impl::compute(millis()); } -void HOT delay(uint32_t ms) { ::delay(ms); } +// Avoid calling ::delay() which pulls in __delay from core_esp8266_wiring.cpp. +// __delay has an intra-object call to the original millis() that --wrap=millis +// can't intercept, preventing the linker from garbage-collecting the expensive +// original millis body (~80 bytes IRAM). This yield loop achieves the same +// behavior: feeds the watchdog, processes SDK tasks, keeps WiFi alive. +void HOT delay(uint32_t ms) { + uint32_t start = millis(); + while (millis() - start < ms) { + yield(); + } +} uint32_t IRAM_ATTR HOT micros() { return ::micros(); } void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); } void arch_restart() {