Skip to content

Commit 4deb5e5

Browse files
Runtime Flash Clock detection (espressif#11903)
* getFlashFrequencyMHz * Refactor source frequency logic for ESP32 Updated source frequency handling for ESP32 and ESP32S3 targets. * fix compile for esp32 * Add default case for core clock selection * move in Esp.cpp * Refactor flash clock register base address usage Replaced FLASH_SPI0_BASE with DR_REG_SPI0_BASE for clock register access. * Refactor flash frequency functions with HAL support Refactor flash frequency functions to use ESP-IDF HAL for better maintainability and chip-specific handling. * Update Esp.cpp * Remove isFlashHighPerformanceModeEnabled function Removed isFlashHighPerformanceModeEnabled function declaration. * Remove HPM Mode check from debug report Removed check for High Performance Mode in chip debug report. * Improve getFlashClockDivider documentation and logic Enhanced the documentation for the getFlashClockDivider function and added handling for modern chips using the SPIMEM structure. * Refactor getFlashClockDivider for ESP32 target * Add includes for ESP32P4 and ESP32C5 targets * Update includes for ESP32 target configurations * Refactor includes for ESP32 chip compatibility Updated includes for modern ESP32 chips to prioritize newer spi_mem_c_struct.h. * Refactor flash chip mode handling for ESP32 variants * Update getFlashChipMode for ESP32C5 target support * Refactor getFlashClockDivider comments for clarity * Update clock handling for ESP32-C5 * SPI1 not SPI0 * c5 fix * update comments * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent 493c528 commit 4deb5e5

File tree

3 files changed

+94
-27
lines changed

3 files changed

+94
-27
lines changed

cores/esp32/Esp.cpp

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,22 @@ extern "C" {
3636
#include "esp_chip_info.h"
3737
#include "esp_mac.h"
3838
#include "esp_flash.h"
39+
40+
// Include HAL layer for flash clock access
41+
#include "hal/spi_flash_ll.h"
42+
#if CONFIG_IDF_TARGET_ESP32
43+
#include "soc/spi_struct.h"
44+
#else
45+
// All modern chips (S2, S3, C2, C3, C5, C6, H2, P4) use spimem
46+
#include "hal/spimem_flash_ll.h"
47+
// Try to include the newer c_struct header first, fall back to regular struct
48+
#if __has_include("soc/spi_mem_c_struct.h")
49+
#include "soc/spi_mem_c_struct.h"
50+
#else
51+
#include "soc/spi_mem_struct.h"
52+
#endif
53+
#endif
54+
3955
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
4056
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
4157
#include "esp32/rom/spi_flash.h"
@@ -348,17 +364,13 @@ uint32_t EspClass::getFlashChipSpeed(void) {
348364
return magicFlashChipSpeed(fhdr.spi_speed);
349365
}
350366

351-
// FIXME for P4
352-
#if !defined(CONFIG_IDF_TARGET_ESP32P4)
353367
FlashMode_t EspClass::getFlashChipMode(void) {
354-
#if CONFIG_IDF_TARGET_ESP32S2
368+
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5
355369
uint32_t spi_ctrl = REG_READ(PERIPHS_SPI_FLASH_CTRL);
356-
#else
357-
#if CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
370+
#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
358371
uint32_t spi_ctrl = REG_READ(DR_REG_SPI0_BASE + 0x8);
359372
#else
360373
uint32_t spi_ctrl = REG_READ(SPI_CTRL_REG(0));
361-
#endif
362374
#endif
363375
/* Not all of the following constants are already defined in older versions of spi_reg.h, so do it manually for now*/
364376
if (spi_ctrl & BIT(24)) { //SPI_FREAD_QIO
@@ -374,9 +386,7 @@ FlashMode_t EspClass::getFlashChipMode(void) {
374386
} else {
375387
return (FM_SLOW_READ);
376388
}
377-
return (FM_DOUT);
378389
}
379-
#endif // if !defined(CONFIG_IDF_TARGET_ESP32P4)
380390

381391
uint32_t EspClass::magicFlashChipSize(uint8_t flashByte) {
382392
/*
@@ -516,3 +526,63 @@ uint64_t EspClass::getEfuseMac(void) {
516526
esp_efuse_mac_get_default((uint8_t *)(&_chipmacid));
517527
return _chipmacid;
518528
}
529+
530+
// ============================================================================
531+
// Flash Frequency Runtime Detection
532+
// ============================================================================
533+
534+
/**
535+
* @brief Read the source clock frequency using ESP-IDF HAL functions
536+
* @return Source clock frequency in MHz (80, 120, 160, or 240)
537+
*/
538+
uint8_t EspClass::getFlashSourceFrequencyMHz(void) {
539+
#if CONFIG_IDF_TARGET_ESP32
540+
// ESP32: Use HAL function
541+
return spi_flash_ll_get_source_clock_freq_mhz(0); // host_id = 0 for SPI0
542+
#else
543+
// All modern MCUs: Use spimem HAL function
544+
return spimem_flash_ll_get_source_freq_mhz();
545+
#endif
546+
}
547+
548+
/**
549+
* @brief Read the clock divider from hardware using HAL structures
550+
* Based on ESP-IDF HAL implementation:
551+
* - ESP32: Uses SPI1.clock (typedef in spi_flash_ll.h)
552+
* - All newer MCUs: Use SPIMEM1.clock (typedef in spimem_flash_ll.h)
553+
* @return Clock divider value (1 = no division, 2 = divide by 2, etc.)
554+
*/
555+
uint8_t EspClass::getFlashClockDivider(void) {
556+
#if CONFIG_IDF_TARGET_ESP32
557+
// ESP32: Flash uses SPI1
558+
// See: line 52: esp-idf/components/hal/esp32/include/hal/spi_flash_ll.h
559+
if (SPI1.clock.clk_equ_sysclk) {
560+
return 1; // 1:1 clock
561+
}
562+
return SPI1.clock.clkcnt_n + 1;
563+
#else
564+
// All newer MCUs: Flash uses SPIMEM1
565+
// See: esp-idf/components/hal/esp32*/include/hal/spimem_flash_ll.h
566+
// Example S3: line 38: typedef typeof(SPIMEM1.clock.val) spimem_flash_ll_clock_reg_t;
567+
// Example C5: lines 97-99: esp-idf/components/soc/esp32c5/mp/include/soc/spi_mem_struct.h
568+
if (SPIMEM1.clock.clk_equ_sysclk) {
569+
return 1; // 1:1 clock
570+
}
571+
return SPIMEM1.clock.clkcnt_n + 1;
572+
#endif
573+
}
574+
575+
/**
576+
* @brief Get the actual flash frequency in MHz
577+
* @return Flash frequency in MHz (80, 120, 160, or 240)
578+
*/
579+
uint32_t EspClass::getFlashFrequencyMHz(void) {
580+
uint8_t source = getFlashSourceFrequencyMHz();
581+
uint8_t divider = getFlashClockDivider();
582+
583+
if (divider == 0) {
584+
divider = 1; // Safety check
585+
}
586+
587+
return source / divider;
588+
}

cores/esp32/Esp.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ class EspClass {
9292
uint32_t getFlashChipSpeed();
9393
FlashMode_t getFlashChipMode();
9494

95+
// Flash frequency runtime detection
96+
uint32_t getFlashFrequencyMHz();
97+
uint8_t getFlashSourceFrequencyMHz();
98+
uint8_t getFlashClockDivider();
99+
95100
uint32_t magicFlashChipSize(uint8_t flashByte);
96101
uint32_t magicFlashChipSpeed(uint8_t flashByte);
97102
FlashMode_t magicFlashChipMode(uint8_t flashByte);

cores/esp32/chip-debug-report.cpp

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
#include "soc/efuse_reg.h"
1010
#include "soc/rtc.h"
1111
#include "soc/spi_reg.h"
12+
#include "soc/soc.h"
1213
#if CONFIG_IDF_TARGET_ESP32S2
1314
#include "esp32s2/rom/spi_flash.h"
1415
#endif
1516
#include "esp_bit_defs.h"
1617

1718
#include "Arduino.h"
1819
#include "esp32-hal-periman.h"
20+
#include "chip-debug-report.h"
1921

2022
#define chip_report_printf log_printf
2123

@@ -138,25 +140,15 @@ static void printFlashInfo(void) {
138140
chip_report_printf(" Block Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.block_size, b2kb(g_rom_flashchip.block_size));
139141
chip_report_printf(" Sector Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.sector_size, b2kb(g_rom_flashchip.sector_size));
140142
chip_report_printf(" Page Size : %8lu B (%6.1f KB)\n", g_rom_flashchip.page_size, b2kb(g_rom_flashchip.page_size));
141-
esp_image_header_t fhdr;
142-
esp_flash_read(esp_flash_default_chip, (void *)&fhdr, ESP_FLASH_IMAGE_BASE, sizeof(esp_image_header_t));
143-
if (fhdr.magic == ESP_IMAGE_HEADER_MAGIC) {
144-
uint32_t f_freq = 0;
145-
switch (fhdr.spi_speed) {
146-
#if CONFIG_IDF_TARGET_ESP32H2
147-
case 0x0: f_freq = 32; break;
148-
case 0x2: f_freq = 16; break;
149-
case 0xf: f_freq = 64; break;
150-
#else
151-
case 0x0: f_freq = 40; break;
152-
case 0x1: f_freq = 26; break;
153-
case 0x2: f_freq = 20; break;
154-
case 0xf: f_freq = 80; break;
155-
#endif
156-
default: f_freq = fhdr.spi_speed; break;
157-
}
158-
chip_report_printf(" Bus Speed : %lu MHz\n", f_freq);
159-
}
143+
144+
// Runtime flash frequency detection from hardware registers
145+
uint32_t actual_freq = ESP.getFlashFrequencyMHz();
146+
uint8_t source_freq = ESP.getFlashSourceFrequencyMHz();
147+
uint8_t divider = ESP.getFlashClockDivider();
148+
149+
chip_report_printf(" Bus Speed : %lu MHz\n", actual_freq);
150+
chip_report_printf(" Flash Frequency : %lu MHz (source: %u MHz, divider: %u)\n", actual_freq, source_freq, divider);
151+
160152
chip_report_printf(" Bus Mode : ");
161153
#if CONFIG_ESPTOOLPY_OCT_FLASH
162154
chip_report_printf("OPI\n");

0 commit comments

Comments
 (0)