From 54ca41e60ced11b7931e83e8dd35b4c07c0aac49 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Sun, 5 Oct 2025 20:45:53 +0200 Subject: [PATCH 01/23] getFlashFrequencyMHz --- cores/esp32/chip-debug-report.cpp | 135 ++++++++++++++++++++++++++---- cores/esp32/chip-debug-report.h | 8 ++ 2 files changed, 125 insertions(+), 18 deletions(-) diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index 8592031ee3f..e3378edc65a 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -9,6 +9,7 @@ #include "soc/efuse_reg.h" #include "soc/rtc.h" #include "soc/spi_reg.h" +#include "soc/soc.h" #if CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/spi_flash.h" #endif @@ -16,6 +17,7 @@ #include "Arduino.h" #include "esp32-hal-periman.h" +#include "chip-debug-report.h" #define chip_report_printf log_printf @@ -138,25 +140,19 @@ static void printFlashInfo(void) { chip_report_printf(" Block Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.block_size, b2kb(g_rom_flashchip.block_size)); chip_report_printf(" Sector Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.sector_size, b2kb(g_rom_flashchip.sector_size)); chip_report_printf(" Page Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.page_size, b2kb(g_rom_flashchip.page_size)); - esp_image_header_t fhdr; - esp_flash_read(esp_flash_default_chip, (void *)&fhdr, ESP_FLASH_IMAGE_BASE, sizeof(esp_image_header_t)); - if (fhdr.magic == ESP_IMAGE_HEADER_MAGIC) { - uint32_t f_freq = 0; - switch (fhdr.spi_speed) { -#if CONFIG_IDF_TARGET_ESP32H2 - case 0x0: f_freq = 32; break; - case 0x2: f_freq = 16; break; - case 0xf: f_freq = 64; break; -#else - case 0x0: f_freq = 40; break; - case 0x1: f_freq = 26; break; - case 0x2: f_freq = 20; break; - case 0xf: f_freq = 80; break; -#endif - default: f_freq = fhdr.spi_speed; break; - } - chip_report_printf(" Bus Speed : %lu MHz\n", f_freq); + + // Runtime flash frequency detection from hardware registers + uint32_t actual_freq = getFlashFrequencyMHz(); + uint8_t source_freq = getFlashSourceFrequencyMHz(); + uint8_t divider = getFlashClockDivider(); + + chip_report_printf(" Bus Speed : %lu MHz\n", actual_freq); + chip_report_printf(" Flash Frequency : %lu MHz (source: %u MHz, divider: %u)\n", actual_freq, source_freq, divider); + + if (isFlashHighPerformanceModeEnabled()) { + chip_report_printf(" HPM Mode : Enabled (> 80 MHz)\n"); } + chip_report_printf(" Bus Mode : "); #if CONFIG_ESPTOOLPY_OCT_FLASH chip_report_printf("OPI\n"); @@ -345,3 +341,106 @@ void printAfterSetupInfo(void) { chip_report_printf("============ After Setup End =============\n"); delay(20); //allow the print to finish } + +// ============================================================================ +// Flash Frequency Runtime Detection +// ============================================================================ + +// Define SPI0 base addresses for different chips +#if CONFIG_IDF_TARGET_ESP32S3 + #define FLASH_SPI0_BASE 0x60003000 +#elif CONFIG_IDF_TARGET_ESP32S2 + #define FLASH_SPI0_BASE 0x3f402000 +#elif CONFIG_IDF_TARGET_ESP32C3 + #define FLASH_SPI0_BASE 0x60002000 +#elif CONFIG_IDF_TARGET_ESP32C2 + #define FLASH_SPI0_BASE 0x60002000 +#elif CONFIG_IDF_TARGET_ESP32C6 + #define FLASH_SPI0_BASE 0x60003000 +#elif CONFIG_IDF_TARGET_ESP32H2 + #define FLASH_SPI0_BASE 0x60003000 +#elif CONFIG_IDF_TARGET_ESP32 + #define FLASH_SPI0_BASE 0x3ff42000 +#else + #define FLASH_SPI0_BASE 0x60003000 // Default for new chips +#endif + +// Register offsets +#define FLASH_CORE_CLK_SEL_OFFSET 0x80 +#define FLASH_CLOCK_OFFSET 0x14 + +/** + * @brief Read the source clock frequency from hardware registers + * @return Source clock frequency in MHz (80, 120, 160, or 240) + */ +uint8_t getFlashSourceFrequencyMHz(void) { + volatile uint32_t* core_clk_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET); + uint32_t core_clk_sel = (*core_clk_reg) & 0x3; // Bits 0-1 + + uint8_t source_freq = 80; // Default + +#if CONFIG_IDF_TARGET_ESP32S3 + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + case 2: source_freq = 160; break; + case 3: source_freq = 240; break; + } +#elif CONFIG_IDF_TARGET_ESP32S2 + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + case 2: source_freq = 160; break; + } +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || \ + CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + } +#elif CONFIG_IDF_TARGET_ESP32 + // ESP32 classic - simplified + source_freq = 80; +#endif + + return source_freq; +} + +/** + * @brief Read the clock divider from hardware registers + * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) + */ +uint8_t getFlashClockDivider(void) { + volatile uint32_t* clock_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CLOCK_OFFSET); + uint32_t clock_val = *clock_reg; + + // Bit 31: if set, clock is 1:1 (no divider) + if (clock_val & (1 << 31)) { + return 1; + } + + // Bits 16-23: clkdiv_pre + uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; + return clkdiv_pre + 1; +} + +/** + * @brief Get the actual flash frequency in MHz + * @return Flash frequency in MHz + */ +uint32_t getFlashFrequencyMHz(void) { + uint8_t source = getFlashSourceFrequencyMHz(); + uint8_t divider = getFlashClockDivider(); + + if (divider == 0) divider = 1; // Safety check + + return source / divider; +} + +/** + * @brief Check if High Performance Mode is enabled + * @return true if flash runs > 80 MHz, false otherwise + */ +bool isFlashHighPerformanceModeEnabled(void) { + return getFlashFrequencyMHz() > 80; +} diff --git a/cores/esp32/chip-debug-report.h b/cores/esp32/chip-debug-report.h index 5c2c8498722..b052e5618e8 100644 --- a/cores/esp32/chip-debug-report.h +++ b/cores/esp32/chip-debug-report.h @@ -5,5 +5,13 @@ */ #pragma once +#include + void printBeforeSetupInfo(void); void printAfterSetupInfo(void); + +// Flash frequency runtime detection +uint32_t getFlashFrequencyMHz(void); +uint8_t getFlashSourceFrequencyMHz(void); +uint8_t getFlashClockDivider(void); +bool isFlashHighPerformanceModeEnabled(void); From a74b0f106d5aed59a92f5072dcc6e11a339b524e Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sun, 5 Oct 2025 20:54:26 +0200 Subject: [PATCH 02/23] Refactor source frequency logic for ESP32 Updated source frequency handling for ESP32 and ESP32S3 targets. --- cores/esp32/chip-debug-report.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index e3378edc65a..778d3b5a613 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -379,7 +379,11 @@ uint8_t getFlashSourceFrequencyMHz(void) { uint8_t source_freq = 80; // Default -#if CONFIG_IDF_TARGET_ESP32S3 +#if CONFIG_IDF_TARGET_ESP32 + // ESP32 classic supports 40 MHz and 80 MHz + // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it + source_freq = 80; // Always 80 MHz source, divider determines 40/80 MHz +#elif CONFIG_IDF_TARGET_ESP32S3 switch (core_clk_sel) { case 0: source_freq = 80; break; case 1: source_freq = 120; break; @@ -398,9 +402,6 @@ uint8_t getFlashSourceFrequencyMHz(void) { case 0: source_freq = 80; break; case 1: source_freq = 120; break; } -#elif CONFIG_IDF_TARGET_ESP32 - // ESP32 classic - simplified - source_freq = 80; #endif return source_freq; From 089f808b0019ec90366727f0fbb4bb93a9a98e0f Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sun, 5 Oct 2025 21:00:00 +0200 Subject: [PATCH 03/23] fix compile for esp32 --- cores/esp32/chip-debug-report.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index 778d3b5a613..993db5e7d82 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -374,16 +374,17 @@ void printAfterSetupInfo(void) { * @return Source clock frequency in MHz (80, 120, 160, or 240) */ uint8_t getFlashSourceFrequencyMHz(void) { +#if CONFIG_IDF_TARGET_ESP32 + // ESP32 classic supports 40 MHz and 80 MHz + // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it + return 80; // Always 80 MHz source, divider determines 40/80 MHz +#else volatile uint32_t* core_clk_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET); uint32_t core_clk_sel = (*core_clk_reg) & 0x3; // Bits 0-1 uint8_t source_freq = 80; // Default -#if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic supports 40 MHz and 80 MHz - // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it - source_freq = 80; // Always 80 MHz source, divider determines 40/80 MHz -#elif CONFIG_IDF_TARGET_ESP32S3 +#if CONFIG_IDF_TARGET_ESP32S3 switch (core_clk_sel) { case 0: source_freq = 80; break; case 1: source_freq = 120; break; @@ -405,6 +406,7 @@ uint8_t getFlashSourceFrequencyMHz(void) { #endif return source_freq; +#endif } /** From ddbc73971f141883bec40e97f4b7997b1adabbaa Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Sun, 5 Oct 2025 21:04:55 +0200 Subject: [PATCH 04/23] Add default case for core clock selection --- cores/esp32/chip-debug-report.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index 993db5e7d82..99616d7bbc5 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -403,6 +403,12 @@ uint8_t getFlashSourceFrequencyMHz(void) { case 0: source_freq = 80; break; case 1: source_freq = 120; break; } +#else + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + default: source_freq = 80; break; + } #endif return source_freq; From e1d7cfb7d4e3e19a7705bae774840c3b055281db Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Mon, 6 Oct 2025 00:21:04 +0200 Subject: [PATCH 05/23] move in Esp.cpp --- cores/esp32/Esp.cpp | 112 ++++++++++++++++++++++++++++ cores/esp32/Esp.h | 6 ++ cores/esp32/chip-debug-report.cpp | 120 +----------------------------- cores/esp32/chip-debug-report.h | 8 -- 4 files changed, 122 insertions(+), 124 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 061404977f9..be7b18290d1 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -516,3 +516,115 @@ uint64_t EspClass::getEfuseMac(void) { esp_efuse_mac_get_default((uint8_t *)(&_chipmacid)); return _chipmacid; } + +// ============================================================================ +// Flash Frequency Runtime Detection +// ============================================================================ + +// Define SPI0 base addresses for different chips +#if CONFIG_IDF_TARGET_ESP32S3 + #define FLASH_SPI0_BASE 0x60003000 +#elif CONFIG_IDF_TARGET_ESP32S2 + #define FLASH_SPI0_BASE 0x3f402000 +#elif CONFIG_IDF_TARGET_ESP32C3 + #define FLASH_SPI0_BASE 0x60002000 +#elif CONFIG_IDF_TARGET_ESP32C2 + #define FLASH_SPI0_BASE 0x60002000 +#elif CONFIG_IDF_TARGET_ESP32C6 + #define FLASH_SPI0_BASE 0x60003000 +#elif CONFIG_IDF_TARGET_ESP32H2 + #define FLASH_SPI0_BASE 0x60003000 +#elif CONFIG_IDF_TARGET_ESP32 + #define FLASH_SPI0_BASE 0x3ff42000 +#else + #define FLASH_SPI0_BASE 0x60003000 // Default for new chips +#endif + +// Register offsets +#define FLASH_CORE_CLK_SEL_OFFSET 0x80 +#define FLASH_CLOCK_OFFSET 0x14 + +/** + * @brief Read the source clock frequency from hardware registers + * @return Source clock frequency in MHz (80, 120, 160, or 240) + */ +uint8_t EspClass::getFlashSourceFrequencyMHz(void) { +#if CONFIG_IDF_TARGET_ESP32 + // ESP32 classic supports 40 MHz and 80 MHz + // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it + return 80; // Always 80 MHz source, divider determines 40/80 MHz +#else + volatile uint32_t* core_clk_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET); + uint32_t core_clk_sel = (*core_clk_reg) & 0x3; // Bits 0-1 + + uint8_t source_freq = 80; // Default + +#if CONFIG_IDF_TARGET_ESP32S3 + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + case 2: source_freq = 160; break; + case 3: source_freq = 240; break; + } +#elif CONFIG_IDF_TARGET_ESP32S2 + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + case 2: source_freq = 160; break; + } +#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || \ + CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + } +#else + switch (core_clk_sel) { + case 0: source_freq = 80; break; + case 1: source_freq = 120; break; + default: source_freq = 80; break; + } +#endif + + return source_freq; +#endif +} + +/** + * @brief Read the clock divider from hardware registers + * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) + */ +uint8_t EspClass::getFlashClockDivider(void) { + volatile uint32_t* clock_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CLOCK_OFFSET); + uint32_t clock_val = *clock_reg; + + // Bit 31: if set, clock is 1:1 (no divider) + if (clock_val & (1 << 31)) { + return 1; + } + + // Bits 16-23: clkdiv_pre + uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; + return clkdiv_pre + 1; +} + +/** + * @brief Get the actual flash frequency in MHz + * @return Flash frequency in MHz + */ +uint32_t EspClass::getFlashFrequencyMHz(void) { + uint8_t source = getFlashSourceFrequencyMHz(); + uint8_t divider = getFlashClockDivider(); + + if (divider == 0) divider = 1; // Safety check + + return source / divider; +} + +/** + * @brief Check if High Performance Mode is enabled + * @return true if flash runs > 80 MHz, false otherwise + */ +bool EspClass::isFlashHighPerformanceModeEnabled(void) { + return getFlashFrequencyMHz() > 80; +} diff --git a/cores/esp32/Esp.h b/cores/esp32/Esp.h index 0b496c91c1b..1f0b8490885 100644 --- a/cores/esp32/Esp.h +++ b/cores/esp32/Esp.h @@ -92,6 +92,12 @@ class EspClass { uint32_t getFlashChipSpeed(); FlashMode_t getFlashChipMode(); + // Flash frequency runtime detection + uint32_t getFlashFrequencyMHz(); + uint8_t getFlashSourceFrequencyMHz(); + uint8_t getFlashClockDivider(); + bool isFlashHighPerformanceModeEnabled(); + uint32_t magicFlashChipSize(uint8_t flashByte); uint32_t magicFlashChipSpeed(uint8_t flashByte); FlashMode_t magicFlashChipMode(uint8_t flashByte); diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index 99616d7bbc5..09a27571574 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -142,14 +142,14 @@ static void printFlashInfo(void) { chip_report_printf(" Page Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.page_size, b2kb(g_rom_flashchip.page_size)); // Runtime flash frequency detection from hardware registers - uint32_t actual_freq = getFlashFrequencyMHz(); - uint8_t source_freq = getFlashSourceFrequencyMHz(); - uint8_t divider = getFlashClockDivider(); + uint32_t actual_freq = ESP.getFlashFrequencyMHz(); + uint8_t source_freq = ESP.getFlashSourceFrequencyMHz(); + uint8_t divider = ESP.getFlashClockDivider(); chip_report_printf(" Bus Speed : %lu MHz\n", actual_freq); chip_report_printf(" Flash Frequency : %lu MHz (source: %u MHz, divider: %u)\n", actual_freq, source_freq, divider); - if (isFlashHighPerformanceModeEnabled()) { + if (ESP.isFlashHighPerformanceModeEnabled()) { chip_report_printf(" HPM Mode : Enabled (> 80 MHz)\n"); } @@ -341,115 +341,3 @@ void printAfterSetupInfo(void) { chip_report_printf("============ After Setup End =============\n"); delay(20); //allow the print to finish } - -// ============================================================================ -// Flash Frequency Runtime Detection -// ============================================================================ - -// Define SPI0 base addresses for different chips -#if CONFIG_IDF_TARGET_ESP32S3 - #define FLASH_SPI0_BASE 0x60003000 -#elif CONFIG_IDF_TARGET_ESP32S2 - #define FLASH_SPI0_BASE 0x3f402000 -#elif CONFIG_IDF_TARGET_ESP32C3 - #define FLASH_SPI0_BASE 0x60002000 -#elif CONFIG_IDF_TARGET_ESP32C2 - #define FLASH_SPI0_BASE 0x60002000 -#elif CONFIG_IDF_TARGET_ESP32C6 - #define FLASH_SPI0_BASE 0x60003000 -#elif CONFIG_IDF_TARGET_ESP32H2 - #define FLASH_SPI0_BASE 0x60003000 -#elif CONFIG_IDF_TARGET_ESP32 - #define FLASH_SPI0_BASE 0x3ff42000 -#else - #define FLASH_SPI0_BASE 0x60003000 // Default for new chips -#endif - -// Register offsets -#define FLASH_CORE_CLK_SEL_OFFSET 0x80 -#define FLASH_CLOCK_OFFSET 0x14 - -/** - * @brief Read the source clock frequency from hardware registers - * @return Source clock frequency in MHz (80, 120, 160, or 240) - */ -uint8_t getFlashSourceFrequencyMHz(void) { -#if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic supports 40 MHz and 80 MHz - // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it - return 80; // Always 80 MHz source, divider determines 40/80 MHz -#else - volatile uint32_t* core_clk_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET); - uint32_t core_clk_sel = (*core_clk_reg) & 0x3; // Bits 0-1 - - uint8_t source_freq = 80; // Default - -#if CONFIG_IDF_TARGET_ESP32S3 - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - case 2: source_freq = 160; break; - case 3: source_freq = 240; break; - } -#elif CONFIG_IDF_TARGET_ESP32S2 - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - case 2: source_freq = 160; break; - } -#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || \ - CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - } -#else - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - default: source_freq = 80; break; - } -#endif - - return source_freq; -#endif -} - -/** - * @brief Read the clock divider from hardware registers - * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) - */ -uint8_t getFlashClockDivider(void) { - volatile uint32_t* clock_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CLOCK_OFFSET); - uint32_t clock_val = *clock_reg; - - // Bit 31: if set, clock is 1:1 (no divider) - if (clock_val & (1 << 31)) { - return 1; - } - - // Bits 16-23: clkdiv_pre - uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; - return clkdiv_pre + 1; -} - -/** - * @brief Get the actual flash frequency in MHz - * @return Flash frequency in MHz - */ -uint32_t getFlashFrequencyMHz(void) { - uint8_t source = getFlashSourceFrequencyMHz(); - uint8_t divider = getFlashClockDivider(); - - if (divider == 0) divider = 1; // Safety check - - return source / divider; -} - -/** - * @brief Check if High Performance Mode is enabled - * @return true if flash runs > 80 MHz, false otherwise - */ -bool isFlashHighPerformanceModeEnabled(void) { - return getFlashFrequencyMHz() > 80; -} diff --git a/cores/esp32/chip-debug-report.h b/cores/esp32/chip-debug-report.h index b052e5618e8..5c2c8498722 100644 --- a/cores/esp32/chip-debug-report.h +++ b/cores/esp32/chip-debug-report.h @@ -5,13 +5,5 @@ */ #pragma once -#include - void printBeforeSetupInfo(void); void printAfterSetupInfo(void); - -// Flash frequency runtime detection -uint32_t getFlashFrequencyMHz(void); -uint8_t getFlashSourceFrequencyMHz(void); -uint8_t getFlashClockDivider(void); -bool isFlashHighPerformanceModeEnabled(void); From 1c01e9c457ba50c74305aa7967c63d003ce0291a Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 11:53:50 +0200 Subject: [PATCH 06/23] Refactor flash clock register base address usage Replaced FLASH_SPI0_BASE with DR_REG_SPI0_BASE for clock register access. --- cores/esp32/Esp.cpp | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index be7b18290d1..42117e5f3bd 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -521,24 +521,7 @@ uint64_t EspClass::getEfuseMac(void) { // Flash Frequency Runtime Detection // ============================================================================ -// Define SPI0 base addresses for different chips -#if CONFIG_IDF_TARGET_ESP32S3 - #define FLASH_SPI0_BASE 0x60003000 -#elif CONFIG_IDF_TARGET_ESP32S2 - #define FLASH_SPI0_BASE 0x3f402000 -#elif CONFIG_IDF_TARGET_ESP32C3 - #define FLASH_SPI0_BASE 0x60002000 -#elif CONFIG_IDF_TARGET_ESP32C2 - #define FLASH_SPI0_BASE 0x60002000 -#elif CONFIG_IDF_TARGET_ESP32C6 - #define FLASH_SPI0_BASE 0x60003000 -#elif CONFIG_IDF_TARGET_ESP32H2 - #define FLASH_SPI0_BASE 0x60003000 -#elif CONFIG_IDF_TARGET_ESP32 - #define FLASH_SPI0_BASE 0x3ff42000 -#else - #define FLASH_SPI0_BASE 0x60003000 // Default for new chips -#endif +// Note: DR_REG_SPI0_BASE is defined in soc/soc.h or soc/reg_base.h for each chip // Register offsets #define FLASH_CORE_CLK_SEL_OFFSET 0x80 @@ -554,7 +537,7 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it return 80; // Always 80 MHz source, divider determines 40/80 MHz #else - volatile uint32_t* core_clk_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET); + volatile uint32_t* core_clk_reg = (volatile uint32_t*)(DR_REG_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET); uint32_t core_clk_sel = (*core_clk_reg) & 0x3; // Bits 0-1 uint8_t source_freq = 80; // Default @@ -595,7 +578,7 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) */ uint8_t EspClass::getFlashClockDivider(void) { - volatile uint32_t* clock_reg = (volatile uint32_t*)(FLASH_SPI0_BASE + FLASH_CLOCK_OFFSET); + volatile uint32_t* clock_reg = (volatile uint32_t*)(DR_REG_SPI0_BASE + FLASH_CLOCK_OFFSET); uint32_t clock_val = *clock_reg; // Bit 31: if set, clock is 1:1 (no divider) From b5df4822e706d8a1c1bc2f2a6622b10daaa26a63 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:09:38 +0200 Subject: [PATCH 07/23] Refactor flash frequency functions with HAL support Refactor flash frequency functions to use ESP-IDF HAL for better maintainability and chip-specific handling. --- cores/esp32/Esp.cpp | 111 ++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 42117e5f3bd..d5b59660654 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -36,6 +36,18 @@ extern "C" { #include "esp_chip_info.h" #include "esp_mac.h" #include "esp_flash.h" + +// Include for HPM (High Performance Mode) functions +#if CONFIG_SPI_FLASH_HPM_ON +#include "esp_private/spi_flash_os.h" +#endif + +// Include HAL layer for flash clock access +#include "hal/spi_flash_ll.h" +#if !CONFIG_IDF_TARGET_ESP32 +#include "hal/spimem_flash_ll.h" +#endif + #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #include "esp32/rom/spi_flash.h" @@ -521,64 +533,33 @@ uint64_t EspClass::getEfuseMac(void) { // Flash Frequency Runtime Detection // ============================================================================ -// Note: DR_REG_SPI0_BASE is defined in soc/soc.h or soc/reg_base.h for each chip - -// Register offsets -#define FLASH_CORE_CLK_SEL_OFFSET 0x80 -#define FLASH_CLOCK_OFFSET 0x14 +// Note: Using ESP-IDF HAL layer functions instead of direct register access +// for better maintainability and chip-specific handling /** - * @brief Read the source clock frequency from hardware registers + * @brief Read the source clock frequency using ESP-IDF HAL functions * @return Source clock frequency in MHz (80, 120, 160, or 240) */ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { #if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic supports 40 MHz and 80 MHz - // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it - return 80; // Always 80 MHz source, divider determines 40/80 MHz + // ESP32 classic: Use HAL function + return spi_flash_ll_get_source_clock_freq_mhz(0); // host_id = 0 for SPI0 #else - volatile uint32_t* core_clk_reg = (volatile uint32_t*)(DR_REG_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET); - uint32_t core_clk_sel = (*core_clk_reg) & 0x3; // Bits 0-1 - - uint8_t source_freq = 80; // Default - -#if CONFIG_IDF_TARGET_ESP32S3 - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - case 2: source_freq = 160; break; - case 3: source_freq = 240; break; - } -#elif CONFIG_IDF_TARGET_ESP32S2 - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - case 2: source_freq = 160; break; - } -#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || \ - CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - } -#else - switch (core_clk_sel) { - case 0: source_freq = 80; break; - case 1: source_freq = 120; break; - default: source_freq = 80; break; - } -#endif - - return source_freq; + // For newer chips (S2, S3, C2, C3, C6, H2): Use spimem HAL function + return spimem_flash_ll_get_source_freq_mhz(); #endif } /** - * @brief Read the clock divider from hardware registers + * @brief Read the clock divider from hardware using HAL abstraction * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) + * + * @note This function still reads hardware registers but uses chip-specific + * base addresses from ESP-IDF HAL layer */ uint8_t EspClass::getFlashClockDivider(void) { - volatile uint32_t* clock_reg = (volatile uint32_t*)(DR_REG_SPI0_BASE + FLASH_CLOCK_OFFSET); + // Read CLOCK register using DR_REG_SPI0_BASE from soc/soc.h + volatile uint32_t* clock_reg = (volatile uint32_t*)(DR_REG_SPI0_BASE + 0x14); uint32_t clock_val = *clock_reg; // Bit 31: if set, clock is 1:1 (no divider) @@ -586,6 +567,17 @@ uint8_t EspClass::getFlashClockDivider(void) { return 1; } + // Bits 16-23: clkdiv_pre + // This is consistent across all ESP32 chips + uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; + return clkdiv_pre + 1; +} + + // Bit 31: if set, clock is 1:1 (no divider) + if (clock_val & (1 << 31)) { + return 1; + } + // Bits 16-23: clkdiv_pre uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; return clkdiv_pre + 1; @@ -607,7 +599,36 @@ uint32_t EspClass::getFlashFrequencyMHz(void) { /** * @brief Check if High Performance Mode is enabled * @return true if flash runs > 80 MHz, false otherwise + * + * @note This function combines hardware register reading with ESP-IDF HPM status + * to provide accurate HPM detection across all scenarios. */ bool EspClass::isFlashHighPerformanceModeEnabled(void) { - return getFlashFrequencyMHz() > 80; + uint32_t freq = getFlashFrequencyMHz(); + + // Primary check: If frequency is > 80 MHz, HPM should be active + if (freq <= 80) { + return false; + } + +#if CONFIG_SPI_FLASH_HPM_ON + // Secondary check: Use ESP-IDF HPM functions if available + // spi_flash_hpm_dummy_adjust() returns true if HPM with dummy adjustment is active + // Note: Some flash chips use other HPM methods (command, status register), + // so we also trust the frequency reading + bool hpm_dummy_active = spi_flash_hpm_dummy_adjust(); + + // If dummy adjust is active, definitely in HPM mode + if (hpm_dummy_active) { + return true; + } + + // If frequency > 80 MHz but dummy adjust not reported, + // HPM might be enabled via other method (command/status register) + // Trust the frequency reading in this case + return true; +#else + // If HPM support not compiled in, rely on frequency reading only + return true; +#endif } From b64562d20cdc9472810a03b4cddcd3c33484564d Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:18:43 +0200 Subject: [PATCH 08/23] Update Esp.cpp --- cores/esp32/Esp.cpp | 63 ++------------------------------------------- 1 file changed, 2 insertions(+), 61 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index d5b59660654..bc6f85be71d 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -37,11 +37,6 @@ extern "C" { #include "esp_mac.h" #include "esp_flash.h" -// Include for HPM (High Performance Mode) functions -#if CONFIG_SPI_FLASH_HPM_ON -#include "esp_private/spi_flash_os.h" -#endif - // Include HAL layer for flash clock access #include "hal/spi_flash_ll.h" #if !CONFIG_IDF_TARGET_ESP32 @@ -533,9 +528,6 @@ uint64_t EspClass::getEfuseMac(void) { // Flash Frequency Runtime Detection // ============================================================================ -// Note: Using ESP-IDF HAL layer functions instead of direct register access -// for better maintainability and chip-specific handling - /** * @brief Read the source clock frequency using ESP-IDF HAL functions * @return Source clock frequency in MHz (80, 120, 160, or 240) @@ -551,11 +543,8 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { } /** - * @brief Read the clock divider from hardware using HAL abstraction + * @brief Read the clock divider from hardware * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) - * - * @note This function still reads hardware registers but uses chip-specific - * base addresses from ESP-IDF HAL layer */ uint8_t EspClass::getFlashClockDivider(void) { // Read CLOCK register using DR_REG_SPI0_BASE from soc/soc.h @@ -567,17 +556,6 @@ uint8_t EspClass::getFlashClockDivider(void) { return 1; } - // Bits 16-23: clkdiv_pre - // This is consistent across all ESP32 chips - uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; - return clkdiv_pre + 1; -} - - // Bit 31: if set, clock is 1:1 (no divider) - if (clock_val & (1 << 31)) { - return 1; - } - // Bits 16-23: clkdiv_pre uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; return clkdiv_pre + 1; @@ -585,7 +563,7 @@ uint8_t EspClass::getFlashClockDivider(void) { /** * @brief Get the actual flash frequency in MHz - * @return Flash frequency in MHz + * @return Flash frequency in MHz (e.g., 80, 120, 160, 240) */ uint32_t EspClass::getFlashFrequencyMHz(void) { uint8_t source = getFlashSourceFrequencyMHz(); @@ -595,40 +573,3 @@ uint32_t EspClass::getFlashFrequencyMHz(void) { return source / divider; } - -/** - * @brief Check if High Performance Mode is enabled - * @return true if flash runs > 80 MHz, false otherwise - * - * @note This function combines hardware register reading with ESP-IDF HPM status - * to provide accurate HPM detection across all scenarios. - */ -bool EspClass::isFlashHighPerformanceModeEnabled(void) { - uint32_t freq = getFlashFrequencyMHz(); - - // Primary check: If frequency is > 80 MHz, HPM should be active - if (freq <= 80) { - return false; - } - -#if CONFIG_SPI_FLASH_HPM_ON - // Secondary check: Use ESP-IDF HPM functions if available - // spi_flash_hpm_dummy_adjust() returns true if HPM with dummy adjustment is active - // Note: Some flash chips use other HPM methods (command, status register), - // so we also trust the frequency reading - bool hpm_dummy_active = spi_flash_hpm_dummy_adjust(); - - // If dummy adjust is active, definitely in HPM mode - if (hpm_dummy_active) { - return true; - } - - // If frequency > 80 MHz but dummy adjust not reported, - // HPM might be enabled via other method (command/status register) - // Trust the frequency reading in this case - return true; -#else - // If HPM support not compiled in, rely on frequency reading only - return true; -#endif -} From fa6c42acaf91e0613fae3d9b6b30ab1a0fdaa7a5 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:29:51 +0200 Subject: [PATCH 09/23] Remove isFlashHighPerformanceModeEnabled function Removed isFlashHighPerformanceModeEnabled function declaration. --- cores/esp32/Esp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/cores/esp32/Esp.h b/cores/esp32/Esp.h index 1f0b8490885..7d5266f7b1a 100644 --- a/cores/esp32/Esp.h +++ b/cores/esp32/Esp.h @@ -96,7 +96,6 @@ class EspClass { uint32_t getFlashFrequencyMHz(); uint8_t getFlashSourceFrequencyMHz(); uint8_t getFlashClockDivider(); - bool isFlashHighPerformanceModeEnabled(); uint32_t magicFlashChipSize(uint8_t flashByte); uint32_t magicFlashChipSpeed(uint8_t flashByte); From d5386b9085388628fb7cf76c7c1940b02fc0fca4 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:31:06 +0200 Subject: [PATCH 10/23] Remove HPM Mode check from debug report Removed check for High Performance Mode in chip debug report. --- cores/esp32/chip-debug-report.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index 09a27571574..160df1c9170 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -149,10 +149,6 @@ static void printFlashInfo(void) { chip_report_printf(" Bus Speed : %lu MHz\n", actual_freq); chip_report_printf(" Flash Frequency : %lu MHz (source: %u MHz, divider: %u)\n", actual_freq, source_freq, divider); - if (ESP.isFlashHighPerformanceModeEnabled()) { - chip_report_printf(" HPM Mode : Enabled (> 80 MHz)\n"); - } - chip_report_printf(" Bus Mode : "); #if CONFIG_ESPTOOLPY_OCT_FLASH chip_report_printf("OPI\n"); From 59c3ee7f956e54b080405beb52d4d593b86c8901 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 14:26:31 +0200 Subject: [PATCH 11/23] Improve getFlashClockDivider documentation and logic Enhanced the documentation for the getFlashClockDivider function and added handling for modern chips using the SPIMEM structure. --- cores/esp32/Esp.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index bc6f85be71d..786b48b8d07 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -41,6 +41,7 @@ extern "C" { #include "hal/spi_flash_ll.h" #if !CONFIG_IDF_TARGET_ESP32 #include "hal/spimem_flash_ll.h" +#include "soc/spi_mem_struct.h" #endif #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ @@ -543,11 +544,12 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { } /** - * @brief Read the clock divider from hardware + * @brief Read the clock divider from hardware using HAL structures * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) */ uint8_t EspClass::getFlashClockDivider(void) { - // Read CLOCK register using DR_REG_SPI0_BASE from soc/soc.h +#if CONFIG_IDF_TARGET_ESP32 + // ESP32 classic: Read CLOCK register directly (no SPIMEM structure available) volatile uint32_t* clock_reg = (volatile uint32_t*)(DR_REG_SPI0_BASE + 0x14); uint32_t clock_val = *clock_reg; @@ -559,6 +561,13 @@ uint8_t EspClass::getFlashClockDivider(void) { // Bits 16-23: clkdiv_pre uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; return clkdiv_pre + 1; +#else + // Modern chips (S2, S3, C2, C3, C5, C6, H2, P4): Use SPIMEM0 structure + if (SPIMEM0.clock.clk_equ_sysclk) { + return 1; // 1:1 clock (no divider) + } + return SPIMEM0.clock.clkcnt_n + 1; +#endif } /** From a9f3ba8ee3c7153375732bf25a1c6b4a5d765dfd Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:27:24 +0200 Subject: [PATCH 12/23] Refactor getFlashClockDivider for ESP32 target --- cores/esp32/Esp.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 786b48b8d07..8dbd169613f 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -39,7 +39,9 @@ extern "C" { // Include HAL layer for flash clock access #include "hal/spi_flash_ll.h" -#if !CONFIG_IDF_TARGET_ESP32 +#if CONFIG_IDF_TARGET_ESP32 +#include "soc/spi_struct.h" +#else #include "hal/spimem_flash_ll.h" #include "soc/spi_mem_struct.h" #endif @@ -549,18 +551,11 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { */ uint8_t EspClass::getFlashClockDivider(void) { #if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic: Read CLOCK register directly (no SPIMEM structure available) - volatile uint32_t* clock_reg = (volatile uint32_t*)(DR_REG_SPI0_BASE + 0x14); - uint32_t clock_val = *clock_reg; - - // Bit 31: if set, clock is 1:1 (no divider) - if (clock_val & (1 << 31)) { - return 1; + // ESP32 classic: Use SPI0 structure + if (SPI0.clock.clk_equ_sysclk) { + return 1; // 1:1 clock (no divider) } - - // Bits 16-23: clkdiv_pre - uint8_t clkdiv_pre = (clock_val >> 16) & 0xFF; - return clkdiv_pre + 1; + return SPI0.clock.clkcnt_n + 1; #else // Modern chips (S2, S3, C2, C3, C5, C6, H2, P4): Use SPIMEM0 structure if (SPIMEM0.clock.clk_equ_sysclk) { From 72c641a87ad17c942e04be11c3b50d5096bfbd1a Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:41:14 +0200 Subject: [PATCH 13/23] Add includes for ESP32P4 and ESP32C5 targets --- cores/esp32/Esp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 8dbd169613f..6d7a907f5ca 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -41,6 +41,9 @@ extern "C" { #include "hal/spi_flash_ll.h" #if CONFIG_IDF_TARGET_ESP32 #include "soc/spi_struct.h" +#elif CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 +#include "hal/spimem_flash_ll.h" +#include "soc/spi_mem_c_struct.h" #else #include "hal/spimem_flash_ll.h" #include "soc/spi_mem_struct.h" From 832de972a7c49c602e3233610a192dc0a998cc14 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:46:09 +0200 Subject: [PATCH 14/23] Update includes for ESP32 target configurations --- cores/esp32/Esp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 6d7a907f5ca..55b37a699dd 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -41,12 +41,13 @@ extern "C" { #include "hal/spi_flash_ll.h" #if CONFIG_IDF_TARGET_ESP32 #include "soc/spi_struct.h" -#elif CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 #include "hal/spimem_flash_ll.h" -#include "soc/spi_mem_c_struct.h" +#include "soc/spi_mem_struct.h" #else +// ESP32-P4, ESP32-C5, and future chips use spi_mem_c_struct.h #include "hal/spimem_flash_ll.h" -#include "soc/spi_mem_struct.h" +#include "soc/spi_mem_c_struct.h" #endif #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ From 65015d57efe567cc47102978de553a1a14ab9cf4 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:52:58 +0200 Subject: [PATCH 15/23] Refactor includes for ESP32 chip compatibility Updated includes for modern ESP32 chips to prioritize newer spi_mem_c_struct.h. --- cores/esp32/Esp.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 55b37a699dd..6c45aa4c453 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -41,13 +41,15 @@ extern "C" { #include "hal/spi_flash_ll.h" #if CONFIG_IDF_TARGET_ESP32 #include "soc/spi_struct.h" -#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 -#include "hal/spimem_flash_ll.h" -#include "soc/spi_mem_struct.h" #else -// ESP32-P4, ESP32-C5, and future chips use spi_mem_c_struct.h +// All modern chips (S2, S3, C2, C3, C5, C6, H2, P4) use spimem #include "hal/spimem_flash_ll.h" +// Try to include the newer c_struct header first, fall back to regular struct +#if __has_include("soc/spi_mem_c_struct.h") #include "soc/spi_mem_c_struct.h" +#else +#include "soc/spi_mem_struct.h" +#endif #endif #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ From 2390a545be6856575d5cd91e28b340405626a945 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:08:44 +0200 Subject: [PATCH 16/23] Refactor flash chip mode handling for ESP32 variants --- cores/esp32/Esp.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 6c45aa4c453..97b4d937511 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -364,17 +364,13 @@ uint32_t EspClass::getFlashChipSpeed(void) { return magicFlashChipSpeed(fhdr.spi_speed); } -// FIXME for P4 -#if !defined(CONFIG_IDF_TARGET_ESP32P4) FlashMode_t EspClass::getFlashChipMode(void) { -#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32P4 uint32_t spi_ctrl = REG_READ(PERIPHS_SPI_FLASH_CTRL); -#else -#if CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 +#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C5 uint32_t spi_ctrl = REG_READ(DR_REG_SPI0_BASE + 0x8); #else uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0)); -#endif #endif /* Not all of the following constants are already defined in older versions of spi_reg.h, so do it manually for now*/ if (spi_ctrl & BIT(24)) { //SPI_FREAD_QIO @@ -390,9 +386,7 @@ FlashMode_t EspClass::getFlashChipMode(void) { } else { return (FM_SLOW_READ); } - return (FM_DOUT); } -#endif // if !defined(CONFIG_IDF_TARGET_ESP32P4) uint32_t EspClass::magicFlashChipSize(uint8_t flashByte) { /* @@ -557,13 +551,19 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { */ uint8_t EspClass::getFlashClockDivider(void) { #if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic: Use SPI0 structure + // ESP32 classic: Use SPI0 structure (no 'mem_' prefix) if (SPI0.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } return SPI0.clock.clkcnt_n + 1; +#elif CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 + // ESP32-P4 and ESP32-C5: Use SPIMEM0 structure with 'mem_' prefix + if (SPIMEM0.clock.mem_clk_equ_sysclk) { + return 1; // 1:1 clock (no divider) + } + return SPIMEM0.clock.mem_clkcnt_n + 1; #else - // Modern chips (S2, S3, C2, C3, C5, C6, H2, P4): Use SPIMEM0 structure + // ESP32-S2, S3, C2, C3, C6, H2: Use SPIMEM0 structure without 'mem_' prefix if (SPIMEM0.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } From de103cdbb75ff484f2905528eeb7f9aed04c1e21 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:13:54 +0200 Subject: [PATCH 17/23] Update getFlashChipMode for ESP32C5 target support --- cores/esp32/Esp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 97b4d937511..82c5c6ed78d 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -365,9 +365,9 @@ uint32_t EspClass::getFlashChipSpeed(void) { } FlashMode_t EspClass::getFlashChipMode(void) { -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32P4 +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 uint32_t spi_ctrl = REG_READ(PERIPHS_SPI_FLASH_CTRL); -#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C5 +#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 uint32_t spi_ctrl = REG_READ(DR_REG_SPI0_BASE + 0x8); #else uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0)); From 7e9dfeffa9c3284cda2affecff34e6ea467234db Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 16:21:34 +0200 Subject: [PATCH 18/23] Refactor getFlashClockDivider comments for clarity --- cores/esp32/Esp.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 82c5c6ed78d..fd084540a7c 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -551,19 +551,13 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { */ uint8_t EspClass::getFlashClockDivider(void) { #if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic: Use SPI0 structure (no 'mem_' prefix) + // ESP32 classic: Use SPI0 structure if (SPI0.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } return SPI0.clock.clkcnt_n + 1; -#elif CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5 - // ESP32-P4 and ESP32-C5: Use SPIMEM0 structure with 'mem_' prefix - if (SPIMEM0.clock.mem_clk_equ_sysclk) { - return 1; // 1:1 clock (no divider) - } - return SPIMEM0.clock.mem_clkcnt_n + 1; #else - // ESP32-S2, S3, C2, C3, C6, H2: Use SPIMEM0 structure without 'mem_' prefix + // All modern chips (S2, S3, C2, C3, C5, C6, H2, P4): Use SPIMEM0 structure if (SPIMEM0.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } From bb19d7da22b0d52ac4f0900607c4d41237f99933 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 6 Oct 2025 18:31:49 +0200 Subject: [PATCH 19/23] Update clock handling for ESP32-C5 --- cores/esp32/Esp.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index fd084540a7c..2189956fb5c 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -556,8 +556,14 @@ uint8_t EspClass::getFlashClockDivider(void) { return 1; // 1:1 clock (no divider) } return SPI0.clock.clkcnt_n + 1; +#elif CONFIG_IDF_TARGET_ESP32C5 + // ESP32-C5: Uses spi_mem_c_clock_reg_t with mem_ prefix + if (SPIMEM0.clock.mem_clk_equ_sysclk) { + return 1; // 1:1 clock (no divider) + } + return SPIMEM0.clock.mem_clkcnt_n + 1; #else - // All modern chips (S2, S3, C2, C3, C5, C6, H2, P4): Use SPIMEM0 structure + // (S2, S3, C2, C3, C6, H2, P4): Use SPIMEM0 structure without mem_ prefix if (SPIMEM0.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } From 934cafd5130abe96aed548ac422f580b3164a9ab Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Tue, 7 Oct 2025 18:17:36 +0200 Subject: [PATCH 20/23] SPI1 not SPI0 --- cores/esp32/Esp.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 2189956fb5c..30cbcccfa74 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -547,27 +547,34 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { /** * @brief Read the clock divider from hardware using HAL structures + * Based on ESP-IDF HAL implementation: + * - ESP32 classic: Uses SPI1.clock (typedef in spi_flash_ll.h line 52) + * - All modern chips: Use SPIMEM1.clock (typedef in spimem_flash_ll.h) * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) */ uint8_t EspClass::getFlashClockDivider(void) { #if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic: Use SPI0 structure - if (SPI0.clock.clk_equ_sysclk) { + // ESP32 classic: Flash uses SPI1 peripheral (not SPI0) + // See: esp-idf/components/hal/esp32/include/hal/spi_flash_ll.h line 52 + if (SPI1.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } - return SPI0.clock.clkcnt_n + 1; + return SPI1.clock.clkcnt_n + 1; #elif CONFIG_IDF_TARGET_ESP32C5 - // ESP32-C5: Uses spi_mem_c_clock_reg_t with mem_ prefix - if (SPIMEM0.clock.mem_clk_equ_sysclk) { + // ESP32-C5: Flash uses SPIMEM1 with mem_ prefixed fields + // See: esp-idf/components/hal/esp32c5/include/hal/spimem_flash_ll.h line 42 + if (SPIMEM1.clock.mem_clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } - return SPIMEM0.clock.mem_clkcnt_n + 1; + return SPIMEM1.clock.mem_clkcnt_n + 1; #else - // (S2, S3, C2, C3, C6, H2, P4): Use SPIMEM0 structure without mem_ prefix - if (SPIMEM0.clock.clk_equ_sysclk) { + // (S2, S3, C2, C3, C6, C61, H2, P4): Flash uses SPIMEM1 + // See: esp-idf/components/hal/esp32*/include/hal/spimem_flash_ll.h + // Example S3: line 38: typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; + if (SPIMEM1.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } - return SPIMEM0.clock.clkcnt_n + 1; + return SPIMEM1.clock.clkcnt_n + 1; #endif } From 5d22dfc22be7f6a3f9f2c919e4bee82742b7c41a Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Tue, 7 Oct 2025 18:26:48 +0200 Subject: [PATCH 21/23] c5 fix --- cores/esp32/Esp.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 30cbcccfa74..58b9e6874eb 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -560,17 +560,11 @@ uint8_t EspClass::getFlashClockDivider(void) { return 1; // 1:1 clock (no divider) } return SPI1.clock.clkcnt_n + 1; -#elif CONFIG_IDF_TARGET_ESP32C5 - // ESP32-C5: Flash uses SPIMEM1 with mem_ prefixed fields - // See: esp-idf/components/hal/esp32c5/include/hal/spimem_flash_ll.h line 42 - if (SPIMEM1.clock.mem_clk_equ_sysclk) { - return 1; // 1:1 clock (no divider) - } - return SPIMEM1.clock.mem_clkcnt_n + 1; #else - // (S2, S3, C2, C3, C6, C61, H2, P4): Flash uses SPIMEM1 + // All modern chips (S2, S3, C2, C3, C5, C6, C61, H2, P4): Flash uses SPIMEM1 // See: esp-idf/components/hal/esp32*/include/hal/spimem_flash_ll.h // Example S3: line 38: typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; + // Example C5: esp-idf/components/soc/esp32c5/mp/include/soc/spi_mem_struct.h lines 97-99 if (SPIMEM1.clock.clk_equ_sysclk) { return 1; // 1:1 clock (no divider) } From eb8203aaa1ab2250666f63d8b4aba49126cf1360 Mon Sep 17 00:00:00 2001 From: Jason2866 Date: Tue, 7 Oct 2025 18:41:58 +0200 Subject: [PATCH 22/23] update comments --- cores/esp32/Esp.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 58b9e6874eb..634d6ffe106 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -537,10 +537,10 @@ uint64_t EspClass::getEfuseMac(void) { */ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { #if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic: Use HAL function + // ESP32: Use HAL function return spi_flash_ll_get_source_clock_freq_mhz(0); // host_id = 0 for SPI0 #else - // For newer chips (S2, S3, C2, C3, C6, H2): Use spimem HAL function + // All modern MCUs: Use spimem HAL function return spimem_flash_ll_get_source_freq_mhz(); #endif } @@ -548,25 +548,25 @@ uint8_t EspClass::getFlashSourceFrequencyMHz(void) { /** * @brief Read the clock divider from hardware using HAL structures * Based on ESP-IDF HAL implementation: - * - ESP32 classic: Uses SPI1.clock (typedef in spi_flash_ll.h line 52) - * - All modern chips: Use SPIMEM1.clock (typedef in spimem_flash_ll.h) + * - ESP32: Uses SPI1.clock (typedef in spi_flash_ll.h) + * - All newer MCUs: Use SPIMEM1.clock (typedef in spimem_flash_ll.h) * @return Clock divider value (1 = no division, 2 = divide by 2, etc.) */ uint8_t EspClass::getFlashClockDivider(void) { #if CONFIG_IDF_TARGET_ESP32 - // ESP32 classic: Flash uses SPI1 peripheral (not SPI0) - // See: esp-idf/components/hal/esp32/include/hal/spi_flash_ll.h line 52 + // ESP32: Flash uses SPI1 + // See: line 52: esp-idf/components/hal/esp32/include/hal/spi_flash_ll.h if (SPI1.clock.clk_equ_sysclk) { - return 1; // 1:1 clock (no divider) + return 1; // 1:1 clock } return SPI1.clock.clkcnt_n + 1; #else - // All modern chips (S2, S3, C2, C3, C5, C6, C61, H2, P4): Flash uses SPIMEM1 + // All newer MCUs: Flash uses SPIMEM1 // See: esp-idf/components/hal/esp32*/include/hal/spimem_flash_ll.h // Example S3: line 38: typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t; - // Example C5: esp-idf/components/soc/esp32c5/mp/include/soc/spi_mem_struct.h lines 97-99 + // Example C5: lines 97-99: esp-idf/components/soc/esp32c5/mp/include/soc/spi_mem_struct.h if (SPIMEM1.clock.clk_equ_sysclk) { - return 1; // 1:1 clock (no divider) + return 1; // 1:1 clock } return SPIMEM1.clock.clkcnt_n + 1; #endif @@ -574,7 +574,7 @@ uint8_t EspClass::getFlashClockDivider(void) { /** * @brief Get the actual flash frequency in MHz - * @return Flash frequency in MHz (e.g., 80, 120, 160, 240) + * @return Flash frequency in MHz (80, 120, 160, or 240) */ uint32_t EspClass::getFlashFrequencyMHz(void) { uint8_t source = getFlashSourceFrequencyMHz(); From 3d1180d00a04c9b84912db2f9e40e47551af59e8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 08:12:19 +0000 Subject: [PATCH 23/23] ci(pre-commit): Apply automatic fixes --- cores/esp32/Esp.cpp | 8 +++++--- cores/esp32/chip-debug-report.cpp | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp index 634d6ffe106..5f5a7a353e8 100644 --- a/cores/esp32/Esp.cpp +++ b/cores/esp32/Esp.cpp @@ -579,8 +579,10 @@ uint8_t EspClass::getFlashClockDivider(void) { uint32_t EspClass::getFlashFrequencyMHz(void) { uint8_t source = getFlashSourceFrequencyMHz(); uint8_t divider = getFlashClockDivider(); - - if (divider == 0) divider = 1; // Safety check - + + if (divider == 0) { + divider = 1; // Safety check + } + return source / divider; } diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index 160df1c9170..753e7346775 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -140,15 +140,15 @@ static void printFlashInfo(void) { chip_report_printf(" Block Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.block_size, b2kb(g_rom_flashchip.block_size)); chip_report_printf(" Sector Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.sector_size, b2kb(g_rom_flashchip.sector_size)); chip_report_printf(" Page Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.page_size, b2kb(g_rom_flashchip.page_size)); - + // Runtime flash frequency detection from hardware registers uint32_t actual_freq = ESP.getFlashFrequencyMHz(); uint8_t source_freq = ESP.getFlashSourceFrequencyMHz(); uint8_t divider = ESP.getFlashClockDivider(); - + chip_report_printf(" Bus Speed : %lu MHz\n", actual_freq); chip_report_printf(" Flash Frequency : %lu MHz (source: %u MHz, divider: %u)\n", actual_freq, source_freq, divider); - + chip_report_printf(" Bus Mode : "); #if CONFIG_ESPTOOLPY_OCT_FLASH chip_report_printf("OPI\n");