diff --git a/components/esp_phy/Kconfig b/components/esp_phy/Kconfig index 77c4d53b0d..ab8155eb98 100644 --- a/components/esp_phy/Kconfig +++ b/components/esp_phy/Kconfig @@ -74,6 +74,12 @@ menu "PHY" If enabled, when an error occurs while the PHY init data is updated, the program will terminate and restart. If not enabled, the PHY init data will not be updated when an error occurs. + + config ESP_PHY_RECORD_USED_TIME + bool "Record PHY used time" + default n + help + Select to support record and query phy used time. endif config ESP_PHY_MAX_WIFI_TX_POWER diff --git a/components/esp_phy/include/esp_phy_init.h b/components/esp_phy/include/esp_phy_init.h index 27041b4dae..119c27c68c 100644 --- a/components/esp_phy/include/esp_phy_init.h +++ b/components/esp_phy/include/esp_phy_init.h @@ -33,6 +33,7 @@ typedef enum { PHY_MODEM_WIFI = 1, /*!< PHY modem WIFI */ PHY_MODEM_BT = 2, /*!< PHY modem BT */ PHY_MODEM_IEEE802154 = 4, /*!< PHY modem IEEE802154 */ + PHY_MODEM_MAX, /*!< Don't use it. Used by ESP_PHY_MODEM_COUNT_MAX */ } esp_phy_modem_t; /** @@ -281,6 +282,23 @@ void phy_init_param_set(uint8_t param); */ void phy_wifi_enable_set(uint8_t enable); +#if CONFIG_ESP_PHY_RECORD_USED_TIME +/** + * @brief Get phy used time from different modem + * @param used_time pointer of variable to get used time, in microseconds + * @param modem modem type + * @return ESP_ERR_INVALID_ARG on incorrect modem type. + */ +esp_err_t phy_query_used_time(uint64_t *used_time, esp_phy_modem_t modem); + +/** + * @brief Clear phy used time for different modem + * @param modem modem type + * @return ESP_ERR_INVALID_ARG on incorrect modem type. + */ +esp_err_t phy_clear_used_time(esp_phy_modem_t modem); +#endif + #ifdef __cplusplus } #endif diff --git a/components/esp_phy/src/phy_init.c b/components/esp_phy/src/phy_init.c index 53b4780c59..3158573937 100644 --- a/components/esp_phy/src/phy_init.c +++ b/components/esp_phy/src/phy_init.c @@ -157,6 +157,60 @@ static phy_country_to_bin_type_t s_country_code_map_type_table[] = { {"US", ESP_PHY_INIT_DATA_TYPE_FCC}, }; #endif + +#if CONFIG_ESP_PHY_RECORD_USED_TIME +#define ESP_PHY_MODEM_COUNT_MAX (__builtin_ffs(PHY_MODEM_MAX - 1)) +#define ESP_PHY_IS_VALID_MODEM(modem) (__builtin_popcount(modem) == 1 && __builtin_ctz(modem) < ESP_PHY_MODEM_COUNT_MAX) + +static DRAM_ATTR struct { + uint64_t used_time; + uint64_t enabled_time; + uint64_t disabled_time; +} s_phy_rf_used_info[ESP_PHY_MODEM_COUNT_MAX]; + +static IRAM_ATTR void phy_record_time(bool enabled, esp_phy_modem_t modem) { + uint8_t index = __builtin_ctz(modem); + if (enabled) { + s_phy_rf_used_info[index].enabled_time = esp_timer_get_time(); + } else { + s_phy_rf_used_info[index].disabled_time = esp_timer_get_time(); + s_phy_rf_used_info[index].used_time += s_phy_rf_used_info[index].disabled_time - s_phy_rf_used_info[index].enabled_time; + } +} + +esp_err_t phy_query_used_time(uint64_t *used_time, esp_phy_modem_t modem) { + if (!ESP_PHY_IS_VALID_MODEM(modem)) { + return ESP_ERR_INVALID_ARG; + } + uint8_t index = __builtin_ctz(modem); + _lock_acquire(&s_phy_access_lock); + *used_time = s_phy_rf_used_info[index].used_time; + if (s_phy_rf_used_info[index].disabled_time < s_phy_rf_used_info[index].enabled_time) { + // phy is being used + *used_time += esp_timer_get_time() - s_phy_rf_used_info[index].enabled_time; + } + _lock_release(&s_phy_access_lock); + return ESP_OK; +} + +esp_err_t phy_clear_used_time(esp_phy_modem_t modem) { + if (!ESP_PHY_IS_VALID_MODEM(modem)) { + return ESP_ERR_INVALID_ARG; + } + uint8_t index = __builtin_ctz(modem); + _lock_acquire(&s_phy_access_lock); + if (s_phy_rf_used_info[index].enabled_time > s_phy_rf_used_info[index].disabled_time) { + // phy is being used + s_phy_rf_used_info[index].enabled_time = esp_timer_get_time(); + } else { + s_phy_rf_used_info[index].enabled_time = s_phy_rf_used_info[index].disabled_time; + } + s_phy_rf_used_info[index].used_time = 0; + _lock_release(&s_phy_access_lock); + return ESP_OK; +} +#endif + uint32_t IRAM_ATTR phy_enter_critical(void) { if (xPortInIsrContext()) { @@ -284,13 +338,18 @@ void esp_phy_enable(esp_phy_modem_t modem) phy_track_pll(); #endif +#if CONFIG_ESP_PHY_RECORD_USED_TIME + phy_record_time(true, modem); +#endif _lock_release(&s_phy_access_lock); } void esp_phy_disable(esp_phy_modem_t modem) { _lock_acquire(&s_phy_access_lock); - +#if CONFIG_ESP_PHY_RECORD_USED_TIME + phy_record_time(false, modem); +#endif phy_clr_modem_flag(modem); if (phy_get_modem_flag() == 0) { // ESP32 will track pll in the wifi/BT modem interrupt handler. diff --git a/components/esp_phy/src/phy_init_esp32hxx.c b/components/esp_phy/src/phy_init_esp32hxx.c index d0d3e2a20b..9ff88d452f 100644 --- a/components/esp_phy/src/phy_init_esp32hxx.c +++ b/components/esp_phy/src/phy_init_esp32hxx.c @@ -8,6 +8,7 @@ #include "freertos/portmacro.h" #include "esp_phy_init.h" #include "esp_private/phy.h" +#include "esp_timer.h" #if SOC_MODEM_CLOCK_IS_INDEPENDENT #include "esp_private/esp_modem_clock.h" @@ -23,6 +24,59 @@ static _lock_t s_phy_access_lock; /* Reference count of enabling PHY */ static bool s_phy_is_enabled = false; +#if CONFIG_ESP_PHY_RECORD_USED_TIME +#define ESP_PHY_MODEM_COUNT_MAX (__builtin_ffs(PHY_MODEM_MAX - 1)) +#define ESP_PHY_IS_VALID_MODEM(modem) (__builtin_popcount(modem) == 1 && __builtin_ctz(modem) < ESP_PHY_MODEM_COUNT_MAX) + +static DRAM_ATTR struct { + uint64_t used_time; + uint64_t enabled_time; + uint64_t disabled_time; +} s_phy_rf_used_info[ESP_PHY_MODEM_COUNT_MAX]; + +static IRAM_ATTR void phy_record_time(bool enabled, esp_phy_modem_t modem) { + uint8_t index = __builtin_ctz(modem); + if (enabled) { + s_phy_rf_used_info[index].enabled_time = esp_timer_get_time(); + } else { + s_phy_rf_used_info[index].disabled_time = esp_timer_get_time(); + s_phy_rf_used_info[index].used_time += s_phy_rf_used_info[index].disabled_time - s_phy_rf_used_info[index].enabled_time; + } +} + +esp_err_t phy_query_used_time(uint64_t *used_time, esp_phy_modem_t modem) { + if (!ESP_PHY_IS_VALID_MODEM(modem)) { + return ESP_ERR_INVALID_ARG; + } + uint8_t index = __builtin_ctz(modem); + _lock_acquire(&s_phy_access_lock); + *used_time = s_phy_rf_used_info[index].used_time; + if (s_phy_rf_used_info[index].disabled_time < s_phy_rf_used_info[index].enabled_time) { + // phy is being used + *used_time += esp_timer_get_time() - s_phy_rf_used_info[index].enabled_time; + } + _lock_release(&s_phy_access_lock); + return ESP_OK; +} + +esp_err_t phy_clear_used_time(esp_phy_modem_t modem) { + if (!ESP_PHY_IS_VALID_MODEM(modem)) { + return ESP_ERR_INVALID_ARG; + } + uint8_t index = __builtin_ctz(modem); + _lock_acquire(&s_phy_access_lock); + if (s_phy_rf_used_info[index].enabled_time > s_phy_rf_used_info[index].disabled_time) { + // phy is being used + s_phy_rf_used_info[index].enabled_time = esp_timer_get_time(); + } else { + s_phy_rf_used_info[index].enabled_time = s_phy_rf_used_info[index].disabled_time; + } + s_phy_rf_used_info[index].used_time = 0; + _lock_release(&s_phy_access_lock); + return ESP_OK; +} +#endif + uint32_t IRAM_ATTR phy_enter_critical(void) { if (xPortInIsrContext()) { @@ -64,13 +118,18 @@ void esp_phy_enable(esp_phy_modem_t modem) phy_set_modem_flag(modem); // Immediately track pll when phy enabled. phy_track_pll(); +#if CONFIG_ESP_PHY_RECORD_USED_TIME + phy_record_time(true, modem); +#endif _lock_release(&s_phy_access_lock); } void esp_phy_disable(esp_phy_modem_t modem) { _lock_acquire(&s_phy_access_lock); - +#if CONFIG_ESP_PHY_RECORD_USED_TIME + phy_record_time(false, modem); +#endif phy_clr_modem_flag(modem); if (phy_get_modem_flag() == 0) {