From 931f95068adaafbdf1e40e2b22a68983e1afe6b1 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Wed, 24 Jul 2024 14:11:08 +0800 Subject: [PATCH 1/2] feat(spiram): Add temperature support for psram adjustment on esp32c5 --- .../mspi_timing_by_mspi_delay.c | 256 +++++++++++++++++- .../mspi_timing_by_mspi_delay.h | 9 +- .../esp_hw_support/mspi_timing_tuning.c | 3 + .../port/esp32s3/mspi_timing_tuning_configs.h | 13 +- components/esp_psram/esp32s3/Kconfig.spiram | 19 ++ components/esp_system/system_init_fn.txt | 4 + 6 files changed, 298 insertions(+), 6 deletions(-) diff --git a/components/esp_hw_support/mspi_timing_by_mspi_delay.c b/components/esp_hw_support/mspi_timing_by_mspi_delay.c index e3c3a86665..19ca724b54 100644 --- a/components/esp_hw_support/mspi_timing_by_mspi_delay.c +++ b/components/esp_hw_support/mspi_timing_by_mspi_delay.c @@ -27,6 +27,13 @@ #include "bootloader_flash.h" #include "esp32s3/rom/spi_flash.h" #include "esp32s3/rom/opi_flash.h" +#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR +#include "mspi_timing_tuning_configs.h" +#include "freertos/FreeRTOS.h" +#include "esp_private/cache_utils.h" +#include "esp_private/sar_periph_ctrl.h" +#include "esp_private/startup_internal.h" +#endif // CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR #define OPI_PSRAM_SYNC_READ 0x0000 #define OPI_PSRAM_SYNC_WRITE 0x8080 @@ -411,6 +418,12 @@ static bool get_working_pll_freq(const uint8_t *reference_data, bool is_flash, u } #endif //Frequency Scanning +#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR +// These arrays store the frequency scan result of the timing points +int psram_pass_freq_min[MSPI_TIMING_CONFIG_NUM_MAX] = {0}; +int psram_pass_freq_max[MSPI_TIMING_CONFIG_NUM_MAX] = {0}; +#endif // CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR + static uint32_t s_select_best_tuning_config_dtr(const mspi_timing_config_t *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash) { #if (MSPI_TIMING_CORE_CLOCK_MHZ == 160) @@ -441,10 +454,11 @@ static uint32_t s_select_best_tuning_config_dtr(const mspi_timing_config_t *conf bool ret = false; //This `max_freq` is the max pll frequency that per MSPI timing tuning config can work - uint32_t max_freq = 0; uint32_t temp_max_freq = 0; uint32_t temp_min_freq = 0; +#if !CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR + uint32_t max_freq = 0; for (; current_point <= end; current_point++) { if (is_flash) { mspi_timing_config_flash_set_tuning_regs(configs, current_point); @@ -465,6 +479,48 @@ static uint32_t s_select_best_tuning_config_dtr(const mspi_timing_config_t *conf } else { ESP_EARLY_LOGD(TAG, "freq scan success, max pll is %" PRIu32 "mhz, best point is index %" PRIu32, max_freq, best_point); } +#else + uint32_t freq_diff_min = 0xffffffff; + for (; current_point <= end; current_point++) { + if (is_flash) { + mspi_timing_config_flash_set_tuning_regs(configs, current_point); + } else { + mspi_timing_config_psram_set_tuning_regs(configs, current_point); + } + + ret = get_working_pll_freq(reference_data, is_flash, &temp_max_freq, &temp_min_freq); + if (ret == true) { + if (temp_min_freq == MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN) { + // divided by 4 for mspi clk frequency + psram_pass_freq_min[current_point] = (temp_max_freq - MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ) / 4; // use MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ to calculate the real frequency + psram_pass_freq_max[current_point] = temp_max_freq / 4; + } else if (temp_max_freq == MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX) { + psram_pass_freq_min[current_point] = temp_min_freq / 4; + psram_pass_freq_max[current_point] = (temp_min_freq + MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ) / 4; // use MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ to calculate the real frequency + } else { + psram_pass_freq_min[current_point] = temp_min_freq / 4; + psram_pass_freq_max[current_point] = temp_max_freq / 4; + } + ESP_EARLY_LOGD(TAG, "sample point %" PRIu32 ", max pll is %" PRIu32 " mhz, min pll is %" PRIu32 " mhz, max spi is %" PRIu32 " mhz, min spi is %" PRIu32 " mhz", current_point, temp_max_freq, temp_min_freq, psram_pass_freq_max[current_point], psram_pass_freq_min[current_point]); + + // calculate the difference to psram_pass_freq and 120MHz + int temp_min_freq_diff = abs(120 - psram_pass_freq_min[current_point]); + int temp_max_freq_diff = abs(psram_pass_freq_max[current_point] - 120); + + if (abs(temp_min_freq_diff - temp_max_freq_diff) < freq_diff_min) { + freq_diff_min = abs(temp_min_freq_diff - temp_max_freq_diff); + best_point = current_point; + } + } + } + if (freq_diff_min == 0xffffffff) { + ESP_EARLY_LOGW(TAG, "freq scan tuning fail, best point is fallen back to index %" PRIu32, end + 1 - consecutive_length); + best_point = end + 1 - consecutive_length; + } else { + ESP_EARLY_LOGD(TAG, "freq scan success, best point is index %" PRIu32, best_point); + } + +#endif return best_point; @@ -630,3 +686,201 @@ uint8_t mspi_timing_config_get_flash_extra_dummy(void) return 0; #endif } + +#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR + +#define INTERVAL_IN_SECOND CONFIG_SPIRAM_TIMING_MEASURE_TEMPERATURE_INTERVAL_SECOND + +// These arrays store the frequency scan result of the timing points +static int s_point_temp_range_min[MSPI_TIMING_CONFIG_NUM_MAX] = {0}; +static int s_point_temp_range_max[MSPI_TIMING_CONFIG_NUM_MAX] = {0}; +static uint32_t s_psram_best_point_idx = 0; + +void mspi_timing_setting_temperature_adjustment_best_point(uint32_t best_point) +{ + s_psram_best_point_idx = best_point; +} + +static void mspi_timing_set_psram_point_idx(uint32_t point_idx) +{ + mspi_timing_config_t timing_configs = {0}; + s_psram_best_point_idx = point_idx; + mspi_timing_get_psram_tuning_configs(&timing_configs); + + mspi_timing_psram_set_best_tuning_config(&timing_configs, point_idx); + mspi_timing_config_psram_set_tuning_regs(&timing_configs, point_idx); +} + +static void set_timing_point(uint32_t point_idx) +{ + // Disable cache in order that cache would not touch psram + spi_flash_disable_interrupts_caches_and_other_cpu(); + mspi_timing_set_psram_point_idx(point_idx); + spi_flash_enable_interrupts_caches_and_other_cpu(); +} + +// A mean filter with window to make the temperature value smoother +static esp_err_t temperature_sensor_get_celsius_filtered(int16_t *temp_filtered) +{ + const int filter_window_len = 7; + int16_t temp_arr[filter_window_len]; + int16_t temp_sum = 0; + uint8_t temp_min_idx = 0; + uint8_t temp_max_idx = 0; + + for (uint8_t idx = 0; idx < filter_window_len; idx++) { + temp_arr[idx] = temp_sensor_get_raw_value(NULL); + // record the index of the max and min temperature value + if (temp_arr[idx] > temp_arr[temp_max_idx]) temp_max_idx = idx; + if (temp_arr[idx] < temp_arr[temp_min_idx]) temp_min_idx = idx; + temp_sum += temp_arr[idx]; + } + // remove the max and min temperature value + temp_sum -= temp_arr[temp_max_idx]; + temp_sum -= temp_arr[temp_min_idx]; + *temp_filtered = temp_sum / (filter_window_len - 2); // Don't calculate the temp_max and temp_min + + return ESP_OK; +} + +/** + * This task will: + * 1. Calculate temperature ranges of timing points + * 2. Monitor current temperature + * 3. Switch timing point if temperature is beyond the range + */ +void adjust_psram_timing_point_task(void *arg) +{ + int16_t temp_refer = 0, temp_curr = 0; + (void)arg; + temperature_sensor_power_acquire(); + temperature_sensor_get_celsius_filtered(&temp_refer); // get the refer temperature + + int temperature_freq_radio = 5; // It means that the frequency will reduce by 1MHz when the temperature rises 5℃ + const int temperature_safe_range = 5; // A temperature buffer zone to avoid switching timing points frequently + // make sure the frequency of current timing point is greater than freq_thres_max and less than freq_thres_min + const int freq_thres_max = 128; // threshold for maximum threshold frequency in specific temperature, should not change + const int freq_thres_min = 112; // threshold for minimum threshold frequency in specific temperature, should not change + int point_curr = s_psram_best_point_idx; + bool valid_point[MSPI_TIMING_CONFIG_NUM_MAX] = {false}; + + // 1. Get the delta of frequency we get at the specific temperature (freq_min) with the frequency min threshold (freq_diff = freq_thres_min - freq_min) + // 2. Convert frequency difference to temperature difference by radio (5), temperature_diff = freq_diff * radio + // 3. Calculate the range of temperature: temperature_thre_min = freq_min - temperature_diff + // Same for the temperature_thre_max. + + // calculate temperature ranges of the every timing point + for (uint32_t point = 0; point < MSPI_TIMING_CONFIG_NUM_MAX; point++) { + if (psram_pass_freq_min[point] == 0 && psram_pass_freq_max[point] == 0) { + continue; + } + valid_point[point] = true; + uint32_t pass_freq_min = psram_pass_freq_min[point]; + uint32_t pass_freq_max = psram_pass_freq_max[point]; + + if (pass_freq_max >= freq_thres_max) { + // frequency pass_freq_max greater than freq_thres_max, it will decrease to freq_thres_max until temperature rise to s_point_temp_range_max + s_point_temp_range_max[point] = temp_refer + (pass_freq_max - freq_thres_max) * temperature_freq_radio; + } else { + // frequency pass_freq_max less than freq_thres_max, it will increase to freq_thres_max until temperature drop to s_point_temp_range_max + s_point_temp_range_max[point] = temp_refer - (freq_thres_max - pass_freq_max) * temperature_freq_radio; + } + + if (pass_freq_min <= freq_thres_min) { + // frequency pass_freq_min less than freq_thres_min, it will increase to freq_thres_min until temperature drop to s_point_temp_range_min + s_point_temp_range_min[point] = temp_refer - (freq_thres_min - pass_freq_min) * temperature_freq_radio; + } else { + // frequency pass_freq_min greater than freq_thres_min, it will decrease to freq_thres_min until temperature rise to s_point_temp_range_min + s_point_temp_range_min[point] = temp_refer + (pass_freq_min - freq_thres_min) * temperature_freq_radio; + } + } + + for (uint32_t point = 0; point < MSPI_TIMING_CONFIG_NUM_MAX - 1; point++) { + if (valid_point[point] && valid_point[point + 1]) { + // check temperature intersection + if (s_point_temp_range_max[point] <= s_point_temp_range_min[point + 1]) { + ESP_EARLY_LOGE(TAG, "no temperature intersection of neighboring phase points"); + abort(); + } + } + } + + while (1) { + vTaskDelay(INTERVAL_IN_SECOND * 1000 / portTICK_PERIOD_MS); + + point_curr = s_psram_best_point_idx; + temperature_sensor_get_celsius_filtered(&temp_curr); + ESP_EARLY_LOGD(TAG, "Getting current temperature value is: %d", temp_curr); + + // Switch timing point if temperature is beyond the range + if (s_point_temp_range_max[point_curr] == 0 && s_point_temp_range_min[point_curr] == 0) { + // The current timing point has no frequency scan result (psram_pass_freq_min and psram_pass_freq_min equal to 0), + // use the previous or next timing point's temperature range to decide what temperature to switch timing point. + + // Use previous timing point's temperature range + + if (point_curr - 1 >= 0) { + if (s_point_temp_range_max[point_curr - 1] != 0 && s_point_temp_range_min[point_curr - 1] != 0) { + if (temp_curr < (s_point_temp_range_max[point_curr - 1] - temperature_safe_range)) { + int point_next = point_curr - 1; + set_timing_point(point_next); + ESP_EARLY_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next); + continue; + } + } + } + + // Use next timing point's temperature range + if (point_curr + 1 < MSPI_TIMING_CONFIG_NUM_MAX) { + if (s_point_temp_range_max[point_curr + 1] != 0 && s_point_temp_range_min[point_curr + 1] != 0) { + if (temp_curr > s_point_temp_range_min[point_curr + 1] + temperature_safe_range) { + int point_next = point_curr + 1; + set_timing_point(point_next); + ESP_EARLY_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next); + continue; + } + } + } + } else { + // Current temperature is greater than the range, switch to next timing point + if (point_curr + 1 < MSPI_TIMING_CONFIG_NUM_MAX) { + if (temp_curr > s_point_temp_range_max[point_curr]) { + int point_next = point_curr + 1; + set_timing_point(point_next); + ESP_EARLY_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next); + continue; + } + } + + // Current temperature is less than the range, switch to previous timing point + if (point_curr - 1 >= 0) { + if (temp_curr < s_point_temp_range_min[point_curr]) { + int point_next = point_curr - 1; + set_timing_point(point_next); + ESP_EARLY_LOGD(TAG, "PSRAM set timing point from %d to %ld\n", point_curr, point_next); + continue; + } + } + } + } +} + +static esp_err_t psram_adjust_timing_point_via_tsens(void) +{ + esp_rom_spiflash_chip_t *chip = &rom_spiflash_legacy_data->chip; + uint8_t vender_id = (chip->device_id >> 16) & 0xff; + if (vender_id == 0xC8 || vender_id == 0x20) { + xTaskCreatePinnedToCore(adjust_psram_timing_point_task, "adjust_psram_timing_point_task", 1024 * 5, NULL, configMAX_PRIORITIES - 2, NULL, 0); + } else { + ESP_EARLY_LOGE(TAG, "The flash model has not been verified support this feature, please contact espressif business support"); + return ESP_ERR_NOT_SUPPORTED; + } + return ESP_OK; +} + +ESP_SYSTEM_INIT_FN(psram_adjust_timing_point_via_temperature, SECONDARY, BIT(0), 240) +{ + return psram_adjust_timing_point_via_tsens(); +} + +#endif //CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR diff --git a/components/esp_hw_support/mspi_timing_by_mspi_delay.h b/components/esp_hw_support/mspi_timing_by_mspi_delay.h index 178d793260..9e9e77029e 100644 --- a/components/esp_hw_support/mspi_timing_by_mspi_delay.h +++ b/components/esp_hw_support/mspi_timing_by_mspi_delay.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -248,6 +248,13 @@ uint8_t mspi_timing_config_get_flash_extra_dummy(void); #endif //#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY +#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR +/** + * @brief Set best point for psram timing tuning dynamic temperature scheme + */ +void mspi_timing_setting_temperature_adjustment_best_point(uint32_t best_point); +#endif // CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/mspi_timing_tuning.c b/components/esp_hw_support/mspi_timing_tuning.c index bfab81120a..4d3e4e2685 100644 --- a/components/esp_hw_support/mspi_timing_tuning.c +++ b/components/esp_hw_support/mspi_timing_tuning.c @@ -287,6 +287,9 @@ static void s_select_best_tuning_config(mspi_timing_config_t *config, uint32_t c } else { #if MSPI_TIMING_PSRAM_DTR_MODE best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, reference_data, IS_DDR); +#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR + mspi_timing_setting_temperature_adjustment_best_point(best_point); +#endif #elif MSPI_TIMING_PSRAM_STR_MODE best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, NULL, IS_SDR); #endif diff --git a/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h b/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h index b20cf0a69a..22ab5dccba 100644 --- a/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h +++ b/components/esp_hw_support/port/esp32s3/mspi_timing_tuning_configs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,7 +15,7 @@ #define MSPI_TIMING_PSRAM_TEST_DATA_ADDR 0 #define MSPI_TIMING_FLASH_TEST_DATA_ADDR ESP_BOOTLOADER_OFFSET /** - * @note BACKGOURND: + * @note BACKGROUND: * * The SPI FLASH module clock and SPI PSRAM module clock is divided from the SPI core clock, core clock is from system clock: * @@ -24,7 +24,7 @@ * RTC8M ----| |---- PSRAM Module Clock * * - * DDR stands for double data rate, MSPI samples at both posedge and negedge. So the real spped will be doubled. + * DDR stands for double data rate, MSPI samples at both posedge and negedge. So the real speed will be doubled. * Speed from high to low: 120M DDR > 80M DDR > 120 SDR > 80M SDR > ... * * Module with speed lower than 120M SDR doesn't need to be tuned @@ -249,11 +249,16 @@ ESP_STATIC_ASSERT(CHECK_POWER_OF_2(MSPI_TIMING_CORE_CLOCK_MHZ / MSPI_TIMING_PSRA //------------------------------------------Frequency Scanning Related-----------------------------------------------// /** * On ESP32S3, only module clock 120M, DDR mode needs frequency scan. Frequency scanning is to get the max workable PLL - * frequency under each successfull timing tuning configuration. PLL frequency may fluctuate under high temperature, + * frequency under each successful timing tuning configuration. PLL frequency may fluctuate under high temperature, * this method is to get the tuning configuration that can work under higher PLL frequency. */ +#if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR +#define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN 424 +#else #define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MIN 440 +#endif #define MSPI_TIMING_PLL_FREQ_SCAN_RANGE_MHZ_MAX 600 #define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_LOW 448 #define MSPI_TIMING_PLL_FREQ_SCAN_THRESH_MHZ_HIGH 520 +#define MSPI_TIMING_PLL_FREQ_SCAN_WIDTH_MHZ 160 #define MSPI_TIMING_PLL_FREQ_SCAN_STEP_MHZ_MODULE_CLK_120M 8 diff --git a/components/esp_psram/esp32s3/Kconfig.spiram b/components/esp_psram/esp32s3/Kconfig.spiram index 8152ff680a..4663437629 100644 --- a/components/esp_psram/esp32s3/Kconfig.spiram +++ b/components/esp_psram/esp32s3/Kconfig.spiram @@ -117,6 +117,25 @@ menu "SPI RAM config" bool "40Mhz clock speed" endchoice + config SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR + depends on SPIRAM_SPEED_120M && SPIRAM_MODE_OCT && IDF_EXPERIMENTAL_FEATURES + bool "Adjust PSRAM timing tuning point via on-chip temperature sensor in real-time" + default n + help + Temperature would influence the source clock frequency so that the timing tuning point set in start-up + might not be always proper when temperature varies in high range. This configuration would help checking + the temperature in real-time, and adjust timing point automatically when temperature change. + (see External RAM documentation for more details) + + config SPIRAM_TIMING_MEASURE_TEMPERATURE_INTERVAL_SECOND + depends on SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR + int "PSRAM timing tuning measure temperature interval (unit: second)" + default 5 + help + Due to adjusting timing point automatically when temperature change, the task will measure current + temperature value in some specific interval. This configuration option would help you to set the + proper interval. The interval unit is second. + config SPIRAM_SPEED int default 120 if SPIRAM_SPEED_120M diff --git a/components/esp_system/system_init_fn.txt b/components/esp_system/system_init_fn.txt index 0af7db8733..42dc368893 100644 --- a/components/esp_system/system_init_fn.txt +++ b/components/esp_system/system_init_fn.txt @@ -105,6 +105,10 @@ SECONDARY: 220: esp_usb_console_init_restart_timer in components/esp_system/port # This makes more sense to be done after esp_pm_impl_init (called from init_pm). SECONDARY: 230: usb_serial_jtag_conn_status_init in components/esp_driver_usb_serial_jtag/src/usb_serial_jtag_connection_monitor.c on BIT(0) +# psram adjust timing point need a separate task which should be created at startup. +# Valid only `CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR` is enabled. +SECONDARY: 240: psram_adjust_timing_point_via_temperature in components/esp_hw_support/mspi_timing_by_mspi_delay.c on BIT(0) + # Has to be the last step! # Now that the application is about to start, disable boot watchdog SECONDARY: 999: init_disable_rtc_wdt in components/esp_system/startup_funcs.c on BIT(0) From efff933047b1110c016d5b4c8d3b0f9cd4413d96 Mon Sep 17 00:00:00 2001 From: "C.S.M" Date: Wed, 24 Jul 2024 14:12:02 +0800 Subject: [PATCH 2/2] docs(spiram): Add docs for adjusting timing phase via temperature --- docs/en/api-guides/flash_psram_config.rst | 4 ++++ docs/zh_CN/api-guides/flash_psram_config.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/en/api-guides/flash_psram_config.rst b/docs/en/api-guides/flash_psram_config.rst index 01587b2062..77f801113b 100644 --- a/docs/en/api-guides/flash_psram_config.rst +++ b/docs/en/api-guides/flash_psram_config.rst @@ -99,6 +99,10 @@ All Supported Modes and Speeds Note 20 celsius degree is not a totally correct number. This value may changes among chips. +.. note:: + + The PSRAM requires a phase point calibration algorithm when operating at 120M. The phase point setting is related to the temperature at startup. When the temperature increases / decreases significantly during the operation of the chip, the PSRAM may experience read/write errors. To solve this problem, you can enable dynamic adjustment of the PSRAM phase point based on the temperature value with :ref:`CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR`. This creates a task that measures the temperature every :ref:`CONFIG_SPIRAM_TIMING_MEASURE_TEMPERATURE_INTERVAL_SECOND` seconds and adjusts the PSRAM phase point accordingly. + F8R8 Hardware ^^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-guides/flash_psram_config.rst b/docs/zh_CN/api-guides/flash_psram_config.rst index f7432c30e4..358e16e111 100644 --- a/docs/zh_CN/api-guides/flash_psram_config.rst +++ b/docs/zh_CN/api-guides/flash_psram_config.rst @@ -99,6 +99,10 @@ SPI Flash 和片外 SPI RAM 配置 请注意,20 摄氏度并不是一个完全准确的数字,这个值在不同芯片间可能会有所不同。 +.. note:: + + PSRAM 在 120M 运行时需要相位点校准算法。相位点设置与启动时的温度有关。当芯片运行期间温度大幅上升(下降)时,PSRAM 可能会出现读写错误。为解决这一问题,可以使能 :ref:`CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR`,根据温度值动态调整 PSRAM 相位点。这将创建一个任务,每隔 :ref:`CONFIG_SPIRAM_TIMING_MEASURE_TEMPERATURE_INTERVAL_SECOND` 秒测量一次温度,并相应调整 PSRAM 相位点。 + F8R8 硬件 ^^^^^^^^^