@@ -36,6 +36,18 @@ extern "C" {
3636#include " esp_chip_info.h"
3737#include " esp_mac.h"
3838#include " esp_flash.h"
39+
40+ // Include for HPM (High Performance Mode) functions
41+ #if CONFIG_SPI_FLASH_HPM_ON
42+ #include " esp_private/spi_flash_os.h"
43+ #endif
44+
45+ // Include HAL layer for flash clock access
46+ #include " hal/spi_flash_ll.h"
47+ #if !CONFIG_IDF_TARGET_ESP32
48+ #include " hal/spimem_flash_ll.h"
49+ #endif
50+
3951#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
4052#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
4153#include " esp32/rom/spi_flash.h"
@@ -521,71 +533,51 @@ uint64_t EspClass::getEfuseMac(void) {
521533// Flash Frequency Runtime Detection
522534// ============================================================================
523535
524- // Note: DR_REG_SPI0_BASE is defined in soc/soc.h or soc/reg_base.h for each chip
525-
526- // Register offsets
527- #define FLASH_CORE_CLK_SEL_OFFSET 0x80
528- #define FLASH_CLOCK_OFFSET 0x14
536+ // Note: Using ESP-IDF HAL layer functions instead of direct register access
537+ // for better maintainability and chip-specific handling
529538
530539/* *
531- * @brief Read the source clock frequency from hardware registers
540+ * @brief Read the source clock frequency using ESP-IDF HAL functions
532541 * @return Source clock frequency in MHz (80, 120, 160, or 240)
533542 */
534543uint8_t EspClass::getFlashSourceFrequencyMHz (void ) {
535544#if CONFIG_IDF_TARGET_ESP32
536- // ESP32 classic supports 40 MHz and 80 MHz
537- // Note: ESP32 uses the PLL clock (80 MHz) as source and divides it
538- return 80 ; // Always 80 MHz source, divider determines 40/80 MHz
545+ // ESP32 classic: Use HAL function
546+ return spi_flash_ll_get_source_clock_freq_mhz (0 ); // host_id = 0 for SPI0
539547#else
540- volatile uint32_t * core_clk_reg = (volatile uint32_t *)(DR_REG_SPI0_BASE + FLASH_CORE_CLK_SEL_OFFSET);
541- uint32_t core_clk_sel = (*core_clk_reg) & 0x3 ; // Bits 0-1
542-
543- uint8_t source_freq = 80 ; // Default
544-
545- #if CONFIG_IDF_TARGET_ESP32S3
546- switch (core_clk_sel) {
547- case 0 : source_freq = 80 ; break ;
548- case 1 : source_freq = 120 ; break ;
549- case 2 : source_freq = 160 ; break ;
550- case 3 : source_freq = 240 ; break ;
551- }
552- #elif CONFIG_IDF_TARGET_ESP32S2
553- switch (core_clk_sel) {
554- case 0 : source_freq = 80 ; break ;
555- case 1 : source_freq = 120 ; break ;
556- case 2 : source_freq = 160 ; break ;
557- }
558- #elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || \
559- CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2
560- switch (core_clk_sel) {
561- case 0 : source_freq = 80 ; break ;
562- case 1 : source_freq = 120 ; break ;
563- }
564- #else
565- switch (core_clk_sel) {
566- case 0 : source_freq = 80 ; break ;
567- case 1 : source_freq = 120 ; break ;
568- default : source_freq = 80 ; break ;
569- }
570- #endif
571-
572- return source_freq;
548+ // For newer chips (S2, S3, C2, C3, C6, H2): Use spimem HAL function
549+ return spimem_flash_ll_get_source_freq_mhz ();
573550#endif
574551}
575552
576553/* *
577- * @brief Read the clock divider from hardware registers
554+ * @brief Read the clock divider from hardware using HAL abstraction
578555 * @return Clock divider value (1 = no division, 2 = divide by 2, etc.)
556+ *
557+ * @note This function still reads hardware registers but uses chip-specific
558+ * base addresses from ESP-IDF HAL layer
579559 */
580560uint8_t EspClass::getFlashClockDivider (void ) {
581- volatile uint32_t * clock_reg = (volatile uint32_t *)(DR_REG_SPI0_BASE + FLASH_CLOCK_OFFSET);
561+ // Read CLOCK register using DR_REG_SPI0_BASE from soc/soc.h
562+ volatile uint32_t * clock_reg = (volatile uint32_t *)(DR_REG_SPI0_BASE + 0x14 );
582563 uint32_t clock_val = *clock_reg;
583564
584565 // Bit 31: if set, clock is 1:1 (no divider)
585566 if (clock_val & (1 << 31 )) {
586567 return 1 ;
587568 }
588569
570+ // Bits 16-23: clkdiv_pre
571+ // This is consistent across all ESP32 chips
572+ uint8_t clkdiv_pre = (clock_val >> 16 ) & 0xFF ;
573+ return clkdiv_pre + 1 ;
574+ }
575+
576+ // Bit 31: if set, clock is 1:1 (no divider)
577+ if (clock_val & (1 << 31 )) {
578+ return 1 ;
579+ }
580+
589581 // Bits 16-23: clkdiv_pre
590582 uint8_t clkdiv_pre = (clock_val >> 16 ) & 0xFF ;
591583 return clkdiv_pre + 1 ;
@@ -607,7 +599,36 @@ uint32_t EspClass::getFlashFrequencyMHz(void) {
607599/* *
608600 * @brief Check if High Performance Mode is enabled
609601 * @return true if flash runs > 80 MHz, false otherwise
602+ *
603+ * @note This function combines hardware register reading with ESP-IDF HPM status
604+ * to provide accurate HPM detection across all scenarios.
610605 */
611606bool EspClass::isFlashHighPerformanceModeEnabled (void ) {
612- return getFlashFrequencyMHz () > 80 ;
607+ uint32_t freq = getFlashFrequencyMHz ();
608+
609+ // Primary check: If frequency is > 80 MHz, HPM should be active
610+ if (freq <= 80 ) {
611+ return false ;
612+ }
613+
614+ #if CONFIG_SPI_FLASH_HPM_ON
615+ // Secondary check: Use ESP-IDF HPM functions if available
616+ // spi_flash_hpm_dummy_adjust() returns true if HPM with dummy adjustment is active
617+ // Note: Some flash chips use other HPM methods (command, status register),
618+ // so we also trust the frequency reading
619+ bool hpm_dummy_active = spi_flash_hpm_dummy_adjust ();
620+
621+ // If dummy adjust is active, definitely in HPM mode
622+ if (hpm_dummy_active) {
623+ return true ;
624+ }
625+
626+ // If frequency > 80 MHz but dummy adjust not reported,
627+ // HPM might be enabled via other method (command/status register)
628+ // Trust the frequency reading in this case
629+ return true ;
630+ #else
631+ // If HPM support not compiled in, rely on frequency reading only
632+ return true ;
633+ #endif
613634}
0 commit comments