@@ -36,6 +36,18 @@ extern "C" {
36
36
#include " esp_chip_info.h"
37
37
#include " esp_mac.h"
38
38
#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
+
39
51
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
40
52
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
41
53
#include " esp32/rom/spi_flash.h"
@@ -521,71 +533,51 @@ uint64_t EspClass::getEfuseMac(void) {
521
533
// Flash Frequency Runtime Detection
522
534
// ============================================================================
523
535
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
529
538
530
539
/* *
531
- * @brief Read the source clock frequency from hardware registers
540
+ * @brief Read the source clock frequency using ESP-IDF HAL functions
532
541
* @return Source clock frequency in MHz (80, 120, 160, or 240)
533
542
*/
534
543
uint8_t EspClass::getFlashSourceFrequencyMHz (void ) {
535
544
#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
539
547
#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 ();
573
550
#endif
574
551
}
575
552
576
553
/* *
577
- * @brief Read the clock divider from hardware registers
554
+ * @brief Read the clock divider from hardware using HAL abstraction
578
555
* @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
579
559
*/
580
560
uint8_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 );
582
563
uint32_t clock_val = *clock_reg;
583
564
584
565
// Bit 31: if set, clock is 1:1 (no divider)
585
566
if (clock_val & (1 << 31 )) {
586
567
return 1 ;
587
568
}
588
569
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
+
589
581
// Bits 16-23: clkdiv_pre
590
582
uint8_t clkdiv_pre = (clock_val >> 16 ) & 0xFF ;
591
583
return clkdiv_pre + 1 ;
@@ -607,7 +599,36 @@ uint32_t EspClass::getFlashFrequencyMHz(void) {
607
599
/* *
608
600
* @brief Check if High Performance Mode is enabled
609
601
* @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.
610
605
*/
611
606
bool 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
613
634
}
0 commit comments