Merge branch 'feature/s2_s3_support_ext_mem_stack_v4.4' into 'release/v4.4'

soc: support placing task stacks in external memory for S2 and S3 (v4.4)

See merge request espressif/esp-idf!20001
This commit is contained in:
Zim Kalinowski
2022-09-13 21:24:02 +08:00
8 changed files with 105 additions and 55 deletions

View File

@@ -2,7 +2,7 @@
/*
* SPDX-FileCopyrightText: 2017 Intel Corporation
* SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -110,7 +110,7 @@ static void bt_mesh_ble_adv_deinit(void);
struct bt_mesh_adv_task {
TaskHandle_t handle;
#if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \
CONFIG_SPIRAM_CACHE_WORKAROUND && \
(CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY)
StaticTask_t *task;
StackType_t *stack;
@@ -639,7 +639,7 @@ void bt_mesh_adv_init(void)
#endif /* defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) */
#if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \
CONFIG_SPIRAM_CACHE_WORKAROUND && \
(CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY)
adv_task.task = heap_caps_calloc(1, sizeof(StaticTask_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
__ASSERT(adv_task.task, "Failed to create adv thread task");
@@ -648,12 +648,12 @@ void bt_mesh_adv_init(void)
adv_task.handle = xTaskCreateStaticPinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, BLE_MESH_ADV_TASK_STACK_SIZE, NULL,
BLE_MESH_ADV_TASK_PRIO, adv_task.stack, adv_task.task, BLE_MESH_ADV_TASK_CORE);
__ASSERT(adv_task.handle, "Failed to create static adv thread");
#else /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && CONFIG_SPIRAM_CACHE_WORKAROUND && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */
#else /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */
int ret = xTaskCreatePinnedToCore(adv_thread, BLE_MESH_ADV_TASK_NAME, BLE_MESH_ADV_TASK_STACK_SIZE, NULL,
BLE_MESH_ADV_TASK_PRIO, &adv_task.handle, BLE_MESH_ADV_TASK_CORE);
__ASSERT(ret == pdTRUE, "Failed to create adv thread");
(void)ret;
#endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && CONFIG_SPIRAM_CACHE_WORKAROUND && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */
#endif /* CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && (CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY */
}
#if CONFIG_BLE_MESH_DEINIT
@@ -666,7 +666,7 @@ void bt_mesh_adv_deinit(void)
vTaskDelete(adv_task.handle);
adv_task.handle = NULL;
#if (CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL && \
CONFIG_SPIRAM_CACHE_WORKAROUND && \
(CONFIG_SPIRAM_CACHE_WORKAROUND || !CONFIG_IDF_TARGET_ESP32) && \
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY)
heap_caps_free(adv_task.stack);
adv_task.stack = NULL;

View File

@@ -175,6 +175,17 @@ menu "ESP32S2-specific"
If SPIRAM_FETCH_INSTRUCTIONS also enabled,
you can run the instruction when erasing or programming the flash.
config SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
bool "Allow external memory as an argument to xTaskCreateStatic"
default n
help
Accessing memory in SPIRAM has certain restrictions, so task stacks allocated by xTaskCreate
are by default allocated from internal RAM.
This option allows for passing memory allocated from SPIRAM to be passed to xTaskCreateStatic.
This should only be used for tasks where the stack is never accessed while the cache is disabled.
Cannot be used together with ESP_COREDUMP_ENABLE_TO_FLASH.
choice SPIRAM_SPEED
prompt "Set RAM clock speed"
default SPIRAM_SPEED_40M
@@ -191,7 +202,8 @@ menu "ESP32S2-specific"
bool "20Mhz clock speed"
endchoice
# insert non-chip-specific items here
# insert non-chip-specific items here NOERROR
source "$IDF_PATH/components/esp_hw_support/Kconfig.spiram.common"
endmenu

View File

@@ -244,6 +244,17 @@ menu "ESP32S3-Specific"
If SPIRAM_FETCH_INSTRUCTIONS is also enabled,
you can run the instruction when erasing or programming the flash.
config SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
bool "Allow external memory as an argument to xTaskCreateStatic"
default n
help
Accessing memory in SPIRAM has certain restrictions, so task stacks allocated by xTaskCreate
are by default allocated from internal RAM.
This option allows for passing memory allocated from SPIRAM to be passed to xTaskCreateStatic.
This should only be used for tasks where the stack is never accessed while the cache is disabled.
Cannot be used together with ESP_COREDUMP_ENABLE_TO_FLASH.
choice SPIRAM_SPEED
prompt "Set RAM clock speed"
default SPIRAM_SPEED_40M

