diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index 8ce3458ea9c..c97e4a5eb1d 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -23,13 +23,20 @@ extern "C" __attribute__((weak)) void initArduino() {} namespace esphome { void HOT yield() { vPortYield(); } -// millis() is inlined in hal.h when CONFIG_FREERTOS_HZ == 1000 (just xTaskGetTickCount()). -// Fallback for non-standard tick rates. No IRAM_ATTR — the original IRAM placement was -// inherited from ESP8266 where Arduino's millis() is called from ISR handlers (Wiegand, -// ZyAura). ESPHome doesn't call millis() from ISR on ESP32. -#if CONFIG_FREERTOS_HZ != 1000 -uint32_t HOT millis() { return micros_to_millis(static_cast(esp_timer_get_time())); } +// Use xTaskGetTickCount() when tick rate is 1 kHz (ESPHome's default via sdkconfig), +// falling back to esp_timer for non-standard rates. IRAM_ATTR is required because +// Wiegand and ZyAura call millis() from IRAM_ATTR ISR handlers on ESP32. +// xTaskGetTickCountFromISR() is used in ISR context to satisfy the FreeRTOS API contract. +uint32_t IRAM_ATTR HOT millis() { +#if CONFIG_FREERTOS_HZ == 1000 + if (xPortInIsrContext()) [[unlikely]] { + return xTaskGetTickCountFromISR(); + } + return xTaskGetTickCount(); +#else + return micros_to_millis(static_cast(esp_timer_get_time())); #endif +} uint64_t HOT millis_64() { return micros_to_millis(static_cast(esp_timer_get_time())); } void HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); } diff --git a/esphome/core/hal.h b/esphome/core/hal.h index 3d615fd395f..03a30b7459f 100644 --- a/esphome/core/hal.h +++ b/esphome/core/hal.h @@ -28,23 +28,10 @@ #endif -// On ESP32 with 1 kHz FreeRTOS tick rate, millis() is just xTaskGetTickCount() — -// a single volatile read of a DRAM global. Inlining it here eliminates the -// function call entirely at every call site. No IRAM needed (no flash code -// executed), no 64-bit math, no HAL call. -#if defined(USE_ESP32) && CONFIG_FREERTOS_HZ == 1000 -#include -#include -#endif - namespace esphome { void yield(); -#if defined(USE_ESP32) && CONFIG_FREERTOS_HZ == 1000 -inline uint32_t millis() { return xTaskGetTickCount(); } -#else uint32_t millis(); -#endif uint64_t millis_64(); uint32_t micros(); void delay(uint32_t ms);