change(esp_hw_support): reject sleep request if task stack in PSRAM

This commit is contained in:
wuzhenghui
2025-11-12 21:14:08 +08:00
parent 1e87d43f1a
commit 353075ca30
9 changed files with 49 additions and 19 deletions

View File

@@ -11,6 +11,7 @@
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "esp_attr.h"
#include "esp_cpu.h"
#include "esp_memory_utils.h"
#if CONFIG_SPIRAM
#include "esp_private/esp_psram_extram.h"
@@ -94,4 +95,10 @@ bool esp_stack_ptr_in_extram(uint32_t sp)
//Check if stack ptr is on PSRAM, and 16 byte aligned.
return (esp_psram_check_ptr_addr((void *)sp) && ((sp & 0xF) == 0));
}
bool IRAM_ATTR esp_task_stack_is_sane_cache_disabled(void)
{
const void *sp = (const void *)esp_cpu_get_sp();
return !esp_stack_ptr_in_extram((uint32_t)sp);
}
#endif

View File

@@ -383,6 +383,15 @@ inline static bool esp_stack_ptr_in_dram(uint32_t sp)
* @return true: is in external ram; false: not in external ram
*/
bool esp_stack_ptr_in_extram(uint32_t sp);
/**
* @brief Check if the current task's stack is in internal memory (DRAM or RTC fast memory = not in PSRAM)
*
* This function verifies that the current task's stack is located in internal memory,
*
* @return true if the stack is in non-cacheable memory, false otherwise
*/
bool esp_task_stack_is_sane_cache_disabled(void);
#endif
/**

View File

@@ -612,6 +612,8 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain,
*
* @return
* - No return - If the sleep is not rejected.
* - ESP_ERR_NOT_ALLOWED Since the sleep process disables the cache, the task requesting to enter sleep must have its
* stack located in internal RAM. Tasks with their stacks in PSRAM are not allowed to request sleep.
* - ESP_ERR_INVALID_STATE VBAT power does not meet the requirements for entering deepsleep
* - ESP_ERR_SLEEP_REJECT sleep request is rejected(wakeup source set before the sleep request)
*/
@@ -630,6 +632,8 @@ void esp_deep_sleep_start(void) __attribute__((__noreturn__));
*
* @return
* - ESP_OK on success (returned after wakeup)
* - ESP_ERR_NOT_ALLOWED Since the sleep process disables the cache, the task requesting to enter sleep must have its
* stack located in internal RAM. Tasks with their stacks in PSRAM are not allowed to request sleep.
* - ESP_ERR_SLEEP_REJECT sleep request is rejected(wakeup source set before the sleep request)
* - ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION after deducting the sleep flow overhead, the final sleep duration
* is too short to cover the minimum sleep duration of the chip, when

View File

@@ -1282,7 +1282,14 @@ static esp_err_t FORCE_IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection)
}
}
#endif
#if CONFIG_SPIRAM && CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
if (!esp_task_stack_is_sane_cache_disabled()) {
ESP_LOGE(TAG, "Deep sleep requests are not allowed from tasks with stacks in PSRAM");
if (allow_sleep_rejection) {
return ESP_ERR_NOT_ALLOWED;
}
}
#endif
#if CONFIG_IDF_TARGET_ESP32S2
/* Due to hardware limitations, on S2 the brownout detector sometimes trigger during deep sleep
to circumvent this we disable the brownout detector before sleeping */
@@ -1665,7 +1672,13 @@ esp_err_t esp_light_sleep_start(void)
// if rtc timer wakeup source is enabled, need to compare final sleep duration and min sleep duration to avoid late wakeup
if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) && (final_sleep_duration_us <= min_sleep_duration_us)) {
err = ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION;
} else {
}
#if CONFIG_SPIRAM && CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
else if (!esp_task_stack_is_sane_cache_disabled()) {
err = ESP_ERR_NOT_ALLOWED;
}
#endif
else {
// Enter sleep, then wait for flash to be ready on wakeup
err = esp_light_sleep_inner(sleep_flags, clk_flags, flash_enable_time_us);
}

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,11 +8,10 @@
#include <string.h>
#include "esp_err.h"
#include "esp_private/cache_utils.h"
#include "esp_rom_sys.h"
#ifndef CONFIG_IDF_TARGET_LINUX
#include "esp_private/cache_utils.h"
#include "esp_cpu.h"
#else
/* esp_cpu.h isn't available when building for Linux */
@@ -30,7 +29,7 @@ static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const ch
esp_rom_printf(" (%s)", esp_err_to_name(rc));
#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP
esp_rom_printf(" at 0x%08x\n", esp_cpu_get_call_addr(addr));
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
#if !CONFIG_APP_BUILD_TYPE_PURE_RAM_APP && !CONFIG_IDF_TARGET_LINUX
if (spi_flash_cache_enabled()) // strings may be in flash cache
#endif
{

View File

@@ -43,8 +43,6 @@ ESP_LOG_ATTR_TAG(TAG, "cache");
// Used only on ROM impl. in idf, this param unused, cache status hold by hal
static uint32_t s_flash_op_cache_state[2];
#ifndef CONFIG_FREERTOS_UNICORE
static SemaphoreHandle_t s_flash_op_mutex;
static volatile bool s_flash_op_can_start = false;
@@ -53,17 +51,6 @@ static volatile bool s_flash_op_complete = false;
static volatile int s_flash_op_cpu = -1;
#endif
static inline bool esp_task_stack_is_sane_cache_disabled(void)
{
const void *sp = (const void *)esp_cpu_get_sp();
return esp_ptr_in_dram(sp)
#if CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
|| esp_ptr_in_rtc_dram_fast(sp)
#endif
;
}
void spi_flash_init_lock(void)
{
s_flash_op_mutex = xSemaphoreCreateRecursiveMutex();
@@ -124,7 +111,9 @@ void IRAM_ATTR spi_flash_op_block_func(void *arg)
void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void)
{
#if CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
assert(esp_task_stack_is_sane_cache_disabled());
#endif
spi_flash_op_lock();

View File

@@ -11,6 +11,7 @@
#include <stddef.h>
#include <stdint.h>
#include "esp_err.h"
#include "esp_memory_utils.h"
#ifdef __cplusplus
extern "C" {

View File

@@ -477,6 +477,10 @@ Entering Sleep
It is also possible to enter sleep modes with no wakeup sources configured. In this case, the chip will be in sleep modes indefinitely until external reset is applied.
.. note::
The sleep process will disable the cache, so the task stack of the task requesting sleep must be located in internal memory (DRAM or RTC fast memory). If a task with its stack in PSRAM requests Light-sleep or Deep-sleep, it will be rejected and an error will be returned.
UART Output Handling
^^^^^^^^^^^^^^^^^^^^

View File

@@ -477,6 +477,10 @@ flash 进入 deep power-down 模式
允许在未配置唤醒源的情况下进入睡眠模式。在此情况下,芯片将一直处于睡眠模式,直到从外部被复位。
.. note::
睡眠流程会禁用 cache因此请求睡眠的任务其任务栈必须位于内部内存DRAM 或 RTC fast memory。如果任务栈位于 PSRAM 的任务请求 Light-sleep 或 Deep-sleep将被拒绝并返回错误。
UART 输出处理
^^^^^^^^^^^^^^^^^^^^