Merge branch 'feature/support_bss_on_psram' into 'master'

psram: support .bss on psram on esp32s3

Closes IDF-4814, IDF-4396, IDFGH-7148, and IDFGH-7153

See merge request espressif/esp-idf!17557
This commit is contained in:
Armando (Dou Yiwen) 2022-04-20 11:16:28 +08:00
commit 5bb59b00e7
36 changed files with 611 additions and 390 deletions

View File

@ -195,9 +195,14 @@ menu "ESP32S2-specific"
bool "20Mhz clock speed"
endchoice
config SPIRAM_SPEED
int
default 80 if SPIRAM_SPEED_80M
default 40 if SPIRAM_SPEED_40M
default 40 if SPIRAM_SPEED_26M
default 40 if SPIRAM_SPEED_20M
# insert non-chip-specific items here NOERROR
source "$IDF_PATH/components/esp_hw_support/Kconfig.spiram.common"
source "$IDF_PATH/components/esp_hw_support/Kconfig.spiram.common" #insert non-chip-specific items here
endmenu

View File

@ -66,9 +66,19 @@ extern "C" {
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
// Forces bss variable into external memory. "
#define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__)
#define EXT_RAM_BSS_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__)
#else
#define EXT_RAM_ATTR
#define EXT_RAM_BSS_ATTR
#endif
/**
* Deprecated Macro for putting .bss on PSRAM
*/
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
// Forces bss variable into external memory. "
#define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__) _Pragma ("GCC warning \"'EXT_RAM_ATTR' macro is deprecated, please use `EXT_RAM_BSS_ATTR`\"")
#else
#define EXT_RAM_ATTR _Pragma ("GCC warning \"'EXT_RAM_ATTR' macro is deprecated, please use `EXT_RAM_BSS_ATTR`\"")
#endif
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst"

View File

@ -116,8 +116,8 @@ TEST_CASE_MULTIPLE_STAGES("Spiram test noinit memory", "[spiram]", write_spiram_
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
#define TEST_BSS_NUM 256
static EXT_RAM_ATTR uint32_t s_bss_buffer[TEST_BSS_NUM];
#define TEST_BSS_NUM (256 * 1024)
static EXT_RAM_BSS_ATTR uint32_t s_bss_buffer[TEST_BSS_NUM];
TEST_CASE("Test variables placed in external .bss segment", "[ld]")
{

View File

@ -92,15 +92,15 @@ config SPIRAM_MALLOC_RESERVE_INTERNAL
config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
bool "Allow .bss segment placed in external memory"
default n
depends on SPIRAM && (IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2) # ESP32-S3 IDF-1974
depends on SPIRAM
select ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY
help
If enabled, variables with EXT_RAM_ATTR attribute will be placed in SPIRAM instead of internal DRAM.
If enabled, variables with EXT_RAM_BSS_ATTR attribute will be placed in SPIRAM instead of internal DRAM.
BSS section of `lwip`, `net80211`, `pp`, `bt` libraries will be automatically placed
in SPIRAM. BSS sections from other object files and libraries can also be placed in SPIRAM through
linker fragment scheme `extram_bss`.
Note that the variables placed in SPIRAM using EXT_RAM_ATTR will be zero initialized.
Note that the variables placed in SPIRAM using EXT_RAM_BSS_ATTR will be zero initialized.
config SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
bool "Allow .noinit segment placed in external memory"

View File

@ -12,17 +12,22 @@
#include "soc/soc_caps.h"
#include "esp_attr.h"
#include "esp_memory_utils.h"
#include "esp_private/spiram_private.h"
//TODO: IDF-4855, replace PSRAM related address region into PSRAM private APIs
bool esp_ptr_dma_ext_capable(const void *p)
{
#ifdef SOC_PSRAM_DMA_CAPABLE
return (intptr_t)p >= SOC_DMA_EXT_LOW && (intptr_t)p < SOC_DMA_EXT_HIGH;
#if !SOC_PSRAM_DMA_CAPABLE
return false;
#endif //!SOC_PSRAM_DMA_CAPABLE
#if CONFIG_SPIRAM
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
return (intptr_t)p >= vaddr_start && (intptr_t)p < vaddr_end;
#else
return false;
#endif
#endif //CONFIG_SPIRAM
}
bool esp_ptr_byte_accessible(const void *p)
@ -37,27 +42,36 @@ bool esp_ptr_byte_accessible(const void *p)
r |= (ip >= SOC_RTC_DRAM_LOW && ip < SOC_RTC_DRAM_HIGH);
#endif
#if CONFIG_SPIRAM
#if CONFIG_SPIRAM_SIZE != -1 // Fixed size, can be more accurate
r |= (ip >= SOC_EXTRAM_DATA_LOW && ip < (SOC_EXTRAM_DATA_LOW + CONFIG_SPIRAM_SIZE));
#else
r |= (ip >= SOC_EXTRAM_DATA_LOW && ip < (SOC_EXTRAM_DATA_HIGH));
#endif
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
r |= (ip >= vaddr_start && ip < vaddr_end);
#endif
return r;
}
bool esp_ptr_external_ram(const void *p) {
#if SOC_SPIRAM_SUPPORTED
return ((intptr_t)p >= SOC_EXTRAM_DATA_LOW && (intptr_t)p < SOC_EXTRAM_DATA_HIGH);
bool esp_ptr_external_ram(const void *p)
{
#if !SOC_SPIRAM_SUPPORTED
return false;
#endif //!SOC_SPIRAM_SUPPORTED
#if CONFIG_SPIRAM
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
return (intptr_t)p >= vaddr_start && (intptr_t)p < vaddr_end;
#else
return false; // SoC has no external RAM
#endif
return false;
#endif //CONFIG_SPIRAM
}
#if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
bool esp_stack_ptr_in_extram(uint32_t sp)
{
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
//Check if stack ptr is in between SOC_EXTRAM_DATA_LOW and SOC_EXTRAM_DATA_HIGH, and 16 byte aligned.
return !(sp < SOC_EXTRAM_DATA_LOW + 0x10 || sp > SOC_EXTRAM_DATA_HIGH - 0x10 || ((sp & 0xF) != 0));
return !(sp < vaddr_start + 0x10 || sp > vaddr_end - 0x10 || ((sp & 0xF) != 0));
}
#endif

View File

@ -0,0 +1,57 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include "esp_err.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ESP_SPIRAM_SIZE_16MBITS = 0, /*!< SPI RAM size is 16 MBits */
ESP_SPIRAM_SIZE_32MBITS = 1, /*!< SPI RAM size is 32 MBits */
ESP_SPIRAM_SIZE_64MBITS = 2, /*!< SPI RAM size is 64 MBits */
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
} esp_spiram_size_t;
/**
* @brief Get the size of the attached SPI RAM chip selected in menuconfig
*
* @return Size in bytes, or 0 if no external RAM chip support compiled in.
*/
size_t esp_spiram_get_size(void);
/**
* @brief Get the psram mapped vaddr range
*
* @param[out] out_vstart PSRAM virtual address start
* @param[out] out_vend PSRAM virtual address end
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE PSRAM is not initialized successfully
*/
esp_err_t esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend);
/**
* @brief Get the psram alloced vaddr range
*
* @param[out] out_vstart PSRAM virtual address start
* @param[out] out_vend PSRAM virtual address end
*
* @return
* - ESP_OK On success
* - ESP_ERR_INVALID_STATE PSRAM is not initialized successfully
*/
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend);
#ifdef __cplusplus
}
#endif

View File

