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" bool "20Mhz clock speed"
endchoice 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" #insert non-chip-specific items here
source "$IDF_PATH/components/esp_hw_support/Kconfig.spiram.common"
endmenu endmenu

View File

@ -66,9 +66,19 @@ extern "C" {
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
// Forces bss variable into 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 #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 #endif
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" // 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 #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
#define TEST_BSS_NUM 256 #define TEST_BSS_NUM (256 * 1024)
static EXT_RAM_ATTR uint32_t s_bss_buffer[TEST_BSS_NUM]; static EXT_RAM_BSS_ATTR uint32_t s_bss_buffer[TEST_BSS_NUM];
TEST_CASE("Test variables placed in external .bss segment", "[ld]") 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 config SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
bool "Allow .bss segment placed in external memory" bool "Allow .bss segment placed in external memory"
default n 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 select ESP_ALLOW_BSS_SEG_EXTERNAL_MEMORY
help 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 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 in SPIRAM. BSS sections from other object files and libraries can also be placed in SPIRAM through
linker fragment scheme `extram_bss`. 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 config SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
bool "Allow .noinit segment placed in external memory" bool "Allow .noinit segment placed in external memory"

View File

@ -12,17 +12,22 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_memory_utils.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) bool esp_ptr_dma_ext_capable(const void *p)
{ {
#ifdef SOC_PSRAM_DMA_CAPABLE #if !SOC_PSRAM_DMA_CAPABLE
return (intptr_t)p >= SOC_DMA_EXT_LOW && (intptr_t)p < SOC_DMA_EXT_HIGH; 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 #else
return false; return false;
#endif #endif //CONFIG_SPIRAM
} }
bool esp_ptr_byte_accessible(const void *p) 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); r |= (ip >= SOC_RTC_DRAM_LOW && ip < SOC_RTC_DRAM_HIGH);
#endif #endif
#if CONFIG_SPIRAM #if CONFIG_SPIRAM
#if CONFIG_SPIRAM_SIZE != -1 // Fixed size, can be more accurate intptr_t vaddr_start = 0;
r |= (ip >= SOC_EXTRAM_DATA_LOW && ip < (SOC_EXTRAM_DATA_LOW + CONFIG_SPIRAM_SIZE)); intptr_t vaddr_end = 0;
#else esp_spiram_get_mapped_range(&vaddr_start, &vaddr_end);
r |= (ip >= SOC_EXTRAM_DATA_LOW && ip < (SOC_EXTRAM_DATA_HIGH)); r |= (ip >= vaddr_start && ip < vaddr_end);
#endif
#endif #endif
return r; return r;
} }
bool esp_ptr_external_ram(const void *p) { 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); #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 #else
return false; // SoC has no external RAM return false;
#endif #endif //CONFIG_SPIRAM
} }
#if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY #if CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
bool esp_stack_ptr_in_extram(uint32_t sp) 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. //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 #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" { extern "C" {
#endif #endif
typedef enum { //TODO: IDF-4382, unify `target/spiram.h`, update migration guide as well
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);
/** /**
* @brief Initialize spiram interface/hardware. Normally called from cpu_start.c. * @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); 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 * @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 * 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); 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 * @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 * 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 #pragma once
#define __ESP_SPIRAM_H
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -24,43 +23,11 @@ extern "C" {
*/ */
esp_err_t esp_spiram_init(void); 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. * @brief Add the initialized SPI RAM to the heap allocator.
*/ */
esp_err_t esp_spiram_add_to_heapalloc(void); 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 * @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 * 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 #ifdef __cplusplus
} }
#endif #endif
#endif

View File

