mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
commit
5bb59b00e7
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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]")
|
||||
{
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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}")
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
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}")
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
*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 < 4) {
|
||||
ESP_EARLY_LOGE(TAG, "SPI SRAM error@%08x:%08x/%08x \n", &spiram[p], spiram[p], p ^ 0xAAAAAAAA);
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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(.);
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) :
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,7 +129,7 @@ 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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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``.
|
||||
|
@ -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 中。
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user