@ -17,20 +17,7 @@
extern "C" {
#endif
typedef enum {
ESP_SPIRAM_SIZE_16MBITS = 0, /*!< SPI RAM size is 16 MBits */
ESP_SPIRAM_SIZE_32MBITS = 1, /*!< SPI RAM size is 32 MBits */
ESP_SPIRAM_SIZE_64MBITS = 2, /*!< SPI RAM size is 64 MBits */
ESP_SPIRAM_SIZE_INVALID, /*!< SPI RAM size is invalid */
} esp_spiram_size_t;
/**
* @brief get SPI RAM size
* @return
* - ESP_SPIRAM_SIZE_INVALID if SPI RAM not enabled or not valid
* - SPI RAM size
*/
esp_spiram_size_t esp_spiram_get_chip_size(void);
//TODO: IDF-4382, unify `target/spiram.h`, update migration guide as well
/**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c.
@ -67,15 +54,6 @@ bool esp_spiram_test(void);
*/
esp_err_t esp_spiram_add_to_heapalloc(void);
/**
* @brief Get the size of the attached SPI RAM chip selected in menuconfig
*
* @return Size in bytes, or 0 if no external RAM chip support compiled in.
*/
size_t esp_spiram_get_size(void);
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the SPI

View File

@ -29,13 +29,6 @@ esp_err_t esp_spiram_init(void);
*/
esp_err_t esp_spiram_add_to_heapalloc(void);
/**
* @brief Get the size of the attached SPI RAM chip selected in menuconfig
*
* @return Size in bytes, or 0 if no external RAM chip support compiled in.
*/
size_t esp_spiram_get_size(void);
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the SPI

View File

@ -5,8 +5,7 @@
*/
#ifndef __ESP_SPIRAM_H
#define __ESP_SPIRAM_H
#pragma once
#include <stddef.h>
#include <stdint.h>
@ -24,43 +23,11 @@ extern "C" {
*/
esp_err_t esp_spiram_init(void);
/**
* @brief Configure Cache/MMU for access to external SPI RAM.
*
* Normally this function is called from cpu_start, if CONFIG_SPIRAM_BOOT_INIT
* option is enabled. Applications which need to enable SPI RAM at run time
* can disable CONFIG_SPIRAM_BOOT_INIT, and call this function later.
*
* @attention this function must be called with flash cache disabled.
*/
void esp_spiram_init_cache(void);
/**
* @brief Memory test for SPI RAM. Should be called after SPI RAM is initialized and
* (in case of a dual-core system) the app CPU is online. This test overwrites the
* memory with crap, so do not call after e.g. the heap allocator has stored important
* stuff in SPI RAM.
*
* @return true on success, false on failed memory test
*/
bool esp_spiram_test(void);
/**
* @brief Add the initialized SPI RAM to the heap allocator.
*/
esp_err_t esp_spiram_add_to_heapalloc(void);
/**
* @brief Get the available physical size of the attached SPI RAM chip
*
* @note If ECC is enabled, the available physical size would be smaller than the physical size. See `CONFIG_SPIRAM_ECC_ENABLE`
*
* @return Size in bytes, or 0 if no external RAM chip support compiled in.
*/
size_t esp_spiram_get_size(void);
/**
* @brief Force a writeback of the data in the SPI RAM cache. This is to be called whenever
* cache is disabled, because disabling cache on the ESP32 discards the data in the SPI
@ -160,5 +127,3 @@ int rodata_flash2spiram_offset(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -10,6 +10,7 @@
#include "sdkconfig.h"
#include "hal/cpu_hal.h"
#include "compare_set.h"
#include "soc/soc.h"
#if __XTENSA__
#include "xtensa/xtruntime.h"
@ -36,6 +37,19 @@ typedef struct {
NEED_VOLATILE_MUX uint32_t count;
}spinlock_t;
#if (CONFIG_ESP32_SPIRAM_SUPPORT)
/**
* @brief Check if the pointer is on external ram
* @param p pointer
* @return true: on external ram; false: not on external ram
*/
static inline bool __attribute__((always_inline)) spinlock_ptr_external_ram(const void *p)
{
//On esp32, this external virtual address rergion is for psram
return ((intptr_t)p >= SOC_EXTRAM_DATA_LOW && (intptr_t)p < SOC_EXTRAM_DATA_HIGH);
}
#endif
/**
* @brief Initialize a lock to its default state - unlocked
* @param lock - spinlock object to initialize
@ -95,7 +109,7 @@ static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *l
result = core_id;
#if defined(CONFIG_ESP32_SPIRAM_SUPPORT)
if (esp_ptr_external_ram(lock)) {
if (spinlock_ptr_external_ram(lock)) {
compare_and_set_extram(&lock->owner, SPINLOCK_FREE, &result);
} else {
#endif

View File

@ -15,7 +15,7 @@ entries:
spiram_psram (noflash)
if SPIRAM_MODE_OCT = y:
opiram_psram (noflash)
if IDF_TARGET_ESP32S2 = y:
if IDF_TARGET_ESP32S2 = y && SPIRAM:
mmu_psram (noflash)
if PERIPH_CTRL_FUNC_IN_IRAM = y:
periph_ctrl: periph_module_reset (noflash)

View File

@ -7,6 +7,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp32/spiram.h"
#include "esp_private/spiram_private.h"
#include "esp32/rom/cache.h"
#include "sdkconfig.h"
#include "esp_himem.h"

View File

@ -17,6 +17,7 @@ we add more types of external RAM memory, this can be made into a more intellige
#include "esp_attr.h"
#include "esp_err.h"
#include "esp32/spiram.h"
#include "esp_private/spiram_private.h"
#include "spiram_psram.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
@ -55,6 +56,12 @@ extern uint8_t _ext_ram_bss_start, _ext_ram_bss_end;
extern uint8_t _ext_ram_noinit_start, _ext_ram_noinit_end;
#endif
//These variables are in bytes
static intptr_t s_allocable_vaddr_start;
static intptr_t s_allocable_vaddr_end;
static intptr_t s_mapped_vaddr_start;
static intptr_t s_mapped_vaddr_end;
static bool spiram_inited=false;
@ -132,6 +139,9 @@ void IRAM_ATTR esp_spiram_init_cache(void)
DPORT_CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DRAM1);
cache_sram_mmu_set(1, 0, SOC_EXTRAM_DATA_LOW, 0, 32, (size / 1024 / 32));
#endif
s_mapped_vaddr_start = (intptr_t)SOC_EXTRAM_DATA_LOW;
s_mapped_vaddr_end = s_mapped_vaddr_start + size;
}
esp_spiram_size_t esp_spiram_get_chip_size(void)
@ -155,6 +165,7 @@ esp_spiram_size_t esp_spiram_get_chip_size(void)
esp_err_t esp_spiram_init(void)
{
assert(!spiram_inited);
esp_err_t r;
r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (r != ESP_OK) {
@ -189,20 +200,50 @@ esp_err_t esp_spiram_add_to_heapalloc(void)
{
//Add entire external RAM region to heap allocator. Heap allocator knows the capabilities of this type of memory, so there's
//no need to explicitly specify them.
intptr_t mallocable_ram_start = (intptr_t)SOC_EXTRAM_DATA_LOW;
s_allocable_vaddr_start = (intptr_t)SOC_EXTRAM_DATA_LOW;
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
if (mallocable_ram_start < (intptr_t)&_ext_ram_bss_end) {
mallocable_ram_start = (intptr_t)&_ext_ram_bss_end;
if (s_allocable_vaddr_start < (intptr_t)&_ext_ram_bss_end) {
s_allocable_vaddr_start = (intptr_t)&_ext_ram_bss_end;
}
#endif
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
if (mallocable_ram_start < (intptr_t)&_ext_ram_noinit_end) {
mallocable_ram_start = (intptr_t)&_ext_ram_noinit_end;
if (s_allocable_vaddr_start < (intptr_t)&_ext_ram_noinit_end) {
s_allocable_vaddr_start = (intptr_t)&_ext_ram_noinit_end;
}
#endif
intptr_t mallocable_ram_end = (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc() - 1;
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (mallocable_ram_end - mallocable_ram_start)/1024);
return heap_caps_add_region(mallocable_ram_start, mallocable_ram_end);
s_allocable_vaddr_end = (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc() - 1;
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (s_allocable_vaddr_end - s_allocable_vaddr_start)/1024);
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end);
}
esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (!spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_mapped_vaddr_start;
*out_vend = s_mapped_vaddr_end;
return ESP_OK;
}
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (!spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_allocable_vaddr_start;
*out_vend = s_allocable_vaddr_end;
return ESP_OK;
}

View File

@ -17,10 +17,11 @@ if(NOT BOOTLOADER_BUILD)
"esp_hmac.c"
"esp_crypto_lock.c"
"esp_ds.c"
"dport_access.c"
"spiram.c"
"mmu_psram.c"
"spiram_psram.c")
"dport_access.c")
if(CONFIG_SPIRAM)
list(APPEND srcs "spiram.c" "mmu_psram.c" "spiram_psram.c")
endif()
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -19,6 +19,7 @@
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "esp_heap_caps_init.h"
#include "esp_private/spiram_private.h"
#include "esp32s2/spiram.h"
#include "esp_private/mmu_psram.h"
#include "spiram_psram.h"
@ -44,47 +45,48 @@ extern uint8_t _ext_ram_bss_end;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
//These variables are in bytes
static uint32_t s_allocable_vaddr_start;
static uint32_t s_allocable_vaddr_end;
static intptr_t s_allocable_vaddr_start;
static intptr_t s_allocable_vaddr_end;
static intptr_t s_mapped_vaddr_start;
static intptr_t s_mapped_vaddr_end;
static bool spiram_inited=false;
static bool s_spiram_inited;
static const char* TAG = "spiram";
bool esp_spiram_test(uint32_t v_start, uint32_t size);
static bool esp_spiram_test(uint32_t v_start, uint32_t size);
esp_err_t esp_spiram_init(void)
{
esp_err_t r;
r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (r != ESP_OK) {
assert(!s_spiram_inited);
esp_err_t ret;
ret = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (ret != ESP_OK) {
#if CONFIG_SPIRAM_IGNORE_NOTFOUND
ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
#endif
return r;
return ret;
}
s_spiram_inited = true;
spiram_inited = true;
uint32_t psram_physical_size = 0;
ret = psram_get_physical_size(&psram_physical_size);
assert(ret == ESP_OK);
//TODO IDF-4380
size_t spiram_size = esp_spiram_get_size();
#if (CONFIG_SPIRAM_SIZE != -1)
if (spiram_size != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dKiB chip but found %dKiB chip. Bailing out..", CONFIG_SPIRAM_SIZE/1024, spiram_size/1024);
if (psram_physical_size != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dMB chip but found %dMB chip. Bailing out..", CONFIG_SPIRAM_SIZE / 1024 / 1024, psram_physical_size / 1024 / 1024);
return ESP_ERR_INVALID_SIZE;
}
#endif
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device", psram_physical_size / (1024 * 1024));
ESP_EARLY_LOGI(TAG, "Speed: %dMHz", CONFIG_SPIRAM_SPEED);
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device",
(spiram_size*8)/(1024*1024));
ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_S40M ? "sram 40m" : \
PSRAM_SPEED == PSRAM_CACHE_S80M ? "sram 80m" : "sram 20m");
ESP_EARLY_LOGI(TAG, "PSRAM initialized, cache is in %s mode.", \
(PSRAM_MODE==PSRAM_VADDR_MODE_EVENODD)?"even/odd (2-core)": \
(PSRAM_MODE==PSRAM_VADDR_MODE_LOWHIGH)?"low/high (2-core)": \
(PSRAM_MODE==PSRAM_VADDR_MODE_NORMAL)?"normal (1-core)":"ERROR");
uint32_t psram_available_size = 0;
ret = psram_get_available_size(&psram_available_size);
assert(ret == ESP_OK);
uint32_t psram_available_size = spiram_size;
__attribute__((unused)) uint32_t total_available_size = psram_available_size;
/**
* `start_page` is the psram physical address in MMU page size.
* MMU page size on ESP32S2 is 64KB
@ -99,8 +101,8 @@ esp_err_t esp_spiram_init(void)
//------------------------------------Copy Flash .text to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
r = mmu_config_psram_text_segment(start_page, spiram_size, &used_page);
if (r != ESP_OK) {
ret = mmu_config_psram_text_segment(start_page, total_available_size, &used_page);
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "No enough psram memory for instructon!");
abort();
}
@ -111,8 +113,8 @@ esp_err_t esp_spiram_init(void)
//------------------------------------Copy Flash .rodata to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_RODATA
r = mmu_config_psram_rodata_segment(start_page, spiram_size, &used_page);
if (r != ESP_OK) {
ret = mmu_config_psram_rodata_segment(start_page, total_available_size, &used_page);
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "No enough psram memory for rodata!");
abort();
}
@ -121,10 +123,10 @@ esp_err_t esp_spiram_init(void)
ESP_EARLY_LOGV(TAG, "after copy .rodata, used page is %d, start_page is %d, psram_available_size is %d B", used_page, start_page, psram_available_size);
#endif //#if CONFIG_SPIRAM_RODATA
//Map the PSRAM physical range to MMU
//----------------------------------Map the PSRAM physical range to MMU-----------------------------//
static DRAM_ATTR uint32_t vaddr_start = 0;
mmu_map_psram(MMU_PAGE_TO_BYTES(start_page), MMU_PAGE_TO_BYTES(start_page) + psram_available_size, &vaddr_start);
if (r != ESP_OK) {
if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "MMU PSRAM mapping wrong!");
abort();
}
@ -141,6 +143,8 @@ esp_err_t esp_spiram_init(void)
/*------------------------------------------------------------------------------
* After mapping, we DON'T care about the PSRAM PHYSICAL ADDRESSS ANYMORE!
*----------------------------------------------------------------------------*/
s_mapped_vaddr_start = vaddr_start;
s_mapped_vaddr_end = vaddr_start + psram_available_size;
s_allocable_vaddr_start = vaddr_start;
s_allocable_vaddr_end = vaddr_start + psram_available_size;
@ -157,35 +161,58 @@ esp_err_t esp_spiram_init(void)
return ESP_OK;
}
/**
* Add the PSRAM available region to heap allocator. Heap allocator knows the capabilities of this type of memory,
* so there's no need to explicitly specify them.
*/
esp_err_t esp_spiram_add_to_heapalloc(void)
{
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end - 1);
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (s_allocable_vaddr_end - s_allocable_vaddr_start) / 1024);
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end);
}
static uint8_t *dma_heap;
esp_err_t esp_spiram_reserve_dma_pool(size_t size) {
if (size==0) return ESP_OK; //no-op
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024);
dma_heap=heap_caps_malloc(size, MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL);
if (!dma_heap) return ESP_ERR_NO_MEM;
uint32_t caps[]={MALLOC_CAP_DMA|MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT};
return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap+size-1);
}
//TODO IDF-4380
size_t esp_spiram_get_size(void)
esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!spiram_inited) {
ESP_EARLY_LOGE(TAG, "SPI RAM not initialized");
abort();
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
psram_size_t size=psram_get_size();
if (size==PSRAM_SIZE_16MBITS) return 2*1024*1024;
if (size==PSRAM_SIZE_32MBITS) return 4*1024*1024;
if (size==PSRAM_SIZE_64MBITS) return 8*1024*1024;
return CONFIG_SPIRAM_SIZE;
if (!s_spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_mapped_vaddr_start;
*out_vend = s_mapped_vaddr_end;
return ESP_OK;
}
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (!s_spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_allocable_vaddr_start;
*out_vend = s_allocable_vaddr_end;
return ESP_OK;
}
esp_err_t esp_spiram_reserve_dma_pool(size_t size)
{
if (size == 0) {
return ESP_OK; //no-op
}
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size/1024);
uint8_t *dma_heap = heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!dma_heap) {
return ESP_ERR_NO_MEM;
}
uint32_t caps[] = {MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT | MALLOC_CAP_32BIT};
return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap + size);
}
/*
@ -206,7 +233,7 @@ void IRAM_ATTR esp_spiram_writeback_cache(void)
*/
bool esp_spiram_is_initialized(void)
{
return spiram_inited;
return s_spiram_inited;
}
uint8_t esp_spiram_get_cs_io(void)
@ -219,7 +246,7 @@ uint8_t esp_spiram_get_cs_io(void)
true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
*/
bool esp_spiram_test(uint32_t v_start, uint32_t size)
static bool esp_spiram_test(uint32_t v_start, uint32_t size)
{
volatile int *spiram = (volatile int *)v_start;

View File

@ -34,8 +34,6 @@
#include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h"
#include "bootloader_common.h"
#if CONFIG_SPIRAM
#include "soc/rtc.h"
static const char* TAG = "psram";
@ -378,20 +376,6 @@ static void IRAM_ATTR psram_gpio_config(psram_cache_mode_t mode)
s_psram_cs_io = psram_io.psram_cs_io;
}
psram_size_t psram_get_size(void)
{
if ((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id)) {
return PSRAM_SIZE_64MBITS;
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_32MBITS) {
return PSRAM_SIZE_32MBITS;
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_16MBITS) {
return PSRAM_SIZE_16MBITS;
} else {
return PSRAM_SIZE_MAX;
}
return PSRAM_SIZE_MAX;
}
//used in UT only
bool psram_is_32mbit_ver0(void)
{
@ -542,4 +526,36 @@ static void IRAM_ATTR psram_cache_init(psram_cache_mode_t psram_cache_mode, psra
CLEAR_PERI_REG_MASK(SPI_MEM_MISC_REG(0), SPI_MEM_CS1_DIS_M); //ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
}
#endif // CONFIG_SPIRAM
/*---------------------------------------------------------------------------------
* Following APIs are not required to be IRAM-Safe
*
* Consider moving these to another file if this kind of APIs grows dramatically
*-------------------------------------------------------------------------------*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
}
if ((PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_64MBITS) || PSRAM_IS_64MBIT_TRIAL(s_psram_id)) {
*out_size_bytes = PSRAM_SIZE_8MB;
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_32MBITS) {
*out_size_bytes = PSRAM_SIZE_4MB;
} else if (PSRAM_SIZE_ID(s_psram_id) == PSRAM_EID_SIZE_16MBITS) {
*out_size_bytes = PSRAM_SIZE_2MB;
} else {
return ESP_ERR_NOT_SUPPORTED;
}
return ESP_OK;
}
/**
* This function is to get the available physical psram size in bytes.
* On ESP32S2, all of the PSRAM physical region are available
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
{
return psram_get_physical_size(out_size_bytes);
}

View File

@ -4,13 +4,20 @@
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifndef _PSRAM_H
#define _PSRAM_H
#include "soc/spi_mem_reg.h"
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PSRAM_SIZE_2MB (2 * 1024 * 1024)
#define PSRAM_SIZE_4MB (4 * 1024 * 1024)
#define PSRAM_SIZE_8MB (8 * 1024 * 1024)
typedef enum {
PSRAM_CACHE_S80M = 1,
PSRAM_CACHE_S40M,
@ -19,12 +26,6 @@ typedef enum {
PSRAM_CACHE_MAX,
} psram_cache_mode_t;
typedef enum {
PSRAM_SIZE_16MBITS = 0,
PSRAM_SIZE_32MBITS = 1,
PSRAM_SIZE_64MBITS = 2,
PSRAM_SIZE_MAX,
} psram_size_t;
/*
See the TRM, chapter PID/MPU/MMU, header 'External RAM' for the definitions of these modes.
@ -40,12 +41,20 @@ typedef enum {
} psram_vaddr_mode_t;
/**
* @brief get psram size
* @return
* - PSRAM_SIZE_MAX if psram not enabled or not valid
* - PSRAM size
* @brief To get the physical psram size in bytes.
*
* @param[out] out_size_bytes physical psram size in bytes.
*/
psram_size_t psram_get_size(void);
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes);
/**
* @brief To get the available physical psram size in bytes.
*
* @note On ESP32S2, all of the PSRAM physical region are available
*
* @param[out] out_size_bytes availabe physical psram size in bytes.
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes);
/**
* @brief psram cache enable function
@ -74,5 +83,3 @@ esp_err_t esp_spiram_wrap_set(spiram_wrap_mode_t mode);
* @return psram CS IO
*/
uint8_t psram_get_cs_io(void);
#endif

