mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 11:03:11 +00:00
feat(psram): allow PSRAM to enter halfsleep mode during light sleep
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_HEX=y
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0
|
||||
# Disable PSRAM halfsleep feature, otherwise P4 tcm section overflows with COMPILER_OPTIMIZATION_NONE=y
|
||||
CONFIG_PM_SLP_SPIRAM_HALFSLEEP_ENABLED=n
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_HEX=y
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=0
|
||||
# Disable PSRAM halfsleep feature, otherwise P4 tcm section overflows with COMPILER_OPTIMIZATION_NONE=y
|
||||
CONFIG_PM_SLP_SPIRAM_HALFSLEEP_ENABLED=n
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -263,6 +263,20 @@ static inline void psram_ctrlr_ll_enable_hex_data_line_mode(uint32_t mspi_id, bo
|
||||
SPIMEM2.mem_sram_cmd.mem_sdout_hex = en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get PSRAM hex data line mode enable status
|
||||
*
|
||||
* @param mspi_id mspi_id
|
||||
*
|
||||
* @return true if hex data line mode is enabled, false otherwise
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline bool psram_ctrlr_ll_is_hex_data_line_mode(uint32_t mspi_id)
|
||||
{
|
||||
(void)mspi_id;
|
||||
return (SPIMEM2.mem_sram_cmd.mem_sdin_hex & SPIMEM2.mem_sram_cmd.mem_sdout_hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable PSRAM AXI master access
|
||||
*
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#if CONFIG_SPIRAM
|
||||
#include "hal/ldo_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "esp_private/esp_psram_impl.h"
|
||||
#endif
|
||||
|
||||
#if (CONFIG_ESP_REV_MIN_FULL == 300)
|
||||
@@ -195,7 +196,7 @@ const pmu_sleep_config_t* pmu_sleep_config_default(
|
||||
// Get light sleep analog default
|
||||
pmu_sleep_analog_config_t analog_default = PMU_SLEEP_ANALOG_LSLP_CONFIG_DEFAULT(sleep_flags);
|
||||
|
||||
#if CONFIG_SPIRAM
|
||||
#if CONFIG_SPIRAM && CONFIG_ESP32P4_SELECTS_REV_LESS_V3
|
||||
// Adjust analog parameters to keep EXT_LDO PSRAM channel volt outputting during light-sleep.
|
||||
analog_default.hp_sys.analog.pd_cur = PMU_PD_CUR_SLEEP_ON;
|
||||
analog_default.lp_sys[PMU_MODE_LP_SLEEP].analog.pd_cur = PMU_PD_CUR_SLEEP_ON;
|
||||
@@ -408,11 +409,15 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt,
|
||||
// to be written back so that regdma can get the correct link.
|
||||
// 3. We cannot use the API provided by ROM to invalidate the cache, since it is a function calling that writes data to the stack during
|
||||
// the return process, which results in dirty cachelines in L1 Cache again.
|
||||
pmu_sleep_cache_sync_items(SMMU_GID_DEFAULT, CACHE_SYNC_WRITEBACK, CACHE_MAP_L1_DCACHE, 0, 0);
|
||||
pmu_sleep_cache_sync_items(SMMU_GID_DEFAULT, CACHE_SYNC_WRITEBACK, CACHE_MAP_L1_DCACHE, 0, 0); // No PSRAM dirty data after this time write back
|
||||
|
||||
if (!dslp) {
|
||||
#if CONFIG_SPIRAM
|
||||
psram_ctrlr_ll_wait_all_transaction_done();
|
||||
#if CONFIG_PM_SLP_SPIRAM_HALFSLEEP_ENABLED
|
||||
esp_psram_impl_enter_halfsleep_mode();
|
||||
#endif
|
||||
mspi_ll_hold_all_psram_pins();
|
||||
#endif
|
||||
s_mpll_freq_mhz_before_sleep = rtc_clk_mpll_get_freq();
|
||||
if (s_mpll_freq_mhz_before_sleep) {
|
||||
@@ -426,10 +431,10 @@ TCM_IRAM_ATTR uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt,
|
||||
_psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, false);
|
||||
_psram_ctrlr_ll_enable_module_clock(PSRAM_CTRLR_LL_MSPI_ID_2, false);
|
||||
}
|
||||
mspi_ll_hold_all_psram_pins();
|
||||
#endif
|
||||
rtc_clk_mpll_disable();
|
||||
}
|
||||
pmu_sleep_cache_sync_items(SMMU_GID_DEFAULT, CACHE_SYNC_WRITEBACK, CACHE_MAP_L1_DCACHE, 0, 0); // No L2 MEM dirty data after this time write back
|
||||
} else {
|
||||
#if CONFIG_P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND
|
||||
if (efuse_hal_chip_revision() == 300) {
|
||||
@@ -493,19 +498,26 @@ TCM_IRAM_ATTR bool pmu_sleep_finish(bool dslp)
|
||||
// Wait eFuse memory update done.
|
||||
while(efuse_ll_get_controller_state() != EFUSE_CONTROLLER_STATE_IDLE);
|
||||
|
||||
if (s_mpll_freq_mhz_before_sleep && !dslp) {
|
||||
rtc_clk_mpll_enable();
|
||||
rtc_clk_mpll_configure(clk_hal_xtal_get_freq_mhz(), s_mpll_freq_mhz_before_sleep, true);
|
||||
if (!dslp) {
|
||||
if (s_mpll_freq_mhz_before_sleep) {
|
||||
rtc_clk_mpll_enable();
|
||||
rtc_clk_mpll_configure(clk_hal_xtal_get_freq_mhz(), s_mpll_freq_mhz_before_sleep, true);
|
||||
#if CONFIG_SPIRAM
|
||||
if (!s_pmu_sleep_regdma_backup_enabled) {
|
||||
// MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here.
|
||||
// If it's a PD_TOP sleep, psram MSPI core clock will be enabled by REGDMA
|
||||
_psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true);
|
||||
_psram_ctrlr_ll_enable_module_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true);
|
||||
if (!s_pmu_sleep_regdma_backup_enabled) {
|
||||
// MSPI2 and MSPI3 share the register for core clock. So we only set MSPI2 here.
|
||||
// If it's a PD_TOP sleep, psram MSPI core clock will be enabled by REGDMA
|
||||
_psram_ctrlr_ll_enable_core_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true);
|
||||
_psram_ctrlr_ll_enable_module_clock(PSRAM_CTRLR_LL_MSPI_ID_2, true);
|
||||
}
|
||||
_psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_2, PSRAM_CLK_SRC_MPLL);
|
||||
_psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_3, PSRAM_CLK_SRC_MPLL);
|
||||
#endif
|
||||
}
|
||||
_psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_2, PSRAM_CLK_SRC_MPLL);
|
||||
_psram_ctrlr_ll_select_clk_source(PSRAM_CTRLR_LL_MSPI_ID_3, PSRAM_CLK_SRC_MPLL);
|
||||
#if CONFIG_SPIRAM
|
||||
mspi_ll_unhold_all_psram_pins();
|
||||
#if CONFIG_PM_SLP_SPIRAM_HALFSLEEP_ENABLED
|
||||
esp_psram_impl_exit_halfsleep_mode();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "rtc_time");
|
||||
|
||||
@@ -211,7 +212,7 @@ uint64_t rtc_time_slowclk_to_us(uint64_t rtc_cycles, uint32_t period)
|
||||
return (rtc_cycles * period) >> RTC_CLK_CAL_FRACT;
|
||||
}
|
||||
|
||||
uint64_t rtc_time_get(void)
|
||||
TCM_IRAM_ATTR uint64_t rtc_time_get(void)
|
||||
{
|
||||
return rtc_timer_hal_get_cycle_count(0);
|
||||
}
|
||||
|
||||
@@ -161,6 +161,10 @@
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_PM_SLP_SPIRAM_HALFSLEEP_ENABLED
|
||||
#include "esp_private/esp_psram_impl.h"
|
||||
#endif
|
||||
|
||||
// If light sleep time is less than that, don't power down flash
|
||||
#define FLASH_PD_MIN_SLEEP_TIME_US 2000
|
||||
|
||||
@@ -1382,6 +1386,10 @@ static SLEEP_FN_ATTR esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint3
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_PM_SLP_SPIRAM_HALFSLEEP_ENABLED
|
||||
esp_psram_impl_resume_from_halfsleep_mode(s_config.rtc_clk_cal_period);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION
|
||||
if (sleep_flags & RTC_SLEEP_PD_VDDSDIO) {
|
||||
/* Cache Resume 2: flash is ready now, we can resume the cache and access flash safely after */
|
||||
|
||||
@@ -287,4 +287,28 @@ menu "Power Management"
|
||||
Only enabled when SPI_FLASH_FREQ_LIMIT_C5_240MHZ is enabled.
|
||||
This is an internal configuration, automatically set based on SPI Flash configuration.
|
||||
|
||||
config PM_SLP_SPIRAM_HALFSLEEP_ENABLED
|
||||
bool "Enable halfsleep mode for PSRAM in light sleep"
|
||||
depends on SPIRAM
|
||||
default y
|
||||
help
|
||||
Enable PSRAM halfsleep mode feature to reduce power consumption during light sleep, if the PSRAM used
|
||||
support halfsleep mode.
|
||||
|
||||
When enabled, the PSRAM chip will be configured to enter halfsleep mode (if applicable) before entering
|
||||
light sleep. This reduces power consumption by:
|
||||
1. Setting refresh rate to 0.5x
|
||||
2. Setting PSRAM to halfsleep mode
|
||||
|
||||
The PSRAM will automatically exit halfsleep mode after waking up from light sleep.
|
||||
|
||||
config PM_SLP_SPIRAM_HALFSLEEP_EXIT_WAIT_DELAY
|
||||
int "The time to wait for PSRAM to be able to access after exiting halfsleep mode (in us)"
|
||||
depends on SPIRAM
|
||||
default 150
|
||||
range 50 250
|
||||
help
|
||||
Configure the delay time between waking up PSRAM halfsleep mode and the first access to PSRAM.
|
||||
Refer to the tXHS parameter in datasheet of the used PSRAM to configure this option.
|
||||
|
||||
endmenu # "Power Management"
|
||||
|
||||
@@ -4,7 +4,7 @@ if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
set(includes "include")
|
||||
set(includes "include" "device/include")
|
||||
|
||||
if(CONFIG_SOC_SPIRAM_XIP_SUPPORTED)
|
||||
list(APPEND includes xip_impl/include)
|
||||
@@ -37,7 +37,6 @@ endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${includes}
|
||||
PRIV_INCLUDE_DIRS device/include
|
||||
PRIV_REQUIRES ${priv_requires}
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "hal/mspi_ll.h"
|
||||
#include "clk_ctrl_os.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#define AP_HEX_PSRAM_SYNC_READ 0x0000
|
||||
#define AP_HEX_PSRAM_SYNC_WRITE 0x8080
|
||||
@@ -62,6 +63,8 @@
|
||||
|
||||
#define AP_HEX_PSRAM_REF_DATA 0x5a6b7c8d
|
||||
|
||||
#define AP_HEX_PSRAM_ULP_MODE_HALFSLEEP 0xF0
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
@@ -76,7 +79,7 @@ typedef struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t vendor_id: 5;
|
||||
uint8_t rsvd0_2: 2;
|
||||
uint8_t rsvd5_7: 3;
|
||||
uint8_t ulp: 1;
|
||||
};
|
||||
uint8_t val;
|
||||
@@ -91,9 +94,9 @@ typedef struct {
|
||||
} mr2;
|
||||
union {
|
||||
struct {
|
||||
uint8_t rsvd3_7: 4;
|
||||
uint8_t rsvd0_3: 4;
|
||||
uint8_t srf: 2;
|
||||
uint8_t rsvd0: 1;
|
||||
uint8_t rsvd6: 1;
|
||||
uint8_t rbx_en: 1;
|
||||
};
|
||||
uint8_t val;
|
||||
@@ -106,6 +109,13 @@ typedef struct {
|
||||
};
|
||||
uint8_t val;
|
||||
} mr4;
|
||||
union {
|
||||
struct {
|
||||
uint8_t rsvd0_3: 4;
|
||||
uint8_t halfsleep: 4;
|
||||
};
|
||||
uint8_t val;
|
||||
} mr6;
|
||||
union {
|
||||
struct {
|
||||
uint8_t bl: 2;
|
||||
@@ -507,3 +517,83 @@ esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
|
||||
#endif
|
||||
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
|
||||
/******************************* Halfsleep Mode *******************************/
|
||||
static PSRAM_HALFSLEEP_DATA_ATTR struct {
|
||||
uint8_t mr4;
|
||||
bool is_hex_line_mode;
|
||||
uint64_t halfsleep_wakeup_tick;
|
||||
} s_halfsleep_ctx = {0};
|
||||
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_enter_halfsleep_mode(void)
|
||||
{
|
||||
// Backup line mode configuration and set to 8-line mode (MR registers R/W not support in hex line mode)
|
||||
s_halfsleep_ctx.is_hex_line_mode = psram_ctrlr_ll_is_hex_data_line_mode(PSRAM_CTRLR_LL_MSPI_ID_3);
|
||||
psram_ctrlr_ll_enable_hex_data_line_mode(PSRAM_CTRLR_LL_MSPI_ID_3, false);
|
||||
// Backup MR4
|
||||
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
|
||||
AP_HEX_PSRAM_REG_READ, AP_HEX_PSRAM_RD_CMD_BITLEN,
|
||||
0x4, AP_HEX_PSRAM_ADDR_BITLEN,
|
||||
AP_HEX_PSRAM_RD_REG_DUMMY_BITLEN,
|
||||
NULL, 0,
|
||||
&s_halfsleep_ctx.mr4, 16,
|
||||
false);
|
||||
// Set refresh rate to 0.5x
|
||||
hex_psram_mode_reg_t mode_reg;
|
||||
mode_reg.mr4.val = s_halfsleep_ctx.mr4;
|
||||
mode_reg.mr4.rf = 3; // (0:4x 1:1x 3:0.5x)
|
||||
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
|
||||
AP_HEX_PSRAM_REG_WRITE, AP_HEX_PSRAM_RD_CMD_BITLEN,
|
||||
0x4, AP_HEX_PSRAM_ADDR_BITLEN,
|
||||
0,
|
||||
&mode_reg.mr4.val, 16,
|
||||
NULL, 0,
|
||||
false);
|
||||
// Set halfsleep mode
|
||||
uint8_t halfsleep_cmd = AP_HEX_PSRAM_ULP_MODE_HALFSLEEP;
|
||||
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
|
||||
AP_HEX_PSRAM_REG_WRITE, AP_HEX_PSRAM_RD_CMD_BITLEN,
|
||||
0x6, AP_HEX_PSRAM_ADDR_BITLEN,
|
||||
0,
|
||||
&halfsleep_cmd, 16,
|
||||
NULL, 0,
|
||||
false);
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_exit_halfsleep_mode(void)
|
||||
{
|
||||
// Record the tick exiting halfsleep mode
|
||||
s_halfsleep_ctx.halfsleep_wakeup_tick = rtc_time_get();
|
||||
|
||||
// Do a SPI dummy write transmission to invalid address to wake up from halfsleep mode
|
||||
uint8_t null = 0;
|
||||
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
|
||||
AP_HEX_PSRAM_REG_WRITE, AP_HEX_PSRAM_WR_CMD_BITLEN,
|
||||
0xFF, AP_HEX_PSRAM_ADDR_BITLEN,
|
||||
0,
|
||||
&null, 0,
|
||||
NULL, 0,
|
||||
false);
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_RESUME_CODE_ATTR void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period)
|
||||
{
|
||||
uint64_t halfsleep_exit_tick = s_halfsleep_ctx.halfsleep_wakeup_tick + rtc_time_us_to_slowclk(CONFIG_PM_SLP_SPIRAM_HALFSLEEP_EXIT_WAIT_DELAY, slowclk_period);
|
||||
while (rtc_time_get() < halfsleep_exit_tick) {
|
||||
// Busy wait for PSRAM to exit halfsleep mode
|
||||
}
|
||||
|
||||
// Restore MR4 configuration (restore refresh rate)
|
||||
psram_ctrlr_ll_common_transaction(PSRAM_CTRLR_LL_MSPI_ID_3,
|
||||
AP_HEX_PSRAM_REG_WRITE, AP_HEX_PSRAM_WR_CMD_BITLEN,
|
||||
0x4, AP_HEX_PSRAM_ADDR_BITLEN,
|
||||
0,
|
||||
&s_halfsleep_ctx.mr4, 16,
|
||||
NULL, 0,
|
||||
false);
|
||||
|
||||
// Restore hex line mode if it was enabled before
|
||||
if (s_halfsleep_ctx.is_hex_line_mode) {
|
||||
psram_ctrlr_ll_enable_hex_data_line_mode(PSRAM_CTRLR_LL_MSPI_ID_3, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -433,6 +433,20 @@ static void config_psram_spi_phases(void)
|
||||
psram_ctrlr_ll_set_cs_pin(PSRAM_CTRLR_LL_MSPI_ID_0, PSRAM_LL_CS_ID_1);
|
||||
}
|
||||
|
||||
/******************************* Halfsleep Mode *******************************/
|
||||
// This PSRAM device does not support halfsleep mode
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_enter_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_exit_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_RESUME_CODE_ATTR void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period)
|
||||
{
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------
|
||||
* Following APIs are not required to be IRAM-Safe
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -20,6 +21,21 @@ extern "C" {
|
||||
#define PSRAM_SIZE_32MB (32 * 1024 * 1024)
|
||||
#define PSRAM_SIZE_64MB (64 * 1024 * 1024)
|
||||
|
||||
#if CONFIG_PM_SLP_SPIRAM_HALFSLEEP_ENABLED
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
#define PSRAM_HALFSLEEP_DATA_ATTR TCM_DRAM_ATTR
|
||||
#define PSRAM_HALFSLEEP_SLEEP_CODE_ATTR TCM_IRAM_ATTR
|
||||
#else
|
||||
#define PSRAM_HALFSLEEP_DATA_ATTR DRAM_ATTR
|
||||
#define PSRAM_HALFSLEEP_SLEEP_CODE_ATTR IRAM_ATTR
|
||||
#endif
|
||||
#define PSRAM_HALFSLEEP_RESUME_CODE_ATTR IRAM_ATTR
|
||||
#else
|
||||
#define PSRAM_HALFSLEEP_DATA_ATTR
|
||||
#define PSRAM_HALFSLEEP_SLEEP_CODE_ATTR
|
||||
#define PSRAM_HALFSLEEP_RESUME_CODE_ATTR
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief To get the physical psram size in bytes.
|
||||
*
|
||||
@@ -51,6 +67,29 @@ esp_err_t esp_psram_impl_enable(void);
|
||||
*/
|
||||
uint8_t esp_psram_impl_get_cs_io(void);
|
||||
|
||||
/**
|
||||
* @brief Set psram to halfsleep mode to save power consumption
|
||||
*
|
||||
* It will also set refresh rate to 0.5x.
|
||||
*/
|
||||
void esp_psram_impl_enter_halfsleep_mode(void);
|
||||
|
||||
/**
|
||||
* @brief Make psram exit halfsleep mode (no wait, wait is done in esp_psram_impl_resume_from_halfsleep_mode)
|
||||
*/
|
||||
void esp_psram_impl_exit_halfsleep_mode(void);
|
||||
|
||||
/**
|
||||
* @brief Resume psram from halfsleep mode (also restore refresh rate)
|
||||
*
|
||||
* @param slowclk_period RTC slow clock period, calibration value obtained using rtc_clk_cal
|
||||
*
|
||||
* @note PSRAM requires some time (tHSPU) to fully recover from halfsleep mode.
|
||||
* This function examines the time between exiting halfsleep mode and current time, and busy wait if the time is not long enough.
|
||||
* This shortens the overall busy loop time if wait is done inside esp_psram_impl_exit_halfsleep_mode.
|
||||
*/
|
||||
void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2013-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2013-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -1175,4 +1175,19 @@ esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
|
||||
{
|
||||
return esp_psram_impl_get_physical_size(out_size_bytes);
|
||||
}
|
||||
|
||||
/******************************* Halfsleep Mode *******************************/
|
||||
// This PSRAM device does not support halfsleep mode
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_enter_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_exit_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_RESUME_CODE_ATTR void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // CONFIG_SPIRAM
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2013-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2013-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -577,3 +577,17 @@ esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
|
||||
{
|
||||
return esp_psram_impl_get_physical_size(out_size_bytes);
|
||||
}
|
||||
|
||||
/******************************* Halfsleep Mode *******************************/
|
||||
// This PSRAM device does not support halfsleep mode
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_enter_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_exit_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_RESUME_CODE_ATTR void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -456,3 +456,17 @@ esp_err_t esp_psram_impl_get_available_size(uint32_t *out_size_bytes)
|
||||
#endif
|
||||
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
|
||||
}
|
||||
|
||||
/******************************* Halfsleep Mode *******************************/
|
||||
// This PSRAM supports halfsleep mode, but not implemented yet
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_enter_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_SLEEP_CODE_ATTR void esp_psram_impl_exit_halfsleep_mode(void)
|
||||
{
|
||||
}
|
||||
|
||||
PSRAM_HALFSLEEP_RESUME_CODE_ATTR void esp_psram_impl_resume_from_halfsleep_mode(uint32_t slowclk_period)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@
|
||||
#include "esp_private/esp_psram_io.h"
|
||||
#include "esp_psram.h"
|
||||
#include "esp_private/esp_psram_extram.h"
|
||||
#include "esp_private/esp_psram_impl.h"
|
||||
#include "esp_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
__attribute__((unused)) const static char *TAG = "PSRAM";
|
||||
|
||||
@@ -58,6 +60,21 @@ TEST_CASE("stress test psram heap allocable", "[psram][manual][ignore]")
|
||||
}
|
||||
}
|
||||
|
||||
#if !CONFIG_SPIRAM_XIP_FROM_PSRAM
|
||||
TEST_CASE("test psram halfsleep mode (if applicable)", "[psram]")
|
||||
{
|
||||
uint32_t rtc_slow_clk_period = rtc_clk_cal(CLK_CAL_RTC_SLOW, CONFIG_RTC_CLK_CAL_CYCLES);
|
||||
s_test_psram_heap_allocable();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
esp_psram_impl_enter_halfsleep_mode();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
esp_psram_impl_exit_halfsleep_mode();
|
||||
esp_psram_impl_resume_from_halfsleep_mode(rtc_slow_clk_period);
|
||||
s_test_psram_heap_allocable();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPIRAM_XIP_FROM_PSRAM
|
||||
/*---------------------------------------------------------------
|
||||
SPI1 with XIP
|
||||
|
||||
Reference in New Issue
Block a user