Restrict wake_loop_any_context to ESP32 only

LibreTiny lacks IRAM_ATTR support needed for ISR-safe paths,
and BK72xx doesn't support the mrs ipsr instruction in Thumb mode.
The existing fast select functionality on LibreTiny is unaffected.
This commit is contained in:
J. Nick Koston
2026-02-28 16:32:05 -10:00
parent fcb21998f8
commit fde32555dc
4 changed files with 13 additions and 30 deletions
+2
View File
@@ -510,10 +510,12 @@ 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(); }
#endif
#endif
#endif
protected:
+3 -5
View File
@@ -315,7 +315,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
@@ -323,12 +323,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;
#ifdef USE_LWIP_FAST_SELECT
#if defined(USE_LWIP_FAST_SELECT) && defined(USE_ESP32)
// Wake the main loop if sleeping in ulTaskNotifyTake(). Without this,
// the main loop would not wake until the select timeout expires (~16ms).
// Uses platform-specific context detection to choose the correct notify
// API (task vs ISR), e.g. xPortInIsrContext() on ESP32 or IPSR register
// on LibreTiny — safe from any calling context.
// Uses xPortInIsrContext() to choose the correct FreeRTOS notify API.
Application::wake_loop_any_context();
#endif
}
+4 -24
View File
@@ -239,38 +239,18 @@ 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);
#ifdef USE_ESP32
// On ESP32, explicitly request context switch if a higher-priority task was woken.
// On LibreTiny (ARM Cortex-M), portYIELD_FROM_ISR is not available — FreeRTOS
// sets the PendSV bit internally when needed, so the switch happens automatically
// when the ISR returns.
portYIELD_FROM_ISR(px_higher_priority_task_woken);
#endif
} else {
esphome_lwip_wake_main_loop();
}
}
#endif
#endif // USE_LWIP_FAST_SELECT
+4 -1
View File
@@ -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
}