View File

@ -16,15 +16,17 @@ if(NOT BOOTLOADER_BUILD)
"dport_access.c"
"esp_hmac.c"
"esp_ds.c"
"esp_crypto_lock.c"
"spiram.c")
"esp_crypto_lock.c")
if(CONFIG_SPIRAM_MODE_QUAD)
list(APPEND srcs "spiram_psram.c")
elseif(CONFIG_SPIRAM_MODE_OCT)
list(APPEND srcs "opiram_psram.c")
if(CONFIG_SPIRAM)
list(APPEND srcs "spiram.c")
if(CONFIG_SPIRAM_MODE_QUAD)
list(APPEND srcs "spiram_psram.c")
elseif(CONFIG_SPIRAM_MODE_OCT)
list(APPEND srcs "opiram_psram.c")
endif()
endif()
endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -25,8 +25,6 @@
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h"
#if CONFIG_SPIRAM_MODE_OCT
#include "soc/rtc.h"
#include "esp_private/spi_flash_os.h"
@ -383,6 +381,10 @@ static void s_config_psram_spi_phases(void)
*-------------------------------------------------------------------------------*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
}
*out_size_bytes = s_psram_size;
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
}
@ -393,6 +395,10 @@ esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
}
#if CONFIG_SPIRAM_ECC_ENABLE
*out_size_bytes = s_psram_size * 15 / 16;
#else
@ -400,5 +406,3 @@ esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
#endif
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
}
#endif //#if CONFIG_SPIRAM_MODE_OCT

