From e215fafebe082f09b7867fa6261d1d8ab4430b97 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 1 May 2025 18:28:07 +1000 Subject: [PATCH] [esp32, debug] Add ``cpu_frequency`` config option and debug sensor (#8542) --- esphome/components/debug/debug_component.cpp | 4 + esphome/components/debug/debug_component.h | 5 + esphome/components/debug/debug_esp32.cpp | 345 +++++------------- esphome/components/debug/sensor.py | 14 + esphome/components/esp32/__init__.py | 54 +++ esphome/components/esp32/core.cpp | 16 +- tests/components/debug/common.yaml | 17 + tests/components/debug/test.esp32-ard.yaml | 3 + tests/components/debug/test.esp32-c3-ard.yaml | 3 + tests/components/debug/test.esp32-idf.yaml | 12 + 10 files changed, 206 insertions(+), 267 deletions(-) diff --git a/esphome/components/debug/debug_component.cpp b/esphome/components/debug/debug_component.cpp index 7d25bf5472..fcded02ba5 100644 --- a/esphome/components/debug/debug_component.cpp +++ b/esphome/components/debug/debug_component.cpp @@ -25,6 +25,7 @@ void DebugComponent::dump_config() { #ifdef USE_SENSOR LOG_SENSOR(" ", "Free space on heap", this->free_sensor_); LOG_SENSOR(" ", "Largest free heap block", this->block_sensor_); + LOG_SENSOR(" ", "CPU frequency", this->cpu_frequency_sensor_); #if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) LOG_SENSOR(" ", "Heap fragmentation", this->fragmentation_sensor_); #endif // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2) @@ -86,6 +87,9 @@ void DebugComponent::update() { this->loop_time_sensor_->publish_state(this->max_loop_time_); this->max_loop_time_ = 0; } + if (this->cpu_frequency_sensor_ != nullptr) { + this->cpu_frequency_sensor_->publish_state(arch_get_cpu_freq_hz()); + } #endif // USE_SENSOR update_platform_(); diff --git a/esphome/components/debug/debug_component.h b/esphome/components/debug/debug_component.h index 608addb4a3..f887d52864 100644 --- a/esphome/components/debug/debug_component.h +++ b/esphome/components/debug/debug_component.h @@ -36,6 +36,9 @@ class DebugComponent : public PollingComponent { #ifdef USE_ESP32 void set_psram_sensor(sensor::Sensor *psram_sensor) { this->psram_sensor_ = psram_sensor; } #endif // USE_ESP32 + void set_cpu_frequency_sensor(sensor::Sensor *cpu_frequency_sensor) { + this->cpu_frequency_sensor_ = cpu_frequency_sensor; + } #endif // USE_SENSOR protected: uint32_t free_heap_{}; @@ -53,6 +56,7 @@ class DebugComponent : public PollingComponent { #ifdef USE_ESP32 sensor::Sensor *psram_sensor_{nullptr}; #endif // USE_ESP32 + sensor::Sensor *cpu_frequency_sensor_{nullptr}; #endif // USE_SENSOR #ifdef USE_ESP32 @@ -75,6 +79,7 @@ class DebugComponent : public PollingComponent { #endif // USE_TEXT_SENSOR std::string get_reset_reason_(); + std::string get_wakeup_cause_(); uint32_t get_free_heap_(); void get_device_info_(std::string &device_info); void update_platform_(); diff --git a/esphome/components/debug/debug_esp32.cpp b/esphome/components/debug/debug_esp32.cpp index 7367f54807..bc772a1d58 100644 --- a/esphome/components/debug/debug_esp32.cpp +++ b/esphome/components/debug/debug_esp32.cpp @@ -1,27 +1,15 @@ #include "debug_component.h" + #ifdef USE_ESP32 #include "esphome/core/log.h" +#include "esphome/core/hal.h" +#include #include #include #include #include -#if defined(USE_ESP32_VARIANT_ESP32) -#include -#elif defined(USE_ESP32_VARIANT_ESP32C2) -#include -#elif defined(USE_ESP32_VARIANT_ESP32C3) -#include -#elif defined(USE_ESP32_VARIANT_ESP32C6) -#include -#elif defined(USE_ESP32_VARIANT_ESP32S2) -#include -#elif defined(USE_ESP32_VARIANT_ESP32S3) -#include -#elif defined(USE_ESP32_VARIANT_ESP32H2) -#include -#endif #ifdef USE_ARDUINO #include #endif @@ -31,6 +19,67 @@ namespace debug { static const char *const TAG = "debug"; +// index by values returned by esp_reset_reason + +static const char *const RESET_REASONS[] = { + "unknown source", + "power-on event", + "external pin", + "software via esp_restart", + "exception/panic", + "interrupt watchdog", + "task watchdog", + "other watchdogs", + "exiting deep sleep mode", + "brownout", + "SDIO", + "USB peripheral", + "JTAG", + "efuse error", + "power glitch detected", + "CPU lock up", +}; + +std::string DebugComponent::get_reset_reason_() { + std::string reset_reason; + unsigned reason = esp_reset_reason(); + if (reason < sizeof(RESET_REASONS) / sizeof(RESET_REASONS[0])) { + reset_reason = RESET_REASONS[reason]; + } else { + reset_reason = "unknown source"; + } + ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); + return "Reset by " + reset_reason; +} + +static const char *const WAKEUP_CAUSES[] = { + "undefined", + "undefined", + "external signal using RTC_IO", + "external signal using RTC_CNTL", + "timer", + "touchpad", + "ULP program", + "GPIO", + "UART", + "WIFI", + "COCPU int", + "COCPU crash", + "BT", +}; + +std::string DebugComponent::get_wakeup_cause_() { + const char *wake_reason; + unsigned reason = esp_sleep_get_wakeup_cause(); + if (reason < sizeof(WAKEUP_CAUSES) / sizeof(WAKEUP_CAUSES[0])) { + wake_reason = WAKEUP_CAUSES[reason]; + } else { + wake_reason = "unknown source"; + } + ESP_LOGD(TAG, "Wakeup Reason: %s", wake_reason); + return wake_reason; +} + void DebugComponent::log_partition_info_() { ESP_LOGCONFIG(TAG, "Partition table:"); ESP_LOGCONFIG(TAG, " %-12s %-4s %-8s %-10s %-10s", "Name", "Type", "Subtype", "Address", "Size"); @@ -44,173 +93,16 @@ void DebugComponent::log_partition_info_() { esp_partition_iterator_release(it); } -std::string DebugComponent::get_reset_reason_() { - std::string reset_reason; - switch (esp_reset_reason()) { - case ESP_RST_POWERON: - reset_reason = "Reset due to power-on event"; - break; - case ESP_RST_EXT: - reset_reason = "Reset by external pin"; - break; - case ESP_RST_SW: - reset_reason = "Software reset via esp_restart"; - break; - case ESP_RST_PANIC: - reset_reason = "Software reset due to exception/panic"; - break; - case ESP_RST_INT_WDT: - reset_reason = "Reset (software or hardware) due to interrupt watchdog"; - break; - case ESP_RST_TASK_WDT: - reset_reason = "Reset due to task watchdog"; - break; - case ESP_RST_WDT: - reset_reason = "Reset due to other watchdogs"; - break; - case ESP_RST_DEEPSLEEP: - reset_reason = "Reset after exiting deep sleep mode"; - break; - case ESP_RST_BROWNOUT: - reset_reason = "Brownout reset (software or hardware)"; - break; - case ESP_RST_SDIO: - reset_reason = "Reset over SDIO"; - break; -#ifdef USE_ESP32_VARIANT_ESP32 -#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 4)) - case ESP_RST_USB: - reset_reason = "Reset by USB peripheral"; - break; - case ESP_RST_JTAG: - reset_reason = "Reset by JTAG"; - break; - case ESP_RST_EFUSE: - reset_reason = "Reset due to efuse error"; - break; - case ESP_RST_PWR_GLITCH: - reset_reason = "Reset due to power glitch detected"; - break; - case ESP_RST_CPU_LOCKUP: - reset_reason = "Reset due to CPU lock up (double exception)"; - break; -#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 4) -#endif // USE_ESP32_VARIANT_ESP32 - default: // Includes ESP_RST_UNKNOWN - switch (rtc_get_reset_reason(0)) { - case POWERON_RESET: - reset_reason = "Power On Reset"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case SW_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || \ - defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) - case RTC_SW_SYS_RESET: -#endif - reset_reason = "Software Reset Digital Core"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case OWDT_RESET: - reset_reason = "Watch Dog Reset Digital Core"; - break; -#endif - case DEEPSLEEP_RESET: - reset_reason = "Deep Sleep Reset Digital Core"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case SDIO_RESET: - reset_reason = "SLC Module Reset Digital Core"; - break; -#endif - case TG0WDT_SYS_RESET: - reset_reason = "Timer Group 0 Watch Dog Reset Digital Core"; - break; -#if !defined(USE_ESP32_VARIANT_ESP32C2) - case TG1WDT_SYS_RESET: - reset_reason = "Timer Group 1 Watch Dog Reset Digital Core"; - break; -#endif - case RTCWDT_SYS_RESET: - reset_reason = "RTC Watch Dog Reset Digital Core"; - break; -#if !defined(USE_ESP32_VARIANT_ESP32C6) && !defined(USE_ESP32_VARIANT_ESP32H2) - case INTRUSION_RESET: - reset_reason = "Intrusion Reset CPU"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32) - case TGWDT_CPU_RESET: - reset_reason = "Timer Group Reset CPU"; - break; -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || \ - defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) - case TG0WDT_CPU_RESET: - reset_reason = "Timer Group 0 Reset CPU"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32) - case SW_CPU_RESET: -#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || \ - defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) - case RTC_SW_CPU_RESET: -#endif - reset_reason = "Software Reset CPU"; - break; - case RTCWDT_CPU_RESET: - reset_reason = "RTC Watch Dog Reset CPU"; - break; -#if defined(USE_ESP32_VARIANT_ESP32) - case EXT_CPU_RESET: - reset_reason = "External CPU Reset"; - break; -#endif - case RTCWDT_BROWN_OUT_RESET: - reset_reason = "Voltage Unstable Reset"; - break; - case RTCWDT_RTC_RESET: - reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module"; - break; -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \ - defined(USE_ESP32_VARIANT_ESP32C6) - case TG1WDT_CPU_RESET: - reset_reason = "Timer Group 1 Reset CPU"; - break; - case SUPER_WDT_RESET: - reset_reason = "Super Watchdog Reset Digital Core And RTC Module"; - break; - case EFUSE_RESET: - reset_reason = "eFuse Reset Digital Core"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) - case GLITCH_RTC_RESET: - reset_reason = "Glitch Reset Digital Core And RTC Module"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32C6) - case USB_UART_CHIP_RESET: - reset_reason = "USB UART Reset Digital Core"; - break; - case USB_JTAG_CHIP_RESET: - reset_reason = "USB JTAG Reset Digital Core"; - break; -#endif -#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3) - case POWER_GLITCH_RESET: - reset_reason = "Power Glitch Reset Digital Core And RTC Module"; - break; -#endif - default: - reset_reason = "Unknown Reset Reason"; - } - break; - } - ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str()); - return reset_reason; -} - uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); } +static const std::map CHIP_FEATURES = { + {CHIP_FEATURE_BLE, "BLE"}, + {CHIP_FEATURE_BT, "BT"}, + {CHIP_FEATURE_EMB_FLASH, "EMB Flash"}, + {CHIP_FEATURE_EMB_PSRAM, "EMB PSRAM"}, + {CHIP_FEATURE_WIFI_BGN, "2.4GHz WiFi"}, +}; + void DebugComponent::get_device_info_(std::string &device_info) { #if defined(USE_ARDUINO) const char *flash_mode; @@ -246,46 +138,16 @@ void DebugComponent::get_device_info_(std::string &device_info) { esp_chip_info_t info; esp_chip_info(&info); - const char *model; -#if defined(USE_ESP32_VARIANT_ESP32) - model = "ESP32"; -#elif defined(USE_ESP32_VARIANT_ESP32C2) - model = "ESP32-C2"; -#elif defined(USE_ESP32_VARIANT_ESP32C3) - model = "ESP32-C3"; -#elif defined(USE_ESP32_VARIANT_ESP32C6) - model = "ESP32-C6"; -#elif defined(USE_ESP32_VARIANT_ESP32S2) - model = "ESP32-S2"; -#elif defined(USE_ESP32_VARIANT_ESP32S3) - model = "ESP32-S3"; -#elif defined(USE_ESP32_VARIANT_ESP32H2) - model = "ESP32-H2"; -#else - model = "UNKNOWN"; -#endif + const char *model = ESPHOME_VARIANT; std::string features; - if (info.features & CHIP_FEATURE_EMB_FLASH) { - features += "EMB_FLASH,"; - info.features &= ~CHIP_FEATURE_EMB_FLASH; + for (auto feature : CHIP_FEATURES) { + if (info.features & feature.first) { + features += feature.second; + features += ", "; + info.features &= ~feature.first; + } } - if (info.features & CHIP_FEATURE_WIFI_BGN) { - features += "WIFI_BGN,"; - info.features &= ~CHIP_FEATURE_WIFI_BGN; - } - if (info.features & CHIP_FEATURE_BLE) { - features += "BLE,"; - info.features &= ~CHIP_FEATURE_BLE; - } - if (info.features & CHIP_FEATURE_BT) { - features += "BT,"; - info.features &= ~CHIP_FEATURE_BT; - } - if (info.features & CHIP_FEATURE_EMB_PSRAM) { - features += "EMB_PSRAM,"; - info.features &= ~CHIP_FEATURE_EMB_PSRAM; - } - if (info.features) + if (info.features != 0) features += "Other:" + format_hex(info.features); ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores, info.revision); @@ -295,6 +157,8 @@ void DebugComponent::get_device_info_(std::string &device_info) { device_info += features; device_info += " Cores:" + to_string(info.cores); device_info += " Revision:" + to_string(info.revision); + device_info += str_sprintf("|CPU Frequency: %" PRIu32 " MHz", arch_get_cpu_freq_hz() / 1000000); + ESP_LOGD(TAG, "CPU Frequency: %" PRIu32 " MHz", arch_get_cpu_freq_hz() / 1000000); // Framework detection device_info += "|Framework: "; @@ -321,50 +185,7 @@ void DebugComponent::get_device_info_(std::string &device_info) { device_info += "|Reset: "; device_info += get_reset_reason_(); - const char *wakeup_reason; - switch (rtc_get_wakeup_cause()) { - case NO_SLEEP: - wakeup_reason = "No Sleep"; - break; - case EXT_EVENT0_TRIG: - wakeup_reason = "External Event 0"; - break; - case EXT_EVENT1_TRIG: - wakeup_reason = "External Event 1"; - break; - case GPIO_TRIG: - wakeup_reason = "GPIO"; - break; - case TIMER_EXPIRE: - wakeup_reason = "Wakeup Timer"; - break; - case SDIO_TRIG: - wakeup_reason = "SDIO"; - break; - case MAC_TRIG: - wakeup_reason = "MAC"; - break; - case UART0_TRIG: - wakeup_reason = "UART0"; - break; - case UART1_TRIG: - wakeup_reason = "UART1"; - break; -#if !defined(USE_ESP32_VARIANT_ESP32C2) - case TOUCH_TRIG: - wakeup_reason = "Touch"; - break; -#endif - case SAR_TRIG: - wakeup_reason = "SAR"; - break; - case BT_TRIG: - wakeup_reason = "BT"; - break; - default: - wakeup_reason = "Unknown"; - } - ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason); + std::string wakeup_reason = this->get_wakeup_cause_(); device_info += "|Wakeup: "; device_info += wakeup_reason; } diff --git a/esphome/components/debug/sensor.py b/esphome/components/debug/sensor.py index 0a23658907..4669095d5d 100644 --- a/esphome/components/debug/sensor.py +++ b/esphome/components/debug/sensor.py @@ -1,5 +1,6 @@ import esphome.codegen as cg from esphome.components import sensor +from esphome.components.esp32 import CONF_CPU_FREQUENCY import esphome.config_validation as cv from esphome.const import ( CONF_BLOCK, @@ -10,6 +11,7 @@ from esphome.const import ( ICON_COUNTER, ICON_TIMER, UNIT_BYTES, + UNIT_HERTZ, UNIT_MILLISECOND, UNIT_PERCENT, ) @@ -60,6 +62,14 @@ CONFIG_SCHEMA = { entity_category=ENTITY_CATEGORY_DIAGNOSTIC, ), ), + cv.Optional(CONF_CPU_FREQUENCY): cv.All( + sensor.sensor_schema( + unit_of_measurement=UNIT_HERTZ, + icon="mdi:speedometer", + accuracy_decimals=0, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + ), } @@ -85,3 +95,7 @@ async def to_code(config): if psram_conf := config.get(CONF_PSRAM): sens = await sensor.new_sensor(psram_conf) cg.add(debug_component.set_psram_sensor(sens)) + + if cpu_freq_conf := config.get(CONF_CPU_FREQUENCY): + sens = await sensor.new_sensor(cpu_freq_conf) + cg.add(debug_component.set_cpu_frequency_sensor(sens)) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 307766ff94..12d0f9fcd5 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +import itertools import logging import os from pathlib import Path @@ -37,6 +38,7 @@ from esphome.const import ( __version__, ) from esphome.core import CORE, HexInt, TimePeriod +from esphome.cpp_generator import RawExpression import esphome.final_validate as fv from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed @@ -54,6 +56,12 @@ from .const import ( # noqa KEY_SUBMODULES, KEY_VARIANT, VARIANT_ESP32, + VARIANT_ESP32C2, + VARIANT_ESP32C3, + VARIANT_ESP32C6, + VARIANT_ESP32H2, + VARIANT_ESP32S2, + VARIANT_ESP32S3, VARIANT_FRIENDLY, VARIANTS, ) @@ -70,7 +78,43 @@ CONF_RELEASE = "release" CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES = "enable_idf_experimental_features" +def get_cpu_frequencies(*frequencies): + return [str(x) + "MHZ" for x in frequencies] + + +CPU_FREQUENCIES = { + VARIANT_ESP32: get_cpu_frequencies(80, 160, 240), + VARIANT_ESP32S2: get_cpu_frequencies(80, 160, 240), + VARIANT_ESP32S3: get_cpu_frequencies(80, 160, 240), + VARIANT_ESP32C2: get_cpu_frequencies(80, 120), + VARIANT_ESP32C3: get_cpu_frequencies(80, 160), + VARIANT_ESP32C6: get_cpu_frequencies(80, 120, 160), + VARIANT_ESP32H2: get_cpu_frequencies(16, 32, 48, 64, 96), +} + +# Make sure not missed here if a new variant added. +assert all(v in CPU_FREQUENCIES for v in VARIANTS) + +FULL_CPU_FREQUENCIES = set(itertools.chain.from_iterable(CPU_FREQUENCIES.values())) + + def set_core_data(config): + cpu_frequency = config.get(CONF_CPU_FREQUENCY, None) + variant = config[CONF_VARIANT] + # if not specified in config, set to 160MHz if supported, the fastest otherwise + if cpu_frequency is None: + choices = CPU_FREQUENCIES[variant] + if "160MHZ" in choices: + cpu_frequency = "160MHZ" + else: + cpu_frequency = choices[-1] + config[CONF_CPU_FREQUENCY] = cpu_frequency + elif cpu_frequency not in CPU_FREQUENCIES[variant]: + raise cv.Invalid( + f"Invalid CPU frequency '{cpu_frequency}' for {config[CONF_VARIANT]}", + path=[CONF_CPU_FREQUENCY], + ) + CORE.data[KEY_ESP32] = {} CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_ESP32 conf = config[CONF_FRAMEWORK] @@ -83,6 +127,7 @@ def set_core_data(config): CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse( config[CONF_FRAMEWORK][CONF_VERSION] ) + CORE.data[KEY_ESP32][KEY_BOARD] = config[CONF_BOARD] CORE.data[KEY_ESP32][KEY_VARIANT] = config[CONF_VARIANT] CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES] = {} @@ -553,11 +598,15 @@ FLASH_SIZES = [ ] CONF_FLASH_SIZE = "flash_size" +CONF_CPU_FREQUENCY = "cpu_frequency" CONF_PARTITIONS = "partitions" CONFIG_SCHEMA = cv.All( cv.Schema( { cv.Required(CONF_BOARD): cv.string_strict, + cv.Optional(CONF_CPU_FREQUENCY): cv.one_of( + *FULL_CPU_FREQUENCIES, upper=True + ), cv.Optional(CONF_FLASH_SIZE, default="4MB"): cv.one_of( *FLASH_SIZES, upper=True ), @@ -598,6 +647,7 @@ async def to_code(config): os.path.join(os.path.dirname(__file__), "post_build.py.script"), ) + freq = config[CONF_CPU_FREQUENCY][:-3] if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: cg.add_platformio_option("framework", "espidf") cg.add_build_flag("-DUSE_ESP_IDF") @@ -631,6 +681,9 @@ async def to_code(config): add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0", False) add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1", False) + # Set default CPU frequency + add_idf_sdkconfig_option(f"CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_{freq}", True) + cg.add_platformio_option("board_build.partitions", "partitions.csv") if CONF_PARTITIONS in config: add_extra_build_file( @@ -696,6 +749,7 @@ async def to_code(config): f"VERSION_CODE({framework_ver.major}, {framework_ver.minor}, {framework_ver.patch})" ), ) + cg.add(RawExpression(f"setCpuFrequencyMhz({freq})")) APP_PARTITION_SIZES = { diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index ff8e663ec1..c90d68d00e 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -13,11 +13,13 @@ #include #ifdef USE_ARDUINO -#include -#endif +#include +#else +#include void setup(); void loop(); +#endif namespace esphome { @@ -59,9 +61,13 @@ uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); } uint32_t arch_get_cpu_cycle_count() { return cpu_hal_get_cycle_count(); } #endif uint32_t arch_get_cpu_freq_hz() { - rtc_cpu_freq_config_t config; - rtc_clk_cpu_freq_get_config(&config); - return config.freq_mhz * 1000000U; + uint32_t freq = 0; +#ifdef USE_ESP_IDF + esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_CPU, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &freq); +#elif defined(USE_ARDUINO) + freq = ESP.getCpuFreqMHz() * 1000000; +#endif + return freq; } #ifdef USE_ESP_IDF diff --git a/tests/components/debug/common.yaml b/tests/components/debug/common.yaml index 5845beaa80..a9d74e6865 100644 --- a/tests/components/debug/common.yaml +++ b/tests/components/debug/common.yaml @@ -1 +1,18 @@ debug: + +text_sensor: + - platform: debug + device: + name: "Device Info" + reset_reason: + name: "Reset Reason" + +sensor: + - platform: debug + free: + name: "Heap Free" + loop_time: + name: "Loop Time" + cpu_frequency: + name: "CPU Frequency" + diff --git a/tests/components/debug/test.esp32-ard.yaml b/tests/components/debug/test.esp32-ard.yaml index dade44d145..8e19a4d627 100644 --- a/tests/components/debug/test.esp32-ard.yaml +++ b/tests/components/debug/test.esp32-ard.yaml @@ -1 +1,4 @@ <<: !include common.yaml + +esp32: + cpu_frequency: 240MHz diff --git a/tests/components/debug/test.esp32-c3-ard.yaml b/tests/components/debug/test.esp32-c3-ard.yaml index dade44d145..7d43491862 100644 --- a/tests/components/debug/test.esp32-c3-ard.yaml +++ b/tests/components/debug/test.esp32-c3-ard.yaml @@ -1 +1,4 @@ <<: !include common.yaml + +esp32: + cpu_frequency: 80MHz diff --git a/tests/components/debug/test.esp32-idf.yaml b/tests/components/debug/test.esp32-idf.yaml index dade44d145..f7483a54b3 100644 --- a/tests/components/debug/test.esp32-idf.yaml +++ b/tests/components/debug/test.esp32-idf.yaml @@ -1 +1,13 @@ <<: !include common.yaml + +esp32: + cpu_frequency: 240MHz + +sensor: + - platform: debug + free: + name: "Heap Free" + psram: + name: "Free PSRAM" + +psram: