Warning

This document is not updated for ESP32H4 yet, so some of the content may not be correct.

This warning was automatically inserted due to the source file being in the add_warnings_pages list.

# Support for External RAM

[中文]

## Introduction

ESP32-H4 has a few hundred kilobytes of internal RAM, residing on the same die as the rest of the chip components. It can be insufficient for some purposes, so ESP32-H4 has the ability to use up to Value not updated of virtual addresses for external PSRAM (pseudo-static RAM) memory. The external memory is incorporated in the memory map and, with certain restrictions, is usable in the same way as internal data RAM.

## Hardware

ESP32-H4 supports PSRAM connected in parallel with the SPI flash chip. While ESP32-H4 is capable of supporting several types of RAM chips, ESP-IDF currently only supports Espressif branded PSRAM chips (e.g., ESP-PSRAM32, ESP-PSRAM64, etc).

Note

Note

Espressif produces both modules and system-in-package chips that integrate compatible PSRAM and flash and are ready to mount on a product PCB. Consult the Espressif website for more information. If you are using a custom PSRAM chip, ESP-IDF SDK might not be compatible with it.

For specific details about connecting the SoC or module pins to an external PSRAM chip, consult the SoC or module datasheet.

## Configuring External RAM

Note

The `SPI RAM` configuration options are available only if the `esp_psram` component is included in the build. To include `SPI RAM` into your project, add the `esp_psram` component as a dependency in either `REQUIRES` or `PRIV_REQUIRES` when registering your component with `idf_component_register`.

ESP-IDF fully supports the use of external RAM in applications. Once the external RAM is initialized at startup, ESP-IDF can be configured to integrate the external RAM in several ways:

- Integrate RAM into the ESP32-H4 Memory Map

- Add External RAM to the Capability Allocator

- Provide External RAM via malloc() (default)

- Allow .bss Segment to Be Placed in External Memory

- Allow .noinit Segment to Be Placed in External Memory

- Execute In Place (XiP) from PSRAM

### Integrate RAM into the ESP32-H4 Memory Map

Select this option by choosing `Integrate RAM into memory map` from CONFIG_SPIRAM_USE.

This is the most basic option for external RAM integration. Most likely, you will need another, more advanced option.

During the ESP-IDF startup, external RAM is mapped into the data virtual address space. The address space is dynamically allocated. The length will be the minimum length between the PSRAM size and the available data virtual address space size.

Applications can manually place data in external memory by creating pointers to this region. So if an application uses external memory, it is responsible for all management of the external RAM: coordinating buffer usage, preventing corruption, etc.

It is recommended to access the PSRAM by ESP-IDF heap memory allocator (see next chapter).

### Add External RAM to the Capability Allocator

Select this option by choosing `Add RAM to heap_caps allocator (malloc() stays internal by default)` from CONFIG_SPIRAM_USE.

When enabled, memory is mapped to data virtual address space and also added to the capabilities-based heap memory allocator using `MALLOC_CAP_SPIRAM`. Since this memory is also tagged with `MALLOC_CAP_DEFAULT`, calls such as `heap_caps_malloc(size, MALLOC_CAP_DEFAULT)` can still return PSRAM pointers.

To explicitly allocate memory from external RAM, a program should call `heap_caps_malloc(size, MALLOC_CAP_SPIRAM)`. After use, this memory can be freed by calling the normal `free()` function.

In this mode, standard `malloc()` does not allocate from external RAM by default because it uses a separate default allocation policy.

### Provide External RAM via malloc()

Select this option by choosing `Make RAM allocatable using malloc() as well` from CONFIG_SPIRAM_USE. This is the default option.

In this case, memory is added to the capability allocator as described for the previous option. However, it is also added to the pool of RAM that can be returned by the standard `malloc()` function.

This allows any application to use the external RAM without having to rewrite the code to use `heap_caps_malloc(..., MALLOC_CAP_SPIRAM)`.

An additional configuration item, CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL, can be used to set the size threshold when a single allocation should prefer external memory:

- When allocating a size less than or equal to the threshold, the allocator will try internal memory first.

- When allocating a size larger than the threshold, the allocator will try external memory first.

If a suitable block of preferred internal/external memory is not available, the allocator will try the other type of memory.

Because some buffers can only be allocated in internal memory, a second configuration item CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL reserves a pool of internal DMA-capable memory at startup (in `main_task`, after PSRAM is initialized). The pool is malloc from the regular internal heaps and re-registered as separate heap pool.

The reserved pool uses the heap capability priority mechanism:

- Medium priority — `MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL`: explicit `heap_caps_malloc()` requests with these flags are preferentially served from this pool.

- Low priority — `MALLOC_CAP_DEFAULT`: `malloc()` may use the pool only after other internal heaps with higher-priority `MALLOC_CAP_DEFAULT` are exhausted.

Therefore, under normal conditions `malloc()` does not allocate from this pool, but it can fall back to it as a last resort before allocation fails entirely.

