[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.
This commit is contained in:
J. Nick Koston
2026-04-11 22:56:59 -10:00
parent dff6199fc8
commit 325d9db499
+11 -1
View File
@@ -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() {