View File

@ -1,45 +1,35 @@
/*
Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
*/
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*----------------------------------------------------------------------------------------------------
* Abstraction layer for PSRAM. PSRAM device related registers and MMU/Cache related code shouls be
* abstracted to lower layers.
*
* When we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
*----------------------------------------------------------------------------------------------------*/
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_heap_caps_init.h"
#include "esp_private/spiram_private.h"
#include "esp32s3/spiram.h"
#include "spiram_psram.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "soc/soc.h"
#include "esp_heap_caps_init.h"
#include "soc/soc_memory_layout.h"
#include "soc/dport_reg.h"
#include "esp32s3/rom/cache.h"
#include "soc/ext_mem_defs.h"
#include "soc/extmem_reg.h"
#include "hal/mmu_hal.h"
#include "hal/cache_ll.h"
/**
* @note consider abstract these cache register operations, so as to make `spiram.c` not needed to be IRAM-SAFE.
* This file only contains abstract operations.
*/
#define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#define MMU_PAGE_SIZE 0x10000
#if CONFIG_SPIRAM
static const char *TAG = "spiram";
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#if CONFIG_SPIRAM_SPEED_40M
#define PSRAM_SPEED PSRAM_CACHE_S40M
@ -47,79 +37,171 @@ static const char *TAG = "spiram";
#define PSRAM_SPEED PSRAM_CACHE_S80M
#endif
static bool s_spiram_inited = false;
static const char *TAG = "spiram";
static bool s_spiram_inited;
//These variables are in bytes
static uint32_t s_allocable_vaddr_start;
static uint32_t s_allocable_vaddr_end;
static DRAM_ATTR uint32_t s_mapped_vaddr_start;
static DRAM_ATTR uint32_t s_mapped_size;
static intptr_t s_allocable_vaddr_start;
static intptr_t s_allocable_vaddr_end;
static intptr_t s_mapped_vaddr_start;
static intptr_t s_mapped_vaddr_end;
/**
* Initially map all psram physical address to virtual address.
* If psram physical size is larger than virtual address range, then only map the virtual address range.
*/
void IRAM_ATTR esp_spiram_init_cache(void)
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
extern uint8_t _ext_ram_bss_start;
extern uint8_t _ext_ram_bss_end;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
static bool esp_spiram_test(uint32_t v_start, uint32_t size);
esp_err_t esp_spiram_init(void)
{
esp_err_t ret = psram_get_available_size(&s_mapped_size);
assert(!s_spiram_inited);
esp_err_t ret;
uint32_t psram_physical_size = 0;
ret = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (ret != ESP_OK) {
abort();
#if CONFIG_SPIRAM_IGNORE_NOTFOUND
ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
#endif
return ret;
}
if ((SOC_EXTRAM_DATA_HIGH - SOC_EXTRAM_DATA_LOW) < s_mapped_size) {
s_spiram_inited = true;
ret = psram_get_physical_size(&psram_physical_size);
assert(ret == ESP_OK);
#if (CONFIG_SPIRAM_SIZE != -1)
if (psram_physical_size != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dMB chip but found %dMB chip. Bailing out..", (CONFIG_SPIRAM_SIZE / 1024 / 1024), (psram_physical_size / 1024 / 1024));
return ESP_ERR_INVALID_SIZE;
}
#endif
ESP_EARLY_LOGI(TAG, "Found %dMB SPI RAM device", psram_physical_size / (1024 * 1024));
ESP_EARLY_LOGI(TAG, "Speed: %dMHz", CONFIG_SPIRAM_SPEED);
/**
* TODO IDF-4318
* Add these feature here:
* - Copy Flash text into PSRAM
* - Copy Flash rodata into PSRAM
*/
//----------------------------------Map the PSRAM physical range to MMU-----------------------------//
uint32_t vaddr_start = 0;
extern uint32_t _rodata_reserved_end;
uint32_t rodata_end_aligned = ALIGN_UP_BY((uint32_t)&_rodata_reserved_end, MMU_PAGE_SIZE);
vaddr_start = rodata_end_aligned;
ESP_EARLY_LOGV(TAG, "rodata_end_aligned is 0x%x bytes", rodata_end_aligned);
uint32_t psram_available_size = 0;
ret = psram_get_available_size(&psram_available_size);
assert(ret == ESP_OK);
if (vaddr_start + psram_available_size > DRAM0_CACHE_ADDRESS_HIGH) {
//Decide these logics when there's a real PSRAM with larger size
ESP_EARLY_LOGE(TAG, "Virtual address not enough for PSRAM!");
abort();
}
s_mapped_vaddr_start = SOC_EXTRAM_DATA_HIGH - s_mapped_size;
Cache_Suspend_DCache();
Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, s_mapped_vaddr_start, 0, 64, s_mapped_size >> 16, 0);
REG_CLR_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE0_BUS);
//On ESP32S3, MMU is shared for both of the cores. Note this when porting `spiram.c`
uint32_t actual_mapped_len = 0;
mmu_hal_map_region(0, MMU_TARGET_PSRAM0, vaddr_start, 0, psram_available_size, &actual_mapped_len);
ESP_EARLY_LOGV(TAG, "actual_mapped_len is 0x%x bytes", actual_mapped_len);
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, vaddr_start, actual_mapped_len);
cache_ll_l1_enable_bus(0, bus_mask);
#if !CONFIG_FREERTOS_UNICORE
REG_CLR_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE1_BUS);
bus_mask = cache_ll_l1_get_bus(1, vaddr_start, actual_mapped_len);
cache_ll_l1_enable_bus(1, bus_mask);
#endif
Cache_Resume_DCache(0);
//Currently no non-heap stuff on ESP32S3
s_allocable_vaddr_start = s_mapped_vaddr_start;
s_allocable_vaddr_end = SOC_EXTRAM_DATA_HIGH;
#if CONFIG_SPIRAM_MEMTEST
//After mapping, simple test SPIRAM first
bool ext_ram_ok = esp_spiram_test(vaddr_start, psram_available_size);
if (!ext_ram_ok) {
ESP_EARLY_LOGE(TAG, "External RAM failed memory test!");
abort();
}
#endif //#if CONFIG_SPIRAM_MEMTEST
/*------------------------------------------------------------------------------
* After mapping, we DON'T care about the PSRAM PHYSICAL ADDRESSS ANYMORE!
*----------------------------------------------------------------------------*/
s_mapped_vaddr_start = vaddr_start;
s_mapped_vaddr_end = vaddr_start + psram_available_size;
s_allocable_vaddr_start = vaddr_start;
s_allocable_vaddr_end = vaddr_start + psram_available_size;
//------------------------------------Configure .bss in PSRAM-------------------------------------//
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
//should never be negative number
uint32_t ext_bss_size = ((intptr_t)&_ext_ram_bss_end - (intptr_t)&_ext_ram_bss_start);
ESP_EARLY_LOGV(TAG, "_ext_ram_bss_start is 0x%x, _ext_ram_bss_start is 0x%x, ext_bss_size is 0x%x bytes", &_ext_ram_bss_start, &_ext_ram_bss_end, ext_bss_size);
s_allocable_vaddr_start += ext_bss_size;
#endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
ESP_EARLY_LOGV(TAG, "s_allocable_vaddr_start is 0x%x, s_allocable_vaddr_end is 0x%x", s_allocable_vaddr_start, s_allocable_vaddr_end);
return ESP_OK;
}
/*
Simple RAM test. Writes a word every 32 bytes. Takes about a second to complete for 4MiB. Returns
true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
*/
bool esp_spiram_test(void)
/**
* Add the PSRAM available region to heap allocator. Heap allocator knows the capabilities of this type of memory,
* so there's no need to explicitly specify them.
*/
esp_err_t esp_spiram_add_to_heapalloc(void)
{
volatile int *spiram = (volatile int *)s_mapped_vaddr_start;
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (s_allocable_vaddr_end - s_allocable_vaddr_start) / 1024);
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end);
}
size_t s = s_mapped_size;
size_t p;
int errct = 0;
int initial_err = -1;
esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
for (p = 0; p < (s / sizeof(int)); p += 8) {
spiram[p] = p ^ 0xAAAAAAAA;
if (!s_spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
for (p = 0; p < (s / sizeof(int)); p += 8) {
if (spiram[p] != (p ^ 0xAAAAAAAA)) {
errct++;
if (errct == 1) {
initial_err = p * 4;
}
if (errct < 4) {
ESP_EARLY_LOGE(TAG, "SPI SRAM error@%08x:%08x/%08x \n", &spiram[p], spiram[p], p ^ 0xAAAAAAAA);
}
}
*out_vstart = s_mapped_vaddr_start;
*out_vend = s_mapped_vaddr_end;
return ESP_OK;
}
esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
{
if (!out_vstart || !out_vend) {
return ESP_ERR_INVALID_ARG;
}
if (errct) {
ESP_EARLY_LOGE(TAG, "SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n", errct, s / 32, initial_err + SOC_EXTRAM_DATA_LOW);
return false;
} else {
ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
return true;
if (!s_spiram_inited) {
return ESP_ERR_INVALID_STATE;
}
*out_vstart = s_allocable_vaddr_start;
*out_vend = s_allocable_vaddr_end;
return ESP_OK;
}
esp_err_t esp_spiram_reserve_dma_pool(size_t size)
{
if (size == 0) {
return ESP_OK;
}
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size / 1024);
uint8_t *dma_heap = heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!dma_heap) {
return ESP_ERR_NO_MEM;
}
uint32_t caps[] = {MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT | MALLOC_CAP_32BIT};
return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap + size);
}
//TODO IDF-4318
@ -222,81 +304,6 @@ int IRAM_ATTR rodata_flash2spiram_offset(void)
}
#endif
esp_err_t esp_spiram_init(void)
{
esp_err_t r;
uint32_t psram_physical_size = 0;
r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (r != ESP_OK) {
#if CONFIG_SPIRAM_IGNORE_NOTFOUND
ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
#endif
return r;
}
s_spiram_inited = true;
r = psram_get_physical_size(&psram_physical_size);
if (r != ESP_OK) {
abort();
}
#if (CONFIG_SPIRAM_SIZE != -1)
if (psram_physical_size != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dMB chip but found %dMB chip. Bailing out..", (CONFIG_SPIRAM_SIZE / 1024 / 1024), (psram_physical_size / 1024 / 1024));
return ESP_ERR_INVALID_SIZE;
}
#endif
ESP_EARLY_LOGI(TAG, "Found %dMB SPI RAM device", psram_physical_size / (1024 * 1024));
ESP_EARLY_LOGI(TAG, "Speed: %dMHz", CONFIG_SPIRAM_SPEED);
ESP_EARLY_LOGI(TAG, "Initialized, cache is in %s mode.", \
(PSRAM_MODE == PSRAM_VADDR_MODE_EVENODD) ? "even/odd (2-core)" : \
(PSRAM_MODE == PSRAM_VADDR_MODE_LOWHIGH) ? "low/high (2-core)" : \
(PSRAM_MODE == PSRAM_VADDR_MODE_NORMAL) ? "normal (1-core)" : "ERROR");
return ESP_OK;
}
/**
* Add entire external RAM region to heap allocator. Heap allocator knows the capabilities of this type of memory,
* so there's no need to explicitly specify them.
*/
esp_err_t esp_spiram_add_to_heapalloc(void)
{
ESP_EARLY_LOGI(TAG, "Adding pool of %dK of external SPI memory to heap allocator", (s_allocable_vaddr_end - s_allocable_vaddr_start) / 1024);
return heap_caps_add_region(s_allocable_vaddr_start, s_allocable_vaddr_end - 1);
}
static uint8_t *dma_heap;
esp_err_t esp_spiram_reserve_dma_pool(size_t size)
{
if (size == 0) {
return ESP_OK; //no-op
}
ESP_EARLY_LOGI(TAG, "Reserving pool of %dK of internal memory for DMA/internal allocations", size / 1024);
dma_heap = heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
if (!dma_heap) {
return ESP_ERR_NO_MEM;
}
uint32_t caps[] = {MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL, 0, MALLOC_CAP_8BIT | MALLOC_CAP_32BIT};
return heap_caps_add_region_with_caps(caps, (intptr_t) dma_heap, (intptr_t) dma_heap + size - 1);
}
size_t esp_spiram_get_size(void)
{
if (!s_spiram_inited) {
ESP_EARLY_LOGE(TAG, "SPI RAM not initialized");
abort();
}
uint32_t size = 0; //in bytes
esp_err_t ret = psram_get_available_size(&size);
if (ret == ESP_OK) {
return size;
} else {
return 0;
}
}
/*
Before flushing the cache, if psram is enabled as a memory-mapped thing, we need to write back the data in the cache to the psram first,
otherwise it will get lost. For now, we just read 64/128K of random PSRAM memory to do this.
@ -323,4 +330,39 @@ uint8_t esp_spiram_get_cs_io(void)
return psram_get_cs_io();
}
#endif
/*
Simple RAM test. Writes a word every 32 bytes. Takes about a second to complete for 4MiB. Returns
true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been
initialized (in a two-core system) or after the heap allocator has taken ownership of the memory.
*/
static bool esp_spiram_test(uint32_t v_start, uint32_t size)
{
volatile int *spiram = (volatile int *)v_start;
size_t s = size;
size_t p;
int errct = 0;
int initial_err = -1;
for (p = 0; p < (s / sizeof(int)); p += 8) {
spiram[p] = p ^ 0xAAAAAAAA;
}
for (p = 0; p < (s / sizeof(int)); p += 8) {
if (spiram[p] != (p ^ 0xAAAAAAAA)) {
errct++;
if (errct == 1) {
initial_err = p * 4;
}
if (errct < 4) {
ESP_EARLY_LOGE(TAG, "SPI SRAM error@%08x:%08x/%08x \n", &spiram[p], spiram[p], p ^ 0xAAAAAAAA);
}
}
}
if (errct) {
ESP_EARLY_LOGE(TAG, "SPI SRAM memory test fail. %d/%d writes failed, first @ %X\n", errct, s / 32, initial_err + SOC_EXTRAM_DATA_LOW);
return false;
} else {
ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
return true;
}
}

View File

@ -1,7 +1,3 @@
/*
Driver bits for PSRAM chips (at the moment only the ESP-PSRAM32 chip).
*/
/*
* SPDX-FileCopyrightText: 2013-2021 Espressif Systems (Shanghai) CO LTD
*
@ -35,8 +31,6 @@
#include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h"
#include "bootloader_common.h"
#if CONFIG_SPIRAM_MODE_QUAD
#include "soc/rtc.h"
#include "esp_private/spi_flash_os.h"
@ -409,6 +403,10 @@ static void config_psram_spi_phases(void)
*-------------------------------------------------------------------------------*/
esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
}
*out_size_bytes = s_psram_size;
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
}
@ -421,7 +419,10 @@ esp_err_t psram_get_physical_size(uint32_t *out_size_bytes)
*/
esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
{
if (!out_size_bytes) {
return ESP_ERR_INVALID_ARG;
}
*out_size_bytes = s_psram_size;
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
}
#endif // CONFIG_SPIRAM

View File

@ -9,16 +9,16 @@
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PSRAM_SIZE_2MB (2 * 1024 * 1024)
#define PSRAM_SIZE_4MB (4 * 1024 * 1024)
#define PSRAM_SIZE_8MB (8 * 1024 * 1024)
#define PSRAM_SIZE_16MB (16 * 1024 * 1024)
#define PSRAM_SIZE_32MB (32 * 1024 * 1024)
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PSRAM_CACHE_S80M = 1,
PSRAM_CACHE_S40M,