### Allow .bss Segment to Be Placed in External Memory

Enable this option by checking CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY.

If enabled, the region of the data virtual address space where the PSRAM is mapped to will be used to store zero-initialized data (BSS segment) from the lwIP, net80211, libpp, wpa_supplicant and bluedroid ESP-IDF libraries.

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`.

This option reduces the internal static memory used by the BSS segment.

Remaining external RAM can also be added to the capability heap allocator using the method shown above.

### Allow .noinit Segment to Be Placed in External Memory

Enable this option by checking CONFIG_SPIRAM_ALLOW_NOINIT_SEG_EXTERNAL_MEMORY. If enabled, the region of the data virtual address space where the PSRAM is mapped to will be used to store non-initialized data. The values placed in this segment will not be initialized or modified even during startup or restart.

By applying the macro `EXT_RAM_NOINIT_ATTR`, data could be moved from the internal NOINIT segment to external RAM. Remaining external RAM can still be added to the capability heap allocator using the method shown above, Add External RAM to the Capability Allocator.

#### Execute In Place (XiP) from PSRAM

The CONFIG_SPIRAM_XIP_FROM_PSRAM option enables the executable in place (XiP) from PSRAM feature. With this option sections that are normally placed in flash, `.text` (for instructions) and `.rodata` (for read only data), will be loaded in PSRAM.

With this option enabled, the cache will not be disabled during an SPI1 flash operation, so code that requires executing during an SPI1 flash operation does not have to be placed in internal RAM.

## Restrictions

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 read operations from or write operations 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 uses the same cache region as the external flash. This means that frequently accessed variables in external RAM can be read and modified almost as quickly as in internal RAM. However, when accessing large chunks of data (> 32 KB), the cache can be insufficient, and speeds will fall back to the access speed of the external RAM. Moreover, accessing large chunks of data can "push out" cached flash, possibly making the execution of code slower afterwards.

- In general, external RAM will not be used as task stack memory. `xTaskCreate()` and similar functions will always allocate internal memory for stack and task TCBs. Task stacks can optionally be placed in external RAM — see Task Stack Placement in External RAM below.

### Task Stack Placement in External RAM

There are three ways to place task stacks in external RAM:

1. Per-task (explicit) – Use `xTaskCreateWithCaps()` with `MALLOC_CAP_SPIRAM`. Requires CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM.

2. Per-task (static) – Use `xTaskCreateStatic()` with a caller-supplied buffer in external RAM. Requires CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM.

3. Global default (automatic) – Enable CONFIG_FREERTOS_PLACE_TASK_STACKS_IN_EXT_RAM. When set, every call to `xTaskCreate()` / `xTaskCreatePinnedToCore()` allocates the stack from PSRAM first, falling back to internal RAM if PSRAM is exhausted. TCBs are always kept in internal DRAM.

When CONFIG_FREERTOS_PLACE_TASK_STACKS_IN_EXT_RAM is enabled, the following additional restrictions apply:

- Flash operations – Any code path that temporarily disables the CPU cache (flash erase/write, NVS, OTA) must run on a task whose stack is in internal RAM, or the operations must be routed through the espressif/esp_flash_dispatcher component, which executes flash operations on a dedicated internal-RAM task.

- Deep sleep – Calling `esp_deep_sleep_start()` from a task with a PSRAM stack logs an error and proceeds anyway, which will likely crash when the cache is disabled during the sleep transition. Use `esp_deep_sleep_try_to_start()` instead: it returns `ESP_ERR_NOT_ALLOWED` cleanly when called from a PSRAM-stacked task. If deep sleep is required, trigger it from a task whose stack is in internal RAM.

- Light sleep – Calling `esp_light_sleep_start()` directly from a PSRAM-stacked task is also rejected with `ESP_ERR_NOT_ALLOWED`. Tickless-idle light sleep (auto-light-sleep) is safe because it is initiated by the idle task, whose stack is always in internal RAM; PSRAM-stacked tasks simply block and resume normally after wake-up.

- pthread – `pthread_create()` delegates to `xTaskCreate()`, so pthread stacks will also move to PSRAM when this option is on.

See the system/freertos/psram_stack example for a working demonstration.

## Failure to Initialize

By default, failure to initialize external RAM will cause the ESP-IDF startup to abort. This can be disabled by enabling the config item CONFIG_SPIRAM_IGNORE_NOTFOUND.

## Encryption

It is possible to enable automatic encryption for data stored in external RAM. When this is enabled any data read and written through the cache will automatically be encrypted or decrypted by the external memory encryption hardware.

This feature is enabled whenever flash encryption is enabled. For more information on how to enable and how it works see Flash Encryption.

Was this page helpful?

- Thank you! We received your feedback.
- If you have any comments, fill in Espressif Documentation Feedback Form.

- We value your feedback.
- Let us know how we can improve this page by filling in Espressif Documentation Feedback Form.