View File

@@ -1,16 +1,8 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "sdkconfig.h"
@@ -31,10 +23,15 @@
#include "soc/rtc_periph.h"
#include "hal/wdt_hal.h"
#include "freertos/xtensa_api.h"
#include "soc/soc_memory_layout.h"
#include "hal/cpu_hal.h"
#include "esp32s2/rom/rtc.h"
#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1))
extern int _bss_end;
/* "inner" restart function for after RTOS, interrupts & anything else on this
* core are already stopped. Stalls other core, resets hardware,
* triggers restart.
@@ -76,6 +73,17 @@ void IRAM_ATTR esp_restart_noos(void)
// Flush any data left in UART FIFOs
esp_rom_uart_tx_wait_idle(0);
esp_rom_uart_tx_wait_idle(1);
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
if (esp_ptr_external_ram(esp_cpu_get_sp())) {
// If stack_addr is from External Memory (CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is used)
// then need to switch SP to Internal Memory otherwise
// we will get the "Cache disabled but cached memory region accessed" error after Cache_Read_Disable.
uint32_t new_sp = ALIGN_DOWN(_bss_end, 16);
SET_STACK(new_sp);
}
#endif
// Disable cache
Cache_Disable_ICache();
Cache_Disable_DCache();

View File

@@ -1,17 +1,9 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "sdkconfig.h"
@@ -30,10 +22,15 @@
#include "soc/rtc_periph.h"
#include "hal/wdt_hal.h"
#include "freertos/xtensa_api.h"
#include "soc/soc_memory_layout.h"
#include "esp32s3/rom/cache.h"
#include "esp32s3/rom/rtc.h"
#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1))
extern int _bss_end;
/* "inner" restart function for after RTOS, interrupts & anything else on this
* core are already stopped. Stalls other core, resets hardware,
* triggers restart.
@@ -69,6 +66,17 @@ void IRAM_ATTR esp_restart_noos(void)
// Flush any data left in UART FIFOs
esp_rom_uart_tx_wait_idle(0);
esp_rom_uart_tx_wait_idle(1);
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
if (esp_ptr_external_ram(esp_cpu_get_sp())) {
// If stack_addr is from External Memory (CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is used)
// then need to switch SP to Internal Memory otherwise
// we will get the "Cache disabled but cached memory region accessed" error after Cache_Read_Disable.
uint32_t new_sp = ALIGN_DOWN(_bss_end, 16);
SET_STACK(new_sp);
}
#endif
// Disable cache
Cache_Disable_ICache();
Cache_Disable_DCache();

View File

@@ -1,19 +1,13 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "xtensa/xtruntime.h"
#define RSR(reg, at) asm volatile ("rsr %0, %1" : "=r" (at) : "i" (reg))
#define WSR(reg, at) asm volatile ("wsr %0, %1" : : "r" (at), "i" (reg))
#define XSR(reg, at) asm volatile ("xsr %0, %1" : "+r" (at) : "i" (reg))
@@ -23,14 +17,27 @@
#define WITLB(at, as) asm volatile ("witlb %0, %1; \n isync \n " : : "r" (at), "r" (as))
#define WDTLB(at, as) asm volatile ("wdtlb %0, %1; \n dsync \n " : : "r" (at), "r" (as))
#define EXTRA_SAVE_AREA_SIZE 32
#define BASE_SAVE_AREA_SIZE 16
#define SAVE_AREA_OFFSET (EXTRA_SAVE_AREA_SIZE + BASE_SAVE_AREA_SIZE)
#define BASE_AREA_SP_OFFSET 12
/* The SET_STACK implements a setting a new stack pointer (sp or a1).
* to do this the need reset PS_WOE, reset WINDOWSTART, update SP, and return PS_WOE.
*
* In addition, if a windowOverflow8/12 happens the exception handler expects to be able to look at
* the previous frames stackpointer to find the extra save area. So this function will reserve space
* for this area as well as initialise the previous sp that points to it
*
* Note: It has 2 implementations one for using in assembler files (*.S) and one for using in C.
*
* C code prototype for SET_STACK:
* uint32_t ps_reg;
* uint32_t w_base;
*
* uint32_t sp = (uint32_t)new_sp - SAVE_AREA_OFFSET; \
*(uint32_t*)(sp - 12) = (uint32_t)new_sp; \
* RSR(PS, ps_reg);
* ps_reg &= ~(PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK);
* WSR(PS, ps_reg);
@@ -46,6 +53,10 @@
*/
#ifdef __ASSEMBLER__
.macro SET_STACK new_sp tmp1 tmp2
addi tmp1, new_sp, -SAVE_AREA_OFFSET
addi tmp2, tmp1, -BASE_AREA_SP_OFFSET
s32i new_sp, tmp2, 0
addi new_sp, tmp1, 0
rsr.ps \tmp1
movi \tmp2, ~(PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK)
and \tmp1, \tmp1, \tmp2
@@ -68,8 +79,11 @@
rsync
.endm
#else
#define SET_STACK(new_sp) \
do { \
uint32_t sp = (uint32_t)new_sp - SAVE_AREA_OFFSET; \
*(uint32_t*)(sp - BASE_AREA_SP_OFFSET) = (uint32_t)new_sp; \
uint32_t tmp1 = 0, tmp2 = 0; \
asm volatile ( \
"rsr.ps %1 \n"\
@@ -93,6 +107,6 @@
"or %1, %1, %2 \n"\
"wsr.ps %1 \n"\
"rsync \n"\
: "+r"(new_sp), "+r"(tmp1), "+r"(tmp2)); \
: "+r"(sp), "+r"(tmp1), "+r"(tmp2)); \
} while (0);
#endif // __ASSEMBLER__

