This is an automated email from the ASF dual-hosted git repository.

fdcavalcanti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 3d30272ce7f arch/xtensa/espressif: initialize the HR Timer from the 
Wi-Fi init path
3d30272ce7f is described below

commit 3d30272ce7f88fb9545dead669717901cf22bf8e
Author: Ricard Rosson <[email protected]>
AuthorDate: Tue Aug 11 09:17:59 2026 +0100

    arch/xtensa/espressif: initialize the HR Timer from the Wi-Fi init path
    
    The Espressif Wi-Fi stack cannot work unless the esp_timer subsystem has
    been initialized, but nothing in the Wi-Fi code does that: it is left to
    each board's bringup to call esp_hr_timer_init() first.  Any board that
    does not happen to make that call dies on the first RF enable.
    
    The dependency is not visible from the Wi-Fi sources.  The path is:
    
      board_wlan_init() -> esp_wlan_sta_initialize() -> esp_wlan_initialize()
        -> esp_wifi_initialize() -> esp_wifi_api_adapter_init()
    
    and later, when the radio is first powered up:
    
      esp_phy_enable_wrapper() -> esp_phy_enable() (esp-hal-3rdparty,
      components/esp_phy/src/phy_init.c) -> phy_track_pll_init()
      (components/esp_phy/src/phy_common.c)
    
    phy_track_pll_init() calls esp_timer_create() and
    esp_timer_start_periodic() wrapped in ESP_ERROR_CHECK().  Both return
    ESP_ERR_INVALID_STATE while esp_timer is uninitialized, because the HAL's
    own esp_timer_init_os() startup hook is compiled out on NuttX
    (#ifndef __NuttX__ in components/esp_timer/src/esp_timer.c), so the timer
    task and the timer ISR only ever get created from NuttX's
    esp_hr_timer_init() -> esp_timer_init().
    
    Initialize the HR Timer at the top of esp_wifi_api_adapter_init(), where
    the requirement actually originates.  esp_hr_timer_init() is idempotent
    (it early-returns once the subsystem is up), so boards that already call
    it during bringup are unaffected.  Also make ESPRESSIF_WIRELESS select
    ESPRESSIF_HR_TIMER explicitly instead of inheriting it through the
    deprecated ESP32{,S2,S3}_RT_TIMER symbols, so the timer adapter is
    guaranteed to be built whenever the radio is.
    
    This is deliberately limited to Xtensa.  The RISC-V common-espressif tree
    has the same unenforced dependency, but nothing is broken there today: its
    ESPRESSIF_WIRELESS already selects both ESPRESSIF_HR_TIMER and RTC_DRIVER,
    and esp_rtc.c initializes the timer.  The mirror change can follow from
    someone able to test it on RISC-V hardware.
    
    This was diagnosed on an out-of-tree ESP32-S3 board whose bringup lacked
    the call.  The failure gives no panic output at all and looks exactly like
    a CPU lockup: the system tick stops, the console dies mid-line and USB
    stays enumerated but unresponsive.  It was tracked down with ROM-level
    ets_printf() breadcrumbs along the init path plus a high-priority thread
    that busy-waits on ets_delay_us(): the breadcrumb trail ends inside
    phy_track_pll_init() and never reaches the print after it, and the
    busy-wait thread keeps printing while every sleep()-based thread stops
    waking, showing the tick is gone.  Initializing the timer ahead of Wi-Fi
    init makes the same image associate to an AP, obtain a DHCP lease and
    serve telnet.  Validated on ESP32-S3 silicon (240 MHz, no PSRAM, 16 MiB
    flash).
    
    esp32s3-devkit:wifi builds clean with the change.
    
    Signed-off-by: Ricard Rosson <[email protected]>
    Assisted-by: Claude Opus 5 (Claude Code)
---
 arch/xtensa/src/common/espressif/Kconfig        |  1 +
 arch/xtensa/src/common/espressif/esp_wifi_api.c | 19 +++++++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/xtensa/src/common/espressif/Kconfig 
b/arch/xtensa/src/common/espressif/Kconfig
index 527b2885672..599a1d3e84f 100644
--- a/arch/xtensa/src/common/espressif/Kconfig
+++ b/arch/xtensa/src/common/espressif/Kconfig
@@ -2045,6 +2045,7 @@ config ESPRESSIF_WIRELESS
        select ESP32_RNG if ARCH_CHIP_ESP32
        select ESP32_RT_TIMER if ARCH_CHIP_ESP32
        select ESP32_TIMER0 if ARCH_CHIP_ESP32
+       select ESPRESSIF_HR_TIMER
        ---help---
                Enable Wireless support
 
diff --git a/arch/xtensa/src/common/espressif/esp_wifi_api.c 
b/arch/xtensa/src/common/espressif/esp_wifi_api.c
index b9486093995..c90189828b1 100644
--- a/arch/xtensa/src/common/espressif/esp_wifi_api.c
+++ b/arch/xtensa/src/common/espressif/esp_wifi_api.c
@@ -34,6 +34,7 @@
 #include "esp_wifi.h"
 #include "esp_private/wifi.h"
 
+#include "esp_hr_timer.h"
 #include "esp_wifi_utils.h"
 #include "esp_wifi_api.h"
 
@@ -124,6 +125,24 @@ int esp_wifi_api_adapter_init(void)
   int ret;
   wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT();
 
+  /* Make sure the HR Timer (and, with it, the underlying esp_timer
+   * subsystem) is running before the radio is brought up.  The first RF
+   * enable reaches phy_track_pll_init(), which calls esp_timer_create() and
+   * esp_timer_start_periodic() inside an ESP_ERROR_CHECK().  Those calls
+   * only work once esp_timer_init() has created the timer task and
+   * installed the timer ISR, and that only happens from
+   * esp_hr_timer_init().  Doing it here keeps the Wi-Fi stack independent
+   * of whether a particular board's bringup code happens to have
+   * initialized the HR Timer.  The call is idempotent.
+   */
+
+  ret = esp_hr_timer_init();
+  if (ret < 0)
+    {
+      wlerr("Failed to initialize HR Timer error=%d\n", ret);
+      return ret;
+    }
+
   esp_wifi_lock(true);
 
   esp_evt_work_init();

Reply via email to