diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index f10bac95ee..7a136e2600 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -564,8 +564,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags) rtc_clk_cpu_freq_set_config(&cpu_freq_config); #if SOC_SPI_MEM_SUPPORT_TIME_TUNING - // Restore mspi clock freq - spi_timing_change_speed_mode_cache_safe(false); + if (cpu_freq_config.source == RTC_CPU_FREQ_SRC_PLL) { + // Restore mspi clock freq + spi_timing_change_speed_mode_cache_safe(false); + } #endif if (!deep_sleep) { diff --git a/components/esp_pm/CMakeLists.txt b/components/esp_pm/CMakeLists.txt index 5c68058e97..40307acbe3 100644 --- a/components/esp_pm/CMakeLists.txt +++ b/components/esp_pm/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRCS "pm_locks.c" "pm_trace.c" "pm_impl.c" INCLUDE_DIRS include - PRIV_REQUIRES esp_system driver + PRIV_REQUIRES esp_system driver spi_flash LDFRAGMENTS linker.lf) diff --git a/components/esp_pm/pm_impl.c b/components/esp_pm/pm_impl.c index 72c6fdb4fd..ca08ecb610 100644 --- a/components/esp_pm/pm_impl.c +++ b/components/esp_pm/pm_impl.c @@ -17,6 +17,7 @@ #include "esp_private/crosscore_int.h" #include "soc/rtc.h" +#include "soc/soc_caps.h" #include "hal/cpu_hal.h" #include "hal/uart_ll.h" #include "hal/uart_types.h" @@ -32,6 +33,10 @@ #include "esp_private/pm_trace.h" #include "esp_private/esp_timer_private.h" +#if SOC_SPI_MEM_SUPPORT_TIME_TUNING +#include "esp_private/spi_flash_os.h" +#endif + #include "esp_sleep.h" #include "sdkconfig.h" @@ -501,7 +506,19 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode) if (switch_down) { on_freq_update(old_ticks_per_us, new_ticks_per_us); } - rtc_clk_cpu_freq_set_config_fast(&new_config); + + if (new_config.source == RTC_CPU_FREQ_SRC_PLL) { + rtc_clk_cpu_freq_set_config_fast(&new_config); +#if SOC_SPI_MEM_SUPPORT_TIME_TUNING + spi_timing_change_speed_mode_cache_safe(false); +#endif + } else { +#if SOC_SPI_MEM_SUPPORT_TIME_TUNING + spi_timing_change_speed_mode_cache_safe(true); +#endif + rtc_clk_cpu_freq_set_config_fast(&new_config); + } + if (!switch_down) { on_freq_update(old_ticks_per_us, new_ticks_per_us); } diff --git a/components/esp_pm/pm_trace.c b/components/esp_pm/pm_trace.c index 1da9c93f55..355dadb7fa 100644 --- a/components/esp_pm/pm_trace.c +++ b/components/esp_pm/pm_trace.c @@ -21,20 +21,27 @@ * Feel free to change when debugging. */ static const int DRAM_ATTR s_trace_io[] = { -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32H2) - BIT(4), BIT(5), // ESP_PM_TRACE_IDLE - BIT(16), BIT(17), // ESP_PM_TRACE_TICK - BIT(18), BIT(18), // ESP_PM_TRACE_FREQ_SWITCH - BIT(19), BIT(19), // ESP_PM_TRACE_CCOMPARE_UPDATE - BIT(25), BIT(26), // ESP_PM_TRACE_ISR_HOOK - BIT(27), BIT(27), // ESP_PM_TRACE_SLEEP +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + BIT(4), BIT(5), // ESP_PM_TRACE_IDLE + BIT(16), BIT(17), // ESP_PM_TRACE_TICK + BIT(18), BIT(18), // ESP_PM_TRACE_FREQ_SWITCH + BIT(19), BIT(19), // ESP_PM_TRACE_CCOMPARE_UPDATE + BIT(25), BIT(26), // ESP_PM_TRACE_ISR_HOOK + BIT(27), BIT(27), // ESP_PM_TRACE_SLEEP +#elif CONFIG_IDF_TARGET_ESP32S3 + BIT(4), BIT(5), // ESP_PM_TRACE_IDLE + BIT(6), BIT(7), // ESP_PM_TRACE_TICK + BIT(14), BIT(14), // ESP_PM_TRACE_FREQ_SWITCH + BIT(15), BIT(15), // ESP_PM_TRACE_CCOMPARE_UPDATE + BIT(16), BIT(17), // ESP_PM_TRACE_ISR_HOOK + BIT(18), BIT(18), // ESP_PM_TRACE_SLEEP #else - BIT(2), BIT(3), // ESP_PM_TRACE_IDLE - BIT(4), BIT(5), // ESP_PM_TRACE_TICK - BIT(6), BIT(6), // ESP_PM_TRACE_FREQ_SWITCH - BIT(7), BIT(7), // ESP_PM_TRACE_CCOMPARE_UPDATE - BIT(8), BIT(9), // ESP_PM_TRACE_ISR_HOOK - BIT(18), BIT(18), // ESP_PM_TRACE_SLEEP + BIT(2), BIT(3), // ESP_PM_TRACE_IDLE + BIT(4), BIT(5), // ESP_PM_TRACE_TICK + BIT(6), BIT(6), // ESP_PM_TRACE_FREQ_SWITCH + BIT(7), BIT(7), // ESP_PM_TRACE_CCOMPARE_UPDATE + BIT(8), BIT(9), // ESP_PM_TRACE_ISR_HOOK + BIT(18), BIT(18), // ESP_PM_TRACE_SLEEP #endif }; diff --git a/components/spi_flash/spi_flash_timing_tuning.c b/components/spi_flash/spi_flash_timing_tuning.c index c27f1c025f..f1f14ad376 100644 --- a/components/spi_flash/spi_flash_timing_tuning.c +++ b/components/spi_flash/spi_flash_timing_tuning.c @@ -472,8 +472,8 @@ void spi_timing_enter_mspi_high_speed_mode(bool control_spi1) void spi_timing_change_speed_mode_cache_safe(bool switch_down) { - Cache_Freeze_ICache_Enable(1); - Cache_Freeze_DCache_Enable(1); + Cache_Freeze_ICache_Enable(CACHE_FREEZE_ACK_BUSY); + Cache_Freeze_DCache_Enable(CACHE_FREEZE_ACK_BUSY); if (switch_down) { //enter MSPI low speed mode, extra delays should be removed spi_timing_enter_mspi_low_speed_mode(false); diff --git a/tools/test_apps/system/flash_psram/app_test.py b/tools/test_apps/system/flash_psram/app_test.py index daa0aa24f7..8589765d09 100644 --- a/tools/test_apps/system/flash_psram/app_test.py +++ b/tools/test_apps/system/flash_psram/app_test.py @@ -16,7 +16,7 @@ def test_loop(env, config_names): # type: (Any, Any) -> None Utility.console_log("Checking config \"{}\"... ".format(name), end='') dut = env.get_dut('flash_psram', 'tools/test_apps/system/flash_psram', app_config_name=name) dut.start_app() - dut.expect('flash psram test success') + dut.expect('flash psram test success', timeout=30) env.close_dut(dut.name) Utility.console_log('done') diff --git a/tools/test_apps/system/flash_psram/main/test_flash_psram.c b/tools/test_apps/system/flash_psram/main/test_flash_psram.c index 2fb38e096b..64129b1ee1 100644 --- a/tools/test_apps/system/flash_psram/main/test_flash_psram.c +++ b/tools/test_apps/system/flash_psram/main/test_flash_psram.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,9 +9,12 @@ #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/semphr.h" #include "esp_system.h" #include "esp_check.h" #include "esp_attr.h" +#include "esp_pm.h" +#include "esp_private/esp_clk.h" #if CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/opi_flash.h" @@ -29,7 +32,26 @@ #define LENGTH_PER_TIME 1024 #endif -static esp_err_t spi0_psram_test(void) +#define MHZ (1000000) +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#if CONFIG_IDF_TARGET_ESP32 +typedef esp_pm_config_esp32_t esp_pm_config_t; +#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ +#elif CONFIG_IDF_TARGET_ESP32S2 +typedef esp_pm_config_esp32s2_t esp_pm_config_t; +#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ +#elif CONFIG_IDF_TARGET_ESP32S3 +typedef esp_pm_config_esp32s3_t esp_pm_config_t; +#define DEFAULT_CPU_FREQ_MHZ CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ +#endif + +static SemaphoreHandle_t DoneSemphr; +static SemaphoreHandle_t StopSemphr; + +static void psram_read_write_task(void* arg) { printf("----------SPI0 PSRAM Test----------\n"); @@ -39,30 +61,145 @@ static esp_err_t spi0_psram_test(void) abort(); } - uint32_t *psram_rd_buf = (uint32_t *)heap_caps_malloc(SPI0_PSRAM_TEST_LEN, MALLOC_CAP_32BIT | MALLOC_CAP_SPIRAM); + uint8_t *psram_rd_buf = (uint8_t *)heap_caps_malloc(SPI0_PSRAM_TEST_LEN, MALLOC_CAP_32BIT | MALLOC_CAP_SPIRAM); if (!psram_rd_buf) { printf("no memory\n"); abort(); } srand(399); - for (int i = 0; i < SPI0_PSRAM_TEST_LEN / LENGTH_PER_TIME; i++) { - for (int j = 0; j < sizeof(psram_wr_buf); j++) { - psram_wr_buf[j] = rand(); - } - memcpy(psram_rd_buf + i * LENGTH_PER_TIME, psram_wr_buf, LENGTH_PER_TIME); + for (uint32_t loop = 0; loop < (uint32_t)(arg); loop++) { + for (int i = 0; i < SPI0_PSRAM_TEST_LEN / LENGTH_PER_TIME; i++) { + for (int j = 0; j < sizeof(psram_wr_buf); j++) { + psram_wr_buf[j] = rand(); + } + memcpy(psram_rd_buf + i * LENGTH_PER_TIME, psram_wr_buf, LENGTH_PER_TIME); - if (memcmp(psram_rd_buf + i * LENGTH_PER_TIME, psram_wr_buf, LENGTH_PER_TIME) != 0) { - printf("Fail\n"); - free(psram_rd_buf); - free(psram_wr_buf); + if (memcmp(psram_rd_buf + i * LENGTH_PER_TIME, psram_wr_buf, LENGTH_PER_TIME) != 0) { + free(psram_rd_buf); + free(psram_wr_buf); + abort(); + } + } + xSemaphoreGive(DoneSemphr); + vTaskDelay(10); + } + free(psram_rd_buf); + free(psram_wr_buf); + vTaskDelete(NULL); +} + +static void pm_light_sleep_enable(void) +{ + int cur_freq_mhz = esp_clk_cpu_freq() / MHZ; + int xtal_freq = esp_clk_xtal_freq() / MHZ; + + esp_pm_config_t pm_config = { + .max_freq_mhz = cur_freq_mhz, + .min_freq_mhz = xtal_freq, + .light_sleep_enable = true + }; + ESP_ERROR_CHECK( esp_pm_configure(&pm_config) ); +} + +static void pm_light_sleep_disable(void) +{ + int cur_freq_mhz = esp_clk_cpu_freq() / MHZ; + + esp_pm_config_t pm_config = { + .max_freq_mhz = cur_freq_mhz, + .min_freq_mhz = cur_freq_mhz, + }; + ESP_ERROR_CHECK( esp_pm_configure(&pm_config) ); +} + +static void pm_switch_freq(int max_cpu_freq_mhz) +{ + int xtal_freq_mhz = esp_clk_xtal_freq() / MHZ; + + esp_pm_config_t pm_config = { + .max_freq_mhz = max_cpu_freq_mhz, + .min_freq_mhz = MIN(max_cpu_freq_mhz, xtal_freq_mhz), + }; + ESP_ERROR_CHECK( esp_pm_configure(&pm_config) ); + printf("Waiting for frequency to be set to %d MHz...\n", max_cpu_freq_mhz); + while (esp_clk_cpu_freq() / MHZ != max_cpu_freq_mhz) + { + vTaskDelay(pdMS_TO_TICKS(200)); + printf("Frequency is %d MHz\n", esp_clk_cpu_freq() / MHZ); + } +} + +static void goto_idle_and_check_stop(uint32_t period) +{ + if (xSemaphoreTake(StopSemphr, pdMS_TO_TICKS(period)) == pdTRUE) { + pm_switch_freq(DEFAULT_CPU_FREQ_MHZ); + vSemaphoreDelete(StopSemphr); + vTaskDelete(NULL); + } +} + +static void pm_switch_task(void *arg) +{ + pm_light_sleep_disable(); + uint32_t period = 100; + StopSemphr = xSemaphoreCreateBinary(); + while (1) { + pm_light_sleep_enable(); + goto_idle_and_check_stop(period); + pm_light_sleep_disable(); + goto_idle_and_check_stop(period); + pm_switch_freq(10); + goto_idle_and_check_stop(period); + pm_switch_freq(80); + goto_idle_and_check_stop(period); + pm_switch_freq(40); + goto_idle_and_check_stop(period); + } +} + +static esp_err_t spi0_psram_test(void) +{ + DoneSemphr = xSemaphoreCreateCounting(1, 0); + xTaskCreate(psram_read_write_task, "", 2048, (void *)(1), 3, NULL); + if (xSemaphoreTake(DoneSemphr, pdMS_TO_TICKS(1000)) == pdTRUE) { + printf(DRAM_STR("----------SPI0 PSRAM Test Success----------\n\n")); + } else { + printf(DRAM_STR("----------SPI0 PSRAM Test Timeout----------\n\n")); + return ESP_FAIL; + } + + vSemaphoreDelete(DoneSemphr); + /* Wait for test_task to finish up */ + vTaskDelay(100); + return ESP_OK; +} + +static esp_err_t spi0_psram_with_dfs_test(void) +{ + printf("----------Access SPI0 PSRAM with DFS Test----------\n"); + + uint32_t test_loop = 50; + DoneSemphr = xSemaphoreCreateCounting(test_loop, 0); + + xTaskCreatePinnedToCore(pm_switch_task, "", 4096, NULL, 3, NULL, 0); + xTaskCreatePinnedToCore(psram_read_write_task, "", 2048, (void *)(test_loop), 3, NULL, 1); + + int cnt = 0; + while (cnt < test_loop) { + if (xSemaphoreTake(DoneSemphr, pdMS_TO_TICKS(1000)) == pdTRUE) { + cnt++; + } else { + vSemaphoreDelete(DoneSemphr); + printf(DRAM_STR("----------SPI0 PSRAM Test Timeout----------\n\n")); return ESP_FAIL; } } - - free(psram_rd_buf); - free(psram_wr_buf); - printf(DRAM_STR("----------SPI0 PSRAM Test Success----------\n\n")); + xSemaphoreGive(StopSemphr); + vSemaphoreDelete(DoneSemphr); + /* Wait for test_task to finish up */ + vTaskDelay(pdMS_TO_TICKS(500)); + printf(DRAM_STR("----------Access SPI0 PSRAM with DFS Test Success----------\n\n")); return ESP_OK; } #endif @@ -151,6 +288,7 @@ void app_main(void) #if CONFIG_SPIRAM ESP_ERROR_CHECK(spi0_psram_test()); + ESP_ERROR_CHECK(spi0_psram_with_dfs_test()); #endif ESP_ERROR_CHECK(spi1_flash_test()); diff --git a/tools/test_apps/system/flash_psram/sdkconfig.defaults b/tools/test_apps/system/flash_psram/sdkconfig.defaults new file mode 100644 index 0000000000..389e5e448c --- /dev/null +++ b/tools/test_apps/system/flash_psram/sdkconfig.defaults @@ -0,0 +1,9 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT_EN=n + +# For test access psram with DFS enabled +CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y +CONFIG_SPIRAM_RODATA=y +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=5