# Himem

[中文]

## Overview

For external memories that are <= 4 MiB, the MMU is configured to use a "unity mapping", meaning that each CPU address is mapped 1-to-1 to the external SPI RAM address, thus allowing external memory to be accessed transparently. However, because the address space for external memory is limited to 4 MiB, only SPI RAM chips that are <= 4 MiB in size can be used fully transparently.

It is still possible for ESP32 to use SPI RAM chips >= 4 MiB in size. However, the memory on these chips needs to be accessed using a bank switching scheme. ESP-IDF provides the Himem API to control this bank switching. More specifically, the Himem API allows particular 32 K banks within 4 MiB address switch mappings at run time, thus allowing access to more than 4 MiB of external memory.

## Usage

In order to use the Himem API, you have to enable it in the menuconfig using CONFIG_SPIRAM_BANKSWITCH_ENABLE, as well as set the amount of banks reserved for this in CONFIG_SPIRAM_BANKSWITCH_RESERVE. This decreases the amount of external memory allocated by functions like `malloc()`, but it allows you to use the Himem API to map any of the remaining memory into the reserved banks.

The Himem API is more-or-less an abstraction of the bank switching scheme: it allows you to claim one or more banks of address space (called 'regions' in the API) as well as one or more of banks of memory to map into the ranges.

## Application Examples

- system/himem demonstrates how to use the Himem API on ESP32 to run a memory test of the upper 4 MiB of an 8 MiB PSRAM chip, illustrating how to allocate address space, allocate the physical memory, and switch it in or out of the allocated address space.

## API Reference

### Header File

- components/esp_psram/include/esp32/himem.h

- This header file can be included with:

  >     #include "esp32/himem.h"

- This header file is a part of the API provided by the `esp_psram` component. To declare that your component depends on `esp_psram`, add the following to your CMakeLists.txt:

  >     REQUIRES esp_psram

  > or

  >     PRIV_REQUIRES esp_psram

### Functions

esp_err_t esp_himem_alloc(size_t size, esp_himem_handle_t *handle_out)

  Allocate a block in high memory.

  Parameters:

    - size -- Size of the to-be-allocated block, in bytes. Note that this needs to be a multiple of the external RAM mmu block size (32K).

    - handle_out -- [out] Handle to be returned

  Returns:

    - ESP_OK if succesful

    - ESP_ERR_NO_MEM if out of memory

    - ESP_ERR_INVALID_SIZE if size is not a multiple of 32K

esp_err_t esp_himem_alloc_map_range(size_t size, esp_himem_rangehandle_t *handle_out)

  Allocate a memory region to map blocks into.

  This allocates a contiguous CPU memory region that can be used to map blocks of physical memory into.

  Parameters:

    - size -- Size of the range to be allocated. Note this needs to be a multiple of the external RAM mmu block size (32K).

    - handle_out -- [out] Handle to be returned

  Returns:

    - ESP_OK if succesful

    - ESP_ERR_NO_MEM if out of memory or address space

    - ESP_ERR_INVALID_SIZE if size is not a multiple of 32K

esp_err_t esp_himem_map(esp_himem_handle_t handle, esp_himem_rangehandle_t range, size_t ram_offset, size_t range_offset, size_t len, int flags, void **out_ptr)

  Map a block of high memory into the CPUs address space.

  This effectively makes the block available for read/write operations.

  Note

  The region to be mapped needs to have offsets and sizes that are aligned to the SPI RAM MMU block size (32K)

  Parameters:

    - handle -- Handle to the block of memory, as given by esp_himem_alloc

    - range -- Range handle to map the memory in

    - ram_offset -- Offset into the block of physical memory of the block to map

    - range_offset -- Offset into the address range where the block will be mapped

    - len -- Length of region to map

    - flags -- One of ESP_HIMEM_MAPFLAG_*

    - out_ptr -- [out] Pointer to variable to store resulting memory pointer in

  Returns:

    - ESP_OK if the memory could be mapped

    - ESP_ERR_INVALID_ARG if offset, range or len aren't MMU-block-aligned (32K)

    - ESP_ERR_INVALID_SIZE if the offsets/lengths don't fit in the allocated memory or range

    - ESP_ERR_INVALID_STATE if a block in the selected ram offset/length is already mapped, or if a block in the selected range offset/length already has a mapping.

esp_err_t esp_himem_free(esp_himem_handle_t handle)

  Free a block of physical memory.

  This clears out the associated handle making the memory available for re-allocation again. This will only succeed if none of the memory blocks currently have a mapping.

  Parameters:

    handle -- Handle to the block of memory, as given by esp_himem_alloc

  Returns:

    - ESP_OK if the memory is succesfully freed

    - ESP_ERR_INVALID_ARG if the handle still is (partially) mapped

esp_err_t esp_himem_free_map_range(esp_himem_rangehandle_t handle)

  Free a mapping range.

  This clears out the associated handle making the range available for re-allocation again. This will only succeed if none of the range blocks currently are used for a mapping.

  Parameters:

    handle -- Handle to the range block, as given by esp_himem_alloc_map_range

  Returns:

    - ESP_OK if the memory is succesfully freed

    - ESP_ERR_INVALID_ARG if the handle still is (partially) mapped to

esp_err_t esp_himem_unmap(esp_himem_rangehandle_t range, void *ptr, size_t len)

  Unmap a region.

  Parameters:

    - range -- Range handle

    - ptr -- Pointer returned by esp_himem_map

    - len -- Length of the block to be unmapped. Must be aligned to the SPI RAM MMU blocksize (32K)

  Returns:

    - ESP_OK if the memory is succesfully unmapped,

    - ESP_ERR_INVALID_ARG if ptr or len are invalid.

size_t esp_himem_get_phys_size(void)

  Get total amount of memory under control of himem API.

  Returns:

    Amount of memory, in bytes

size_t esp_himem_get_free_size(void)

  Get free amount of memory under control of himem API.

  Returns:

    Amount of free memory, in bytes

size_t esp_himem_reserved_area_size(void)

  Get amount of SPI memory address space needed for bankswitching.

  Note

  This is also weakly defined in esp32/spiram.c and returns 0 there, so if no other function in this file is used, no memory is reserved.

  Returns:

    Amount of reserved area, in bytes

### Macros

ESP_HIMEM_BLKSZ

ESP_HIMEM_MAPFLAG_RO

  Indicates that a mapping will only be read from. Note that this is unused for now.

### Type Definitions

typedef struct esp_himem_ramdata_t *esp_himem_handle_t

typedef struct esp_himem_rangedata_t *esp_himem_rangehandle_t

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.