Himem
概述
对于小于等于 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”),以及一个或多个需映射到此范围的内存存储体。
应用示例
system/himem 演示了如何在 ESP32 上使用 Himem API 对 8 MiB PSRAM 芯片的上部 4 MiB 进行内存测试,展示了如何分配地址空间、分配物理内存,并在分配的地址空间中切换内存。
API 参考
Header File
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 onesp_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