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 8592031ee3f..09a27571574 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 = 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 (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");