View File

@ -116,7 +116,7 @@ static esp_err_t esp_sleep_tagmem_pd_low_init(bool enable)
uint32_t data_size = (uint32_t)(_rodata_reserved_end - _rodata_start);
#else
uint32_t data_start = SOC_DROM_LOW;
uint32_t data_size = (SOC_EXTRAM_DATA_HIGH-SOC_EXTRAM_DATA_LOW) + (SOC_DROM_HIGH-SOC_DROM_LOW);
uint32_t data_size = SOC_EXTRAM_DATA_SIZE;
#endif
ESP_LOGI(TAG, "Code start at %08x, total %.2f KiB, data start at %08x, total %.2f KiB",
code_start, (float)code_size/1024, data_start, (float)data_size/1024);

View File

@ -14,17 +14,27 @@
#include "test_utils.h"
#include "unity.h"
#include "esp_heap_caps.h"
#include "esp_private/spiram_private.h"
#if CONFIG_SPIRAM
#include "spiram.h"
const static char *TAG = "PSRAM";
#if CONFIG_SPIRAM_MODE_OCT
#define TEST_ALLOC_SIZE (4 * 1024 * 1024)
#else
#define TEST_ALLOC_SIZE (1 * 1024 * 1024)
#endif
static bool s_check_valid_psram_alloced_range(const void *p)
{
intptr_t vaddr_start = 0;
intptr_t vaddr_end = 0;
esp_spiram_get_alloced_range(&vaddr_start, &vaddr_end);
return (intptr_t)p >= vaddr_start && (intptr_t)p < vaddr_end;
}
TEST_CASE("test psram heap allocable","[psram]")
{
uint32_t *ext_buffer = (uint32_t *)heap_caps_calloc(TEST_ALLOC_SIZE, 1, MALLOC_CAP_SPIRAM);
@ -32,9 +42,8 @@ TEST_CASE("test psram heap allocable","[psram]")
uintptr_t start = (uintptr_t)ext_buffer;
uintptr_t end = (uintptr_t)ext_buffer + TEST_ALLOC_SIZE;
ESP_LOGI(TAG, "test ext buffer start addr is %x, end addr is %x", start, end);
TEST_ASSERT((start >= SOC_EXTRAM_DATA_LOW) && (end <= SOC_EXTRAM_DATA_HIGH));
ESP_LOGI(TAG, "test ext buffer start addr is 0x%x, end addr is 0x%x", start, end);
TEST_ASSERT(s_check_valid_psram_alloced_range((void *)start) && s_check_valid_psram_alloced_range((void *)end));
for (int i = 0; i < TEST_ALLOC_SIZE / sizeof(uint32_t); i++) {
ext_buffer[i] = (i + 1) ^ 0xaaaaaaaa;
@ -47,6 +56,7 @@ TEST_CASE("test psram heap allocable","[psram]")
free(ext_buffer);
}
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
#include "esp_timer.h"
#include "esp32s3/rom/spi_flash.h"

View File

@ -223,7 +223,7 @@ SECTIONS
_noinit_end = ABSOLUTE(.);
} > dram0_0_seg
/* external memory bss, from any global variable with EXT_RAM_ATTR attribute*/
/* external memory bss, from any global variable with EXT_RAM_BSS_ATTR attribute*/
.ext_ram.bss (NOLOAD) :
{
_ext_ram_bss_start = ABSOLUTE(.);

View File

@ -233,7 +233,7 @@ SECTIONS
_noinit_end = ABSOLUTE(.);
} > dram0_0_seg
/* external memory bss, from any global variable with EXT_RAM_ATTR attribute*/
/* external memory bss, from any global variable with EXT_RAM_BSS_ATTR attribute*/
.ext_ram.bss (NOLOAD) :
{
_ext_ram_bss_start = ABSOLUTE(.);
@ -249,7 +249,6 @@ SECTIONS
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
*(.ext_ram.bss*)
mapping[dram0_bss]

View File

@ -90,7 +90,7 @@ MEMORY
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */
drom0_0_seg (R) : org = 0x3C000020, len = 0x800000-0x20
drom0_0_seg (R) : org = 0x3C000020, len = 0x2000000-0x20
/* (See iram0_2_seg for meaning of 0x20 offset in the above.) */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
@ -115,6 +115,11 @@ MEMORY
#else
rtc_slow_seg(RW) : org = 0x50000000 , len = 0x2000
#endif // CONFIG_ULP_COPROC_ENABLED
/**
* `extern_ram_seg` and `drom0_0_seg` share the same bus and the address region.
* A dummy section is used to avoid overlap. See `.ext_ram.dummy` in `sections.ld.in`
*/
extern_ram_seg(RWX) : org = 0x3c000020 , len = 0x2000000-0x20
}
#if CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE

View File

@ -231,7 +231,6 @@ SECTIONS
{
. = ALIGN (8);
_bss_start = ABSOLUTE(.);
*(.ext_ram.bss*)
mapping[dram0_bss]
@ -292,7 +291,7 @@ SECTIONS
*/
.flash_rodata_dummy (NOLOAD):
{
_flash_rodata_dummy_start = .;
_flash_rodata_dummy_start = ABSOLUTE(.);
/* Start at the same alignment constraint than .flash.text */
. = ALIGN(ALIGNOF(.flash.text));
/* Create an empty gap as big as .flash.text section */
@ -381,6 +380,25 @@ SECTIONS
mapping[rodata_noload]
} > default_rodata_seg
/**
* This section is required to skip flash rodata sections, because `extern_ram_seg`
* and `drom0_0_seg` are on the same bus
*/
.ext_ram.dummy (NOLOAD):
{
. = ORIGIN(extern_ram_seg) + (_rodata_reserved_end - _flash_rodata_dummy_start);
. = ALIGN (0x10000);
} > extern_ram_seg
/* This section holds .ext_ram.bss data, and will be put in PSRAM */
.ext_ram.bss (NOLOAD) :
{
_ext_ram_bss_start = ABSOLUTE(.);
mapping[extern_ram]
. = ALIGN(4);
_ext_ram_bss_end = ABSOLUTE(.);
} > extern_ram_seg
/* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) :
{

View File

@ -389,12 +389,10 @@ void IRAM_ATTR call_start_cpu0(void)
bootloader_init_mem();
#if CONFIG_SPIRAM_BOOT_INIT
if (esp_spiram_init() != ESP_OK) {
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment");
abort();
#endif
#endif
#if CONFIG_SPIRAM_IGNORE_NOTFOUND
ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it.");
@ -405,11 +403,11 @@ void IRAM_ATTR call_start_cpu0(void)
#endif
}
//TODO: IDF-4382
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3
#if CONFIG_IDF_TARGET_ESP32
if (g_spiram_ok) {
esp_spiram_init_cache();
}
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3, //TODO: IDF-4382
#endif //#if CONFIG_IDF_TARGET_ESP32, //TODO: IDF-4382
#endif
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
@ -439,7 +437,7 @@ void IRAM_ATTR call_start_cpu0(void)
#if CONFIG_SPIRAM_MEMTEST
//TODO: IDF-4382
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3
#if CONFIG_IDF_TARGET_ESP32
if (g_spiram_ok) {
bool ext_ram_ok = esp_spiram_test();
if (!ext_ram_ok) {
@ -447,7 +445,7 @@ void IRAM_ATTR call_start_cpu0(void)
abort();
}
}
#endif //CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3, //TODO: IDF-4382
#endif //CONFIG_IDF_TARGET_ESP32, //TODO: IDF-4382
#endif //CONFIG_SPIRAM_MEMTEST
//TODO: IDF-4382

View File

@ -87,6 +87,8 @@ enum tlsf_config
FL_INDEX_MAX = 23, //Each pool can have up 8MB
#elif (TLSF_MAX_POOL_SIZE <= (16 * 1024 * 1024))
FL_INDEX_MAX = 24, //Each pool can have up 16MB
#elif (TLSF_MAX_POOL_SIZE <= (32 * 1024 * 1024))
FL_INDEX_MAX = 25, //Each pool can have up 32MB
#else
#error "Higher TLSF pool sizes should be added for this new config"
#endif

View File

@ -185,7 +185,7 @@
#define SOC_RTC_DATA_LOW 0x50000000
#define SOC_RTC_DATA_HIGH 0x50002000
#define SOC_EXTRAM_DATA_LOW 0x3D000000
#define SOC_EXTRAM_DATA_LOW 0x3C000000
#define SOC_EXTRAM_DATA_HIGH 0x3E000000
#define SOC_IROM_MASK_LOW 0x40000000
#define SOC_IROM_MASK_HIGH 0x4001A100

View File

@ -91,7 +91,7 @@ If a suitable block of preferred internal/external memory is not available, the
Because some buffers can only be allocated in internal memory, a second configuration item :ref:`CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL` defines a pool of internal memory which is reserved for *only* explicitly internal allocations (such as memory for DMA use). Regular ``malloc()`` will not allocate from this pool. The :ref:`MALLOC_CAP_DMA <dma-capable-memory>` and ``MALLOC_CAP_INTERNAL`` flags can be used to allocate memory from this pool.
.. only:: esp32 or esp32s2
.. only:: SOC_SPIRAM_SUPPORTED
.. _external_ram_config_bss:
@ -102,7 +102,7 @@ Because some buffers can only be allocated in internal memory, a second configur
If enabled, a region of the address space starting from {IDF_TARGET_PSRAM_ADDR_START} will be used to store zero-initialized data (BSS segment) from the lwIP, net80211, libpp, and bluedroid ESP-IDF libraries.
Additional data can be moved from the internal BSS segment to external RAM by applying the macro ``EXT_RAM_ATTR`` to any static declaration (which is not initialized to a non-zero value).
Additional data can be moved from the internal BSS segment to external RAM by applying the macro ``EXT_RAM_BSS_ATTR`` to any static declaration (which is not initialized to a non-zero value).
It is also possible to place the BSS section of a component or a library to external RAM using linker fragment scheme ``extram_bss``.
@ -129,8 +129,8 @@ 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 buffer 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.

View File

@ -16,9 +16,9 @@ DRAM (Data RAM)
Non-constant static data (.data) and zero-initialized data (.bss) is placed by the linker into Internal SRAM as data memory. The remaining space in this region is used for the runtime heap.
.. only:: esp32 or esp32s2
.. only:: SOC_SPIRAM_SUPPORTED
By applying the ``EXT_RAM_ATTR`` macro, zero-initialized data can also be placed into external RAM. To use this macro, the :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` needs to be enabled. See :ref:`external_ram_config_bss`.
By applying the ``EXT_RAM_BSS_ATTR`` macro, zero-initialized data can also be placed into external RAM. To use this macro, the :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY` needs to be enabled. See :ref:`external_ram_config_bss`.
.. only:: esp32

View File

@ -41,10 +41,21 @@ ESP HW Support
- The header file ``esp_intr.h`` has been deleted. Please include ``esp_intr_alloc.h`` to allocate and manipulate interrupts.
- The header file ``esp_panic.h`` has been deleted. ESP-IDF developers should include ``esp_private/panic_reason.h`` to get supported panic reasons. And should include ``esp_debug_helpers.h`` to use any debug related helper functions, e.g. print backtrace.
- The header file ``soc_log.h`` is now renamed to ``esp_hw_log.h`` and all logging macros have been updated from ``SOC_LOGx`` to ``ESP_HW_LOGx``. ESP-IDF users must use the later form.
- The header file ``esp_spiram.h`` file is deleted. Users should use the ``<target>/spiram.h`` file instead.
- The header file ``esp32/himem.h`` file is deleted. Users should use the esp_himem.h file instead.
- The header files ``spinlock.h``, ``clk_ctrl_os.h`` and ``rtc_wdt.h`` must now be included without the ``soc`` prefix. Eg:- ``#include "spinlock.h"``.
PSRAM
^^^^^
- The header file ``esp_spiram.h`` file has been deleted. Users should use the ``<target>/spiram.h`` file instead.
- The header file ``esp32/himem.h`` file has been deleted. Users should use the esp_himem.h file instead.
- `esp_spiram_get_chip_size` has been deleted.
- `esp_spiram_get_size` has been moved to `esp_private/spiram_private.h`
ESP Common
----------
- `EXT_RAM_ATTR` is deprecated. Use this new macro `EXT_RAM_BSS_ATTR` to put .bss on PSRAM.
ESP System
----------
- The header files ``esp_random.h``, ``esp_mac.h`` and ``esp_chip_info.h``, which were all previously indirectly included via the header file ``esp_system.h``, must now be included directly. These headers are removed from ``esp_system.h``.

View File

@ -91,7 +91,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到以 {IDF_TARGET_PSRAM_ADDR_STAR
由于有些内存缓冲器仅可在内部存储器中分配,因此需要使用第二个配置项 :ref:`CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL` 定义一个内部内存池,仅限显式的内部存储器分配使用(例如用于 DMA 的存储器)。常规 ``malloc()`` 将不会从该池中分配,但可以使用 :ref:`MALLOC_CAP_DMA <dma-capable-memory>```MALLOC_CAP_INTERNAL`` 标志从该池中分配存储器。
.. only:: esp32 or esp32s2
.. only:: SOC_SPIRAM_SUPPORTED
.. _external_ram_config_bss:
@ -102,7 +102,7 @@ ESP-IDF 启动过程中,片外 RAM 被映射到以 {IDF_TARGET_PSRAM_ADDR_STAR
启用该选项后,从 {IDF_TARGET_PSRAM_ADDR_START} 起始的地址空间将用于存储来自 lwip、net80211、libpp 和 bluedroid ESP-IDF 库中零初始化的数据BSS 段)。
``EXT_RAM_ATTR`` 宏应用于任何静态声明(未初始化为非零值)之后,可以将附加数据从内部 BSS 段移到片外 RAM。
``EXT_RAM_BSS_ATTR`` 宏应用于任何静态声明(未初始化为非零值)之后,可以将附加数据从内部 BSS 段移到片外 RAM。
也可以使用链接器片段方案 ``extram_bss`` 将组件或库的 BSS 段放到片外 RAM 中。

View File

@ -16,9 +16,9 @@ DRAM数据 RAM
非常量静态数据(.data 段)和零初始化数据(.bss 段)由链接器放入内部 SRAM 作为数据存储。此区域中的剩余空间可在程序运行时用作堆。
.. only:: esp32 or esp32s2
.. only:: SOC_SPIRAM_SUPPORTED
通过应用 ``EXT_RAM_ATTR`` 宏,零初始化数据也可以放入外部 RAM。使用这个宏需要启用 :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`。详情请见 :ref:`external_ram_config_bss`
通过应用 ``EXT_RAM_BSS_ATTR`` 宏,零初始化数据也可以放入外部 RAM。使用这个宏需要启用 :ref:`CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY`。详情请见 :ref:`external_ram_config_bss`
.. only:: esp32