@ -10,6 +10,7 @@
#include "sdkconfig.h" #include "sdkconfig.h"
#include "hal/cpu_hal.h" #include "hal/cpu_hal.h"
#include "compare_set.h" #include "compare_set.h"
#include "soc/soc.h"
#if __XTENSA__ #if __XTENSA__
#include "xtensa/xtruntime.h" #include "xtensa/xtruntime.h"
@ -36,6 +37,19 @@ typedef struct {
NEED_VOLATILE_MUX uint32_t count; NEED_VOLATILE_MUX uint32_t count;
}spinlock_t; }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 * @brief Initialize a lock to its default state - unlocked
* @param lock - spinlock object to initialize * @param lock - spinlock object to initialize
@ -95,7 +109,7 @@ static inline bool __attribute__((always_inline)) spinlock_acquire(spinlock_t *l
result = core_id; result = core_id;
#if defined(CONFIG_ESP32_SPIRAM_SUPPORT) #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); compare_and_set_extram(&lock->owner, SPINLOCK_FREE, &result);
} else { } else {
#endif #endif

View File

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

View File

@ -7,6 +7,7 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp32/spiram.h" #include "esp32/spiram.h"
#include "esp_private/spiram_private.h"
#include "esp32/rom/cache.h" #include "esp32/rom/cache.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_himem.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_attr.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp32/spiram.h" #include "esp32/spiram.h"
#include "esp_private/spiram_private.h"
#include "spiram_psram.h" #include "spiram_psram.h"
#include "esp_log.h" #include "esp_log.h"
#include "freertos/FreeRTOS.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; extern uint8_t _ext_ram_noinit_start, _ext_ram_noinit_end;
#endif #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; 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); 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)); cache_sram_mmu_set(1, 0, SOC_EXTRAM_DATA_LOW, 0, 32, (size / 1024 / 32));
#endif #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) 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) esp_err_t esp_spiram_init(void)
{ {
assert(!spiram_inited);
esp_err_t r; esp_err_t r;
r = psram_enable(PSRAM_SPEED, PSRAM_MODE); r = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (r != ESP_OK) { 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 //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. //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 CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
if (mallocable_ram_start < (intptr_t)&_ext_ram_bss_end) { if (s_allocable_vaddr_start < (intptr_t)&_ext_ram_bss_end) {
mallocable_ram_start = (intptr_t)&_ext_ram_bss_end; s_allocable_vaddr_start = (intptr_t)&_ext_ram_bss_end;
} }
#endif #endif
#if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY #if CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY
if (mallocable_ram_start < (intptr_t)&_ext_ram_noinit_end) { if (s_allocable_vaddr_start < (intptr_t)&_ext_ram_noinit_end) {
mallocable_ram_start = (intptr_t)&_ext_ram_noinit_end; s_allocable_vaddr_start = (intptr_t)&_ext_ram_noinit_end;
} }
#endif #endif
intptr_t mallocable_ram_end = (intptr_t)SOC_EXTRAM_DATA_LOW + spiram_size_usable_for_malloc() - 1; 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", (mallocable_ram_end - mallocable_ram_start)/1024); 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(mallocable_ram_start, mallocable_ram_end); 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_hmac.c"
"esp_crypto_lock.c" "esp_crypto_lock.c"
"esp_ds.c" "esp_ds.c"
"dport_access.c" "dport_access.c")
"spiram.c"
"mmu_psram.c" if(CONFIG_SPIRAM)
"spiram_psram.c") list(APPEND srcs "spiram.c" "mmu_psram.c" "spiram_psram.c")
endif()
endif() endif()
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}")

View File

@ -19,6 +19,7 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h" #include "freertos/xtensa_api.h"
#include "esp_heap_caps_init.h" #include "esp_heap_caps_init.h"
#include "esp_private/spiram_private.h"
#include "esp32s2/spiram.h" #include "esp32s2/spiram.h"
#include "esp_private/mmu_psram.h" #include "esp_private/mmu_psram.h"
#include "spiram_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 #endif //#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
//These variables are in bytes //These variables are in bytes
static uint32_t s_allocable_vaddr_start; static intptr_t s_allocable_vaddr_start;
static uint32_t s_allocable_vaddr_end; 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"; 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 esp_spiram_init(void)
{ {
esp_err_t r; assert(!s_spiram_inited);
r = psram_enable(PSRAM_SPEED, PSRAM_MODE); esp_err_t ret;
if (r != ESP_OK) { ret = psram_enable(PSRAM_SPEED, PSRAM_MODE);
if (ret != ESP_OK) {
#if CONFIG_SPIRAM_IGNORE_NOTFOUND #if CONFIG_SPIRAM_IGNORE_NOTFOUND
ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out."); ESP_EARLY_LOGE(TAG, "SPI RAM enabled but initialization failed. Bailing out.");
#endif #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 (CONFIG_SPIRAM_SIZE != -1)
if (spiram_size != CONFIG_SPIRAM_SIZE) { if (psram_physical_size != CONFIG_SPIRAM_SIZE) {
ESP_EARLY_LOGE(TAG, "Expected %dKiB chip but found %dKiB chip. Bailing out..", CONFIG_SPIRAM_SIZE/1024, spiram_size/1024); 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; return ESP_ERR_INVALID_SIZE;
} }
#endif #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", uint32_t psram_available_size = 0;
(spiram_size*8)/(1024*1024)); ret = psram_get_available_size(&psram_available_size);
ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_S40M ? "sram 40m" : \ assert(ret == ESP_OK);
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 = spiram_size; __attribute__((unused)) uint32_t total_available_size = psram_available_size;
/** /**
* `start_page` is the psram physical address in MMU page size. * `start_page` is the psram physical address in MMU page size.
* MMU page size on ESP32S2 is 64KB * MMU page size on ESP32S2 is 64KB
@ -99,8 +101,8 @@ esp_err_t esp_spiram_init(void)
//------------------------------------Copy Flash .text to PSRAM-------------------------------------// //------------------------------------Copy Flash .text to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS
r = mmu_config_psram_text_segment(start_page, spiram_size, &used_page); ret = mmu_config_psram_text_segment(start_page, total_available_size, &used_page);
if (r != ESP_OK) { if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "No enough psram memory for instructon!"); ESP_EARLY_LOGE(TAG, "No enough psram memory for instructon!");
abort(); abort();
} }
@ -111,8 +113,8 @@ esp_err_t esp_spiram_init(void)
//------------------------------------Copy Flash .rodata to PSRAM-------------------------------------// //------------------------------------Copy Flash .rodata to PSRAM-------------------------------------//
#if CONFIG_SPIRAM_RODATA #if CONFIG_SPIRAM_RODATA
r = mmu_config_psram_rodata_segment(start_page, spiram_size, &used_page); ret = mmu_config_psram_rodata_segment(start_page, total_available_size, &used_page);
if (r != ESP_OK) { if (ret != ESP_OK) {
ESP_EARLY_LOGE(TAG, "No enough psram memory for rodata!"); ESP_EARLY_LOGE(TAG, "No enough psram memory for rodata!");
abort(); 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); 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 #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; 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); 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!"); ESP_EARLY_LOGE(TAG, "MMU PSRAM mapping wrong!");
abort(); abort();
} }
@ -141,6 +143,8 @@ esp_err_t esp_spiram_init(void)
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* After mapping, we DON'T care about the PSRAM PHYSICAL ADDRESSS ANYMORE! * 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_start = vaddr_start;
s_allocable_vaddr_end = vaddr_start + psram_available_size; s_allocable_vaddr_end = vaddr_start + psram_available_size;
@ -157,35 +161,58 @@ esp_err_t esp_spiram_init(void)
return ESP_OK; 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) 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 IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
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)
{ {
if (!spiram_inited) { if (!out_vstart || !out_vend) {
ESP_EARLY_LOGE(TAG, "SPI RAM not initialized"); return ESP_ERR_INVALID_ARG;
abort();
} }
psram_size_t size=psram_get_size(); if (!s_spiram_inited) {
if (size==PSRAM_SIZE_16MBITS) return 2*1024*1024; return ESP_ERR_INVALID_STATE;
if (size==PSRAM_SIZE_32MBITS) return 4*1024*1024; }
if (size==PSRAM_SIZE_64MBITS) return 8*1024*1024;
return CONFIG_SPIRAM_SIZE; *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) bool esp_spiram_is_initialized(void)
{ {
return spiram_inited; return s_spiram_inited;
} }
uint8_t esp_spiram_get_cs_io(void) 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 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. 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; volatile int *spiram = (volatile int *)v_start;

View File

@ -34,8 +34,6 @@
#include "driver/spi_common.h" #include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#include "bootloader_common.h" #include "bootloader_common.h"
#if CONFIG_SPIRAM
#include "soc/rtc.h" #include "soc/rtc.h"
static const char* TAG = "psram"; 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; 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 //used in UT only
bool psram_is_32mbit_ver0(void) 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) 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 * SPDX-License-Identifier: Apache-2.0
*/ */
#pragma once
#ifndef _PSRAM_H
#define _PSRAM_H
#include "soc/spi_mem_reg.h" #include "soc/spi_mem_reg.h"
#include "esp_err.h" #include "esp_err.h"
#include "sdkconfig.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 { typedef enum {
PSRAM_CACHE_S80M = 1, PSRAM_CACHE_S80M = 1,
PSRAM_CACHE_S40M, PSRAM_CACHE_S40M,
@ -19,12 +26,6 @@ typedef enum {
PSRAM_CACHE_MAX, PSRAM_CACHE_MAX,
} psram_cache_mode_t; } 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. 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; } psram_vaddr_mode_t;
/** /**
* @brief get psram size * @brief To get the physical psram size in bytes.
* @return *
* - PSRAM_SIZE_MAX if psram not enabled or not valid * @param[out] out_size_bytes physical psram size in bytes.
* - PSRAM size
*/ */
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 * @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 * @return psram CS IO
*/ */
uint8_t psram_get_cs_io(void); uint8_t psram_get_cs_io(void);
#endif

View File

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

View File

@ -25,8 +25,6 @@
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/spi_common.h" #include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#if CONFIG_SPIRAM_MODE_OCT
#include "soc/rtc.h" #include "soc/rtc.h"
#include "esp_private/spi_flash_os.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) 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; *out_size_bytes = s_psram_size;
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE); 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) 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 #if CONFIG_SPIRAM_ECC_ENABLE
*out_size_bytes = s_psram_size * 15 / 16; *out_size_bytes = s_psram_size * 15 / 16;
#else #else
@ -400,5 +406,3 @@ esp_err_t psram_get_available_size(uint32_t *out_size_bytes)
#endif #endif
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE); 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-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * 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 <stdint.h>
#include <string.h> #include <string.h>
#include <sys/param.h> #include <sys/param.h>
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "esp_err.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 "esp32s3/spiram.h"
#include "spiram_psram.h" #include "spiram_psram.h"
#include "esp_log.h" #include "hal/mmu_hal.h"
#include "freertos/FreeRTOS.h" #include "hal/cache_ll.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"
/**
* @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 PSRAM_MODE PSRAM_VADDR_MODE_NORMAL
#define MMU_PAGE_SIZE 0x10000 #define MMU_PAGE_SIZE 0x10000
#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#if CONFIG_SPIRAM
static const char *TAG = "spiram";
#if CONFIG_SPIRAM_SPEED_40M #if CONFIG_SPIRAM_SPEED_40M
#define PSRAM_SPEED PSRAM_CACHE_S40M #define PSRAM_SPEED PSRAM_CACHE_S40M
@ -47,79 +37,171 @@ static const char *TAG = "spiram";
#define PSRAM_SPEED PSRAM_CACHE_S80M #define PSRAM_SPEED PSRAM_CACHE_S80M
#endif #endif
static bool s_spiram_inited = false;
static const char *TAG = "spiram";
static bool s_spiram_inited;
//These variables are in bytes //These variables are in bytes
static uint32_t s_allocable_vaddr_start; static intptr_t s_allocable_vaddr_start;
static uint32_t s_allocable_vaddr_end; static intptr_t s_allocable_vaddr_end;
static DRAM_ATTR uint32_t s_mapped_vaddr_start; static intptr_t s_mapped_vaddr_start;
static DRAM_ATTR uint32_t s_mapped_size; static intptr_t s_mapped_vaddr_end;
/**
* Initially map all psram physical address to virtual address. #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
* If psram physical size is larger than virtual address range, then only map the virtual address range. extern uint8_t _ext_ram_bss_start;
*/ extern uint8_t _ext_ram_bss_end;
void IRAM_ATTR esp_spiram_init_cache(void) #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) { 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 //Decide these logics when there's a real PSRAM with larger size
ESP_EARLY_LOGE(TAG, "Virtual address not enough for PSRAM!"); ESP_EARLY_LOGE(TAG, "Virtual address not enough for PSRAM!");
abort(); abort();
} }
s_mapped_vaddr_start = SOC_EXTRAM_DATA_HIGH - s_mapped_size;
Cache_Suspend_DCache(); //On ESP32S3, MMU is shared for both of the cores. Note this when porting `spiram.c`
Cache_Dbus_MMU_Set(MMU_ACCESS_SPIRAM, s_mapped_vaddr_start, 0, 64, s_mapped_size >> 16, 0); uint32_t actual_mapped_len = 0;
REG_CLR_BIT(EXTMEM_DCACHE_CTRL1_REG, EXTMEM_DCACHE_SHUT_CORE0_BUS); 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 #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 #endif
Cache_Resume_DCache(0);
//Currently no non-heap stuff on ESP32S3 #if CONFIG_SPIRAM_MEMTEST
s_allocable_vaddr_start = s_mapped_vaddr_start; //After mapping, simple test SPIRAM first
s_allocable_vaddr_end = SOC_EXTRAM_DATA_HIGH; 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 * Add the PSRAM available region to heap allocator. Heap allocator knows the capabilities of this type of memory,
true when RAM seems OK, false when test fails. WARNING: Do not run this before the 2nd cpu has been * so there's no need to explicitly specify them.
initialized (in a two-core system) or after the heap allocator has taken ownership of the memory. */
*/ esp_err_t esp_spiram_add_to_heapalloc(void)
bool esp_spiram_test(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; esp_err_t IRAM_ATTR esp_spiram_get_mapped_range(intptr_t *out_vstart, intptr_t *out_vend)
size_t p; {
int errct = 0; if (!out_vstart || !out_vend) {
int initial_err = -1; return ESP_ERR_INVALID_ARG;
}
for (p = 0; p < (s / sizeof(int)); p += 8) { if (!s_spiram_inited) {
spiram[p] = p ^ 0xAAAAAAAA; return ESP_ERR_INVALID_STATE;
} }
for (p = 0; p < (s / sizeof(int)); p += 8) {
if (spiram[p] != (p ^ 0xAAAAAAAA)) { *out_vstart = s_mapped_vaddr_start;
errct++; *out_vend = s_mapped_vaddr_end;
if (errct == 1) { return ESP_OK;
initial_err = p * 4; }
}
if (errct < 4) { esp_err_t esp_spiram_get_alloced_range(intptr_t *out_vstart, intptr_t *out_vend)
ESP_EARLY_LOGE(TAG, "SPI SRAM error@%08x:%08x/%08x \n", &spiram[p], spiram[p], p ^ 0xAAAAAAAA); {
} 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); if (!s_spiram_inited) {
return false; return ESP_ERR_INVALID_STATE;
} else {
ESP_EARLY_LOGI(TAG, "SPI SRAM memory test OK");
return true;
} }
*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 //TODO IDF-4318
@ -222,81 +304,6 @@ int IRAM_ATTR rodata_flash2spiram_offset(void)
} }
#endif #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, 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. 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(); 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 * SPDX-FileCopyrightText: 2013-2021 Espressif Systems (Shanghai) CO LTD
* *
@ -35,8 +31,6 @@
#include "driver/spi_common.h" #include "driver/spi_common.h"
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#include "bootloader_common.h" #include "bootloader_common.h"
#if CONFIG_SPIRAM_MODE_QUAD
#include "soc/rtc.h" #include "soc/rtc.h"
#include "esp_private/spi_flash_os.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) 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; *out_size_bytes = s_psram_size;
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE); 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) 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; *out_size_bytes = s_psram_size;
return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE); return (s_psram_size ? ESP_OK : ESP_ERR_INVALID_STATE);
} }
#endif // CONFIG_SPIRAM

