Merge remote-tracking branch 'origin/libretiny_millis_xtaskgettickcount' into integration

This commit is contained in:
J. Nick Koston
2026-04-22 07:35:50 +02:00
2 changed files with 40 additions and 4 deletions
+22 -1
View File
@@ -16,8 +16,29 @@ void loop();
namespace esphome {
void HOT yield() { ::yield(); }
// Skip the Arduino core's ::millis() wrapper so the public esphome::millis() is
// inlinable at its call sites and matches MillisInternal::get()'s fast path.
// IRAM_ATTR is kept because components (e.g. rotary_encoder) call millis() from
// ISR handlers; xTaskGetTickCountFromISR() is used in ISR context to satisfy the
// FreeRTOS API contract.
//
// RTL87xx and LN882x run FreeRTOS at 1 kHz, so xTaskGetTickCount() is already in
// milliseconds. BK72xx runs at 500 Hz — multiply by portTICK_PERIOD_MS (== 2) to
// convert ticks to milliseconds, matching the Arduino core's wiring.c.
#if defined(USE_RTL87XX) || defined(USE_LN882X)
uint32_t IRAM_ATTR HOT millis() {
static_assert(configTICK_RATE_HZ == 1000, "millis() fast path requires 1 kHz FreeRTOS tick");
return in_isr_context() ? xTaskGetTickCountFromISR() : xTaskGetTickCount();
}
#elif defined(USE_BK72XX)
uint32_t IRAM_ATTR HOT millis() {
// BK72xx's Arduino millis() does not dispatch on ISR context; match that.
return xTaskGetTickCount() * portTICK_PERIOD_MS;
}
#else
uint32_t IRAM_ATTR HOT millis() { return ::millis(); }
uint64_t millis_64() { return Millis64Impl::compute(::millis()); }
#endif
uint64_t millis_64() { return Millis64Impl::compute(millis()); }
uint32_t IRAM_ATTR HOT micros() { return ::micros(); }
void HOT delay(uint32_t ms) { ::delay(ms); }
void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { ::delayMicroseconds(us); }
+18 -3
View File
@@ -7,6 +7,9 @@
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <sdkconfig.h>
#elif defined(USE_LIBRETINY)
#include <FreeRTOS.h>
#include <task.h>
#endif
namespace esphome {
@@ -14,10 +17,11 @@ namespace esphome {
// Friend-gated accessor for a fast millis() variant intended only for
// known task-context callers on the main loop hot path (Application::loop()
// and WarnIfComponentBlockingGuard::finish()). It skips the ISR-context
// dispatch that the public esphome::millis() pays on ESP32.
// dispatch that the public esphome::millis() pays on ESP32 and libretiny.
//
// MUST NOT be called from ISR context: on ESP32 it calls the non-FromISR
// FreeRTOS API directly, which is undefined behavior in ISR context.
// MUST NOT be called from ISR context: on ESP32 and libretiny it calls the
// non-FromISR FreeRTOS API directly, which is undefined behavior in ISR
// context.
//
// Adding new callers requires adding a friend declaration here — that
// is the review point. Do not relax the access (e.g. by making get()
@@ -31,6 +35,17 @@ class MillisInternal {
static ESPHOME_ALWAYS_INLINE uint32_t get() {
#if defined(USE_ESP32) && CONFIG_FREERTOS_HZ == 1000
return xTaskGetTickCount();
#elif defined(USE_LIBRETINY) && (defined(USE_RTL87XX) || defined(USE_LN882X))
// RTL87xx and LN882x run FreeRTOS at 1 kHz, so xTaskGetTickCount() is
// already in milliseconds.
static_assert(configTICK_RATE_HZ == 1000, "MillisInternal fast path requires 1 kHz FreeRTOS tick");
return xTaskGetTickCount();
#elif defined(USE_BK72XX)
// BK72xx runs FreeRTOS at 500 Hz; scale ticks by portTICK_PERIOD_MS (== 2).
// Inlined here because esphome::millis() on BK72xx has no-op IRAM_ATTR but
// is still out-of-line, so calling it would cost a real function call.
static_assert(configTICK_RATE_HZ == 500, "BK72xx MillisInternal assumes 500 Hz FreeRTOS tick");
return xTaskGetTickCount() * portTICK_PERIOD_MS;
#else
return millis();
#endif