View File

@@ -125,19 +125,18 @@ External RAM use has the following restrictions:
* When flash cache is disabled (for example, if the flash is being written to), the external RAM also becomes inaccessible; any reads from or writes to it will lead to an illegal cache access exception. This is also the reason why ESP-IDF does not by default allocate any task stacks in external RAM (see below).
* External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Therefore when External RAM is enabled, any buffers that will be used in combination with DMA must be allocated using ``heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL)`` and can be freed using a standard ``free()`` call.
* External RAM cannot be used as a place to store DMA transaction descriptors or as a buffer for a DMA transfer to read from or write into. Therefore when External RAM is enabled, any buffers that will be used in combination with DMA must be allocated using ``heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL)`` and can be freed using a standard ``free()`` call.
.. only:: SOC_PSRAM_DMA_CAPABLE
Note, although {IDF_TARGET_NAME} has hardware support for DMA to/from external RAM, this is not yet supported in ESP-IDF.
* External RAM uses the same cache region as the external flash. This means that frequently accessed variables in external RAM can be read and modified almost as quickly as in internal ram. However, when accessing large chunks of data (>32 KB), the cache can be insufficient, and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can "push out" cached flash, possibly making the execution of code slower afterwards.
* In general, external RAM cannot be used as task stack memory. Due to this, :cpp:func:`xTaskCreate` and similar functions will always allocate internal memory for stack and task TCBs, and functions such as :cpp:func:`xTaskCreateStatic` will check if the buffers passed are internal.
* In general, external RAM will not be used as task stack memory. :cpp:func:`xTaskCreate` and similar functions will always allocate internal memory for stack and task TCBs.
.. only:: esp32
The option :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` can be used to place task stacks into external memory. In these cases :cpp:func:`xTaskCreateStatic` must be used to specify a task stack buffer allocated from external memory, otherwise task stacks will still be allocated from internal memory.
The option :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` can be used to place task stacks into external memory. In these cases :cpp:func:`xTaskCreateStatic` must be used to specify a task stack buffer allocated from external memory, otherwise task stacks will still be allocated from internal memory.
Failure to initialize
=====================

View File

@@ -135,9 +135,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到以 {IDF_TARGET_PSRAM_ADDR_STAR
* 一般来说,片外 RAM 不可用作任务堆栈存储器。因此 :cpp:func:`xTaskCreate` 及类似函数将始终为堆栈和任务 TCB 分配片上储存器,而 :cpp:func:`xTaskCreateStatic` 类型的函数将检查传递的 Buffer 是否属于片上存储器。
.. only:: esp32
可以使用 :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` 选项将任务堆栈放入片外存储器。这时,必须使用 :cpp:func:`xTaskCreateStatic` 指定从片外存储器分配的任务堆栈缓冲区,否则任务堆栈将会从片上存储器分配。
可以使用 :ref:`CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY` 选项将任务堆栈放入片外存储器。这时,必须使用 :cpp:func:`xTaskCreateStatic` 指定从片外存储器分配的任务堆栈缓冲区,否则任务堆栈将会从片上存储器分配。
初始化失败
=====================