View File

@ -9,16 +9,16 @@
#include "esp_err.h" #include "esp_err.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#define PSRAM_SIZE_2MB (2 * 1024 * 1024) #define PSRAM_SIZE_2MB (2 * 1024 * 1024)
#define PSRAM_SIZE_4MB (4 * 1024 * 1024) #define PSRAM_SIZE_4MB (4 * 1024 * 1024)
#define PSRAM_SIZE_8MB (8 * 1024 * 1024) #define PSRAM_SIZE_8MB (8 * 1024 * 1024)
#define PSRAM_SIZE_16MB (16 * 1024 * 1024) #define PSRAM_SIZE_16MB (16 * 1024 * 1024)
#define PSRAM_SIZE_32MB (32 * 1024 * 1024) #define PSRAM_SIZE_32MB (32 * 1024 * 1024)
#ifdef __cplusplus
extern "C" {
#endif
typedef enum { typedef enum {
PSRAM_CACHE_S80M = 1, PSRAM_CACHE_S80M = 1,
PSRAM_CACHE_S40M, 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); uint32_t data_size = (uint32_t)(_rodata_reserved_end - _rodata_start);
#else #else
uint32_t data_start = SOC_DROM_LOW; 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 #endif
ESP_LOGI(TAG, "Code start at %08x, total %.2f KiB, data start at %08x, total %.2f KiB", 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); code_start, (float)code_size/1024, data_start, (float)data_size/1024);

View File

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

View File

@ -223,7 +223,7 @@ SECTIONS
_noinit_end = ABSOLUTE(.); _noinit_end = ABSOLUTE(.);
} > dram0_0_seg } > 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 (NOLOAD) :
{ {
_ext_ram_bss_start = ABSOLUTE(.); _ext_ram_bss_start = ABSOLUTE(.);

View File

@ -233,7 +233,7 @@ SECTIONS
_noinit_end = ABSOLUTE(.); _noinit_end = ABSOLUTE(.);
} > dram0_0_seg } > 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 (NOLOAD) :
{ {
_ext_ram_bss_start = ABSOLUTE(.); _ext_ram_bss_start = ABSOLUTE(.);
@ -249,7 +249,6 @@ SECTIONS
{ {
. = ALIGN (8); . = ALIGN (8);
_bss_start = ABSOLUTE(.); _bss_start = ABSOLUTE(.);
*(.ext_ram.bss*)
mapping[dram0_bss] mapping[dram0_bss]

View File

@ -90,7 +90,7 @@ MEMORY
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/* Flash mapped constant data */ /* 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.) */ /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
@ -115,6 +115,11 @@ MEMORY
#else #else
rtc_slow_seg(RW) : org = 0x50000000 , len = 0x2000 rtc_slow_seg(RW) : org = 0x50000000 , len = 0x2000
#endif // CONFIG_ULP_COPROC_ENABLED #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 #if CONFIG_ESP32S3_USE_FIXED_STATIC_RAM_SIZE

View File

@ -231,7 +231,6 @@ SECTIONS
{ {
. = ALIGN (8); . = ALIGN (8);
_bss_start = ABSOLUTE(.); _bss_start = ABSOLUTE(.);
*(.ext_ram.bss*)
mapping[dram0_bss] mapping[dram0_bss]
@ -292,7 +291,7 @@ SECTIONS
*/ */
.flash_rodata_dummy (NOLOAD): .flash_rodata_dummy (NOLOAD):
{ {
_flash_rodata_dummy_start = .; _flash_rodata_dummy_start = ABSOLUTE(.);
/* Start at the same alignment constraint than .flash.text */ /* Start at the same alignment constraint than .flash.text */
. = ALIGN(ALIGNOF(.flash.text)); . = ALIGN(ALIGNOF(.flash.text));
/* Create an empty gap as big as .flash.text section */ /* Create an empty gap as big as .flash.text section */
@ -381,6 +380,25 @@ SECTIONS
mapping[rodata_noload] mapping[rodata_noload]
} > default_rodata_seg } > 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 */ /* Marks the end of IRAM code segment */
.iram0.text_end (NOLOAD) : .iram0.text_end (NOLOAD) :
{ {

View File

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

View File

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

View File

@ -185,7 +185,7 @@
#define SOC_RTC_DATA_LOW 0x50000000 #define SOC_RTC_DATA_LOW 0x50000000
#define SOC_RTC_DATA_HIGH 0x50002000 #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_EXTRAM_DATA_HIGH 0x3E000000
#define SOC_IROM_MASK_LOW 0x40000000 #define SOC_IROM_MASK_LOW 0x40000000
#define SOC_IROM_MASK_HIGH 0x4001A100 #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. 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: .. _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. 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``. 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). * 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 .. 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. 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. 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 .. 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_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 ``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 ``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"``. - 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 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``. - 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`` 标志从该池中分配存储器。 由于有些内存缓冲器仅可在内部存储器中分配,因此需要使用第二个配置项 :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: .. _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 段)。 启用该选项后,从 {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 中。 也可以使用链接器片段方案 ``extram_bss`` 将组件或库的 BSS 段放到片外 RAM 中。

View File

@ -16,9 +16,9 @@ DRAM数据 RAM
非常量静态数据(.data 段)和零初始化数据(.bss 段)由链接器放入内部 SRAM 作为数据存储。此区域中的剩余空间可在程序运行时用作堆。 非常量静态数据(.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 .. only:: esp32