Himem

[English]

概述

对于小于等于 4 MiB 大小的外部内存,MMU 配置为使用“统一映射”,即每个 CPU 地址一对一地映射到外部 SPI RAM 地址,从而透明地访问外部内存。但是,由于外部内存的地址空间只有 4 MiB,因此只有小于等于 4 MiB 大小的 SPI RAM 芯片才能完全透明地使用。

ESP32 仍可使用大于等于 4 MiB 大小的 SPI RAM 芯片。不过,这些芯片上的内存需要通过存储体切换方案 (bank switching) 来访问。ESP-IDF 提供了 Himem API 来控制此类存储体切换。具体而言,Himem API 允许在运行时切换地址映射,将特定的 32 K 存储体映射到 4 MiB 地址空间中,从而访问超过 4 MiB 的外部内存。

使用注意事项

使用 Himem API 前,必须在 menuconfig 中启用 CONFIG_SPIRAM_BANKSWITCH_ENABLE,并在 CONFIG_SPIRAM_BANKSWITCH_RESERVE 中设置为此预留的储存体数量。这会减少由 malloc() 等函数分配的外部内存量,但允许使用 Himem API 将任何剩余内存映射到预留的存储体中。

Himem API 可以看作是存储体切换方案的一个抽象。具体而言,该 API 允许声明一个或多个地址空间存储体(在 API 中称为“regions”),以及一个或多个需映射到此范围的内存存储体。

示例

ESP-IDF 中提供了对大内存范围进行简单内存测试的示例,请前往 system/himem 查看。

API 参考

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.

参数
  • 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

返回

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

参数
  • 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

返回

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

备注

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

参数
  • 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

返回

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

参数

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

返回

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

参数

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

返回

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

参数
  • 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)

返回

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

返回

Amount of memory, in bytes

size_t esp_himem_get_free_size(void)

Get free amount of memory under control of himem API.

返回

Amount of free memory, in bytes

size_t esp_himem_reserved_area_size(void)

Get amount of SPI memory address space needed for bankswitching.

备注

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.

返回

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