From 9c81c0ab536c7ca185f887294412ac262d894d90 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 16 Mar 2026 14:54:20 -1000 Subject: [PATCH] [esp32] Add sram1_as_iram option for +40KB IRAM on original ESP32 Add a new `sram1_as_iram` option under `esp32 > framework > advanced` that enables CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM, reclaiming 40KB of SRAM1 memory as additional IRAM on the original ESP32. This requires a bootloader from ESP-IDF v5.1 or later. USB flashing updates the bootloader automatically, but OTA does not. At boot, ESPHome now detects the bootloader version and suggests enabling this option when the bootloader is compatible. --- esphome/components/esp32/__init__.py | 19 +++++++++++++++++++ esphome/core/application.cpp | 20 ++++++++++++++++++++ esphome/core/defines.h | 1 + 3 files changed, 40 insertions(+) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 18178c83ff..ef5ddad8a4 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -96,6 +96,7 @@ CONF_ENABLE_LWIP_ASSERT = "enable_lwip_assert" CONF_EXECUTE_FROM_PSRAM = "execute_from_psram" CONF_MINIMUM_CHIP_REVISION = "minimum_chip_revision" CONF_RELEASE = "release" +CONF_SRAM1_AS_IRAM = "sram1_as_iram" ARDUINO_FRAMEWORK_NAME = "framework-arduinoespressif32" ARDUINO_FRAMEWORK_PKG = f"pioarduino/{ARDUINO_FRAMEWORK_NAME}" @@ -882,6 +883,13 @@ def final_validate(config): path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_MINIMUM_CHIP_REVISION], ) ) + if config[CONF_VARIANT] != VARIANT_ESP32 and advanced[CONF_SRAM1_AS_IRAM]: + errs.append( + cv.Invalid( + f"'{CONF_SRAM1_AS_IRAM}' is only supported on {VARIANT_ESP32}", + path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_SRAM1_AS_IRAM], + ) + ) if ( config[CONF_VARIANT] != VARIANT_ESP32P4 and config.get(CONF_ENGINEERING_SAMPLE) is not None @@ -1129,6 +1137,7 @@ FRAMEWORK_SCHEMA = cv.Schema( cv.Optional(CONF_MINIMUM_CHIP_REVISION): cv.one_of( *ESP32_CHIP_REVISIONS ), + cv.Optional(CONF_SRAM1_AS_IRAM, default=False): cv.boolean, # DHCP server is needed for WiFi AP mode. When WiFi component is used, # it will handle disabling DHCP server when AP is not configured. # Default to false (disabled) when WiFi is not used. @@ -1595,6 +1604,16 @@ async def to_code(config): for rev, flag in ESP32_CHIP_REVISIONS.items(): add_idf_sdkconfig_option(flag, rev == min_rev) cg.add_define("USE_ESP32_MIN_CHIP_REVISION_SET") + + # Use SRAM1 region as IRAM on ESP32 (original) variant + # This provides an additional 40KB of IRAM by using SRAM1 memory that was previously + # reserved for bootloader DRAM. Requires a bootloader from ESP-IDF v5.1 or later. + # WARNING: If the device has an old bootloader (pre-v5.1), the app will fail to boot. + # A USB flash will update the bootloader automatically. OTA updates do not. + # See: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/performance/ram-usage.html + if variant == VARIANT_ESP32 and conf[CONF_ADVANCED][CONF_SRAM1_AS_IRAM]: + add_idf_sdkconfig_option("CONFIG_ESP_SYSTEM_ESP32_SRAM1_REGION_AS_IRAM", True) + cg.add_define("USE_ESP32_SRAM1_AS_IRAM") add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_SINGLE_APP", False) add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM", True) add_idf_sdkconfig_option("CONFIG_PARTITION_TABLE_CUSTOM_FILENAME", "partitions.csv") diff --git a/esphome/core/application.cpp b/esphome/core/application.cpp index 3a9e825e04..53289c1ac4 100644 --- a/esphome/core/application.cpp +++ b/esphome/core/application.cpp @@ -9,6 +9,13 @@ #endif #ifdef USE_ESP32 #include +#if defined(USE_ESP32_FRAMEWORK_ESP_IDF) +#include +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) +#include +#include +#endif +#endif #endif #ifdef USE_LWIP_FAST_SELECT #include "esphome/core/lwip_fast_select.h" @@ -249,6 +256,19 @@ void Application::process_dump_config_() { #endif } #endif +#if defined(USE_ESP32_VARIANT_ESP32) && defined(USE_ESP32_FRAMEWORK_ESP_IDF) && !defined(USE_ESP32_SRAM1_AS_IRAM) && \ + ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) + { + // Check if bootloader supports SRAM1 as IRAM (requires ESP-IDF >= 5.1 bootloader) + // esp_bootloader_desc_t is only available in ESP-IDF >= 5.2, but any bootloader + // from 5.2+ also supports SRAM1 as IRAM (which was introduced in 5.1) + esp_bootloader_desc_t boot_desc; + if (esp_ota_get_bootloader_description(nullptr, &boot_desc) == ESP_OK) { + ESP_LOGW(TAG, "Bootloader supports SRAM1 as IRAM (+40KB). " + "Set sram1_as_iram: true under esp32 > framework > advanced"); + } + } +#endif #endif } diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 390ac8ddd7..57a9d7a159 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -200,6 +200,7 @@ #define USE_ESPHOME_TASK_LOG_BUFFER #define USE_OTA_ROLLBACK #define USE_ESP32_MIN_CHIP_REVISION_SET +#define USE_ESP32_SRAM1_AS_IRAM #define USE_BLUETOOTH_PROXY #define BLUETOOTH_PROXY_MAX_CONNECTIONS 3