diff --git a/esphome/core/application.h b/esphome/core/application.h index 4baf24cd9d..541ec57ff1 100644 --- a/esphome/core/application.h +++ b/esphome/core/application.h @@ -633,6 +633,7 @@ class Application { esphome_lwip_wake_main_loop_from_isr(px_higher_priority_task_woken); } +#ifdef USE_ESP32 /// Wake the main event loop from any context (ISR, thread, or main loop). /// Detects the calling context and uses the appropriate FreeRTOS API. static void IRAM_ATTR wake_loop_any_context() { esphome_lwip_wake_main_loop_any_context(); } @@ -642,6 +643,13 @@ class Application { static void IRAM_ATTR wake_loop_any_context() { socket::socket_wake(); } #endif #endif +#endif + +#if defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP) + /// Wake the main event loop from any context (ISR, thread, or main loop). + /// On ESP8266: sets the socket wake flag and calls esp_schedule() to exit esp_delay() early. + static void IRAM_ATTR wake_loop_any_context() { socket::socket_wake(); } +#endif #if defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP) /// Wake the main event loop from any context (ISR, thread, or main loop). diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index 2d03c7d4d7..ea49e8c39e 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -328,7 +328,7 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() { // This method is thread and ISR-safe because: // 1. Only performs simple assignments to volatile variables (atomic on all platforms) // 2. No read-modify-write operations that could be interrupted - // 3. No memory allocation or object construction; the only call (wake_loop_any_context) is ISR-safe + // 3. No memory allocation or object construction; on ESP32 the only call (wake_loop_any_context) is ISR-safe // 4. IRAM_ATTR ensures code is in IRAM, not flash (required for ISR execution) // 5. Components are never destroyed, so no use-after-free concerns // 6. App is guaranteed to be initialized before any ISR could fire @@ -336,11 +336,10 @@ void IRAM_ATTR HOT Component::enable_loop_soon_any_context() { // 8. Race condition with main loop is handled by clearing flag before processing this->pending_enable_loop_ = true; App.has_pending_enable_loop_requests_ = true; -#if defined(USE_LWIP_FAST_SELECT) || (defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP)) +#if (defined(USE_LWIP_FAST_SELECT) && defined(USE_ESP32)) || (defined(USE_ESP8266) && defined(USE_SOCKET_IMPL_LWIP_TCP)) // Wake the main loop from sleep. Without this, the main loop would not // wake until the select/delay timeout expires (~16ms). - // ESP32/LibreTiny: uses platform-specific context detection (xPortInIsrContext - // or IPSR register) to choose the correct FreeRTOS notify API. + // ESP32: uses xPortInIsrContext() to choose the correct FreeRTOS notify API. // ESP8266: sets socket wake flag and calls esp_schedule() to exit esp_delay() early. Application::wake_loop_any_context(); #endif diff --git a/esphome/core/lwip_fast_select.c b/esphome/core/lwip_fast_select.c index a3cc6ab8fe..989f66e9be 100644 --- a/esphome/core/lwip_fast_select.c +++ b/esphome/core/lwip_fast_select.c @@ -239,26 +239,11 @@ void IRAM_ATTR esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task } // Wake the main loop from any context (ISR, thread, or main loop). -// Detects ISR context and delegates to the appropriate variant: -// ESP32 (Xtensa/RISC-V): xPortInIsrContext() — checks interrupt nesting counter -// LibreTiny (ARM Cortex-M): IPSR register read via inline asm (0 = task context) -#ifdef USE_LIBRETINY -// Read the ARM Cortex-M IPSR register directly via inline asm. -// Avoids depending on CMSIS __get_IPSR() which may not be declared/available -// in all LibreTiny chip family toolchains (e.g. beken-72xx). -static inline IRAM_ATTR uint32_t esphome_get_ipsr(void) { - uint32_t ipsr = 0; - __asm volatile("mrs %0, ipsr" : "=r"(ipsr)); - return ipsr; -} -#endif - -void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void) { +// ESP32-only: uses xPortInIsrContext() to detect ISR context. +// LibreTiny is excluded because it lacks IRAM_ATTR support needed for ISR-safe paths. #ifdef USE_ESP32 +void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void) { if (xPortInIsrContext()) { -#else - if (esphome_get_ipsr() != 0) { -#endif int px_higher_priority_task_woken = 0; esphome_lwip_wake_main_loop_from_isr(&px_higher_priority_task_woken); portYIELD_FROM_ISR(px_higher_priority_task_woken); @@ -266,5 +251,6 @@ void IRAM_ATTR esphome_lwip_wake_main_loop_any_context(void) { esphome_lwip_wake_main_loop(); } } +#endif #endif // USE_LWIP_FAST_SELECT diff --git a/esphome/core/lwip_fast_select.h b/esphome/core/lwip_fast_select.h index ded0590359..6fce34fd76 100644 --- a/esphome/core/lwip_fast_select.h +++ b/esphome/core/lwip_fast_select.h @@ -34,8 +34,11 @@ void esphome_lwip_wake_main_loop(void); void esphome_lwip_wake_main_loop_from_isr(int *px_higher_priority_task_woken); /// Wake the main loop task from any context (ISR, thread, or main loop). -/// Detects the calling context and uses the appropriate FreeRTOS API. +/// ESP32-only: uses xPortInIsrContext() to detect ISR context. +/// LibreTiny lacks IRAM_ATTR support needed for ISR-safe paths. +#ifdef USE_ESP32 void esphome_lwip_wake_main_loop_any_context(void); +#endif #ifdef __cplusplus }