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();