内存同步

[English]

简介

ESP32-S2 可以通过以下方式访问其连接的 PSRAM:

  • CPU

  • DMA

默认情况下,CPU 通过 cache 访问上述内存,而 DMA 则可以直接访问内存。

这可能导致 cache 数据不一致的问题:

  • 当 DMA 事务更改内存块的内容,并且该内容已经加载到 cache 中时:

    • CPU 可能会读取陈旧数据。

    • cache 中的陈旧数据可能会被写回到内存中,而 DMA 事务更新的新数据将被覆盖。

  • 当 CPU 更改了地址的内容,内容已经加载至 cache 中,但还未存在于内存中(cache 会根据自己的策略将内容写回内存)时:

    • 下一个 DMA 事务从内存中读取此内容,将会获取陈旧数据。

解决此类 cache 数据不一致问题的常见方法有三种:

  1. 基于硬件的 cache 一致性互连,ESP32-S2 没有此功能。

  2. 使用来自 non-cacheable 内存的 DMA 缓冲区(CPU 绕过 cache 访问的内存被称为 non-cacheable 内存)。

  3. 显式调用内存同步 API 将 cache 中的内容写回到内存,或使 cache 中的内容无效化。

内存同步驱动程序

建议使用 ESP-IDF 的 esp_mm 组件所提供的内存同步 API esp_cache_msync() 来处理此类 cache 数据不一致的问题。

驱动程序的概念

cache 与内存同步的方向:

cache 与内存同步的类型:

驱动程序的行为

调用 esp_cache_msync(),可以同步 cache 和内存。第一个参数 addr 和第二个参数 size 共同描述了要同步的内存区域。关于第三个参数 flags

  • ESP_CACHE_MSYNC_FLAG_DIR_C2M。使用此标志,指定地址区域中的内容将被写回到内存中。这一方向通常在 CPU 更新地址内容 之后 使用(例如对地址执行 memset 后),且需要在 DMA 对同一地址进行操作 之前 使用。

  • ESP_CACHE_MSYNC_FLAG_DIR_M2C。使用此标志,指定地址区域中的内容在 cache 中将无效化。这一方向通常在 DMA 更新地址内容 之后 使用,且需要在 CPU 将操作读取到同一地址 之前 使用。

上述两个标志用于选择同步的方向,不能同时使用。如果两个标志都未使用, esp_cache_msync() 将默认选择 ESP_CACHE_MSYNC_FLAG_DIR_C2M

上述两个标志能帮助选择同步地址的类型,不能同时使用,且如果没有用其中任何一个,则 esp_cache_msync() 将默认选择 ESP_CACHE_MSYNC_FLAG_TYPE_DATA

地址对齐的要求

使用 esp_cache_msync() 时,对地址和大小(以字节为单位)存在来自 cache 的对齐要求。

  • 起始地址和大小都符合 cache 与内存同步对齐要求的地址区域被称为 对齐地址区域

  • 起始地址或大小不符合 cache 与内存同步对齐要求的地址区域被称为 非对齐地址区域

默认情况下,如果指定了非对齐地址区域,则 esp_cache_msync() 将报错 ESP_ERR_INVALID_ARG,并告知所需的对齐方式。

有关地址对齐要求的警告

可以通过设置 ESP_CACHE_MSYNC_FLAG_UNALIGNED 标志跳过此类检查。但请注意,使用此标志需谨慎,因为在非对齐地址区域内同步 cache 和内存可能会在无形中破坏内存。

举个例子,假设:

  • 对齐要求为 0x40 字节。

  • 调用 esp_cache_msync(),并使用 ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_UNALIGNED 标志,指定的地址区域为 0x4000_0020 ~ 0x4000_0060(详见下图中的 data C)。

上述设置将触发地址区域 0x4000_0000 ~ 0x4000_0080 cache 失效,详见下图中的 sync item0sync item1

如果 0x4000_0000 ~ 0x4000_0020 中的内容(下图中的 data A)或 0x4000_0060 ~ 0x4000_0080 中的内容(下图中的 data B)尚未写回到内存,则 data Adata B 将被丢弃。

../../_images/cache_align_issue.png

API 参考

API 参考 - ESP Msync 驱动程序

Header File

  • components/esp_mm/include/esp_cache.h

  • This header file can be included with:

    #include "esp_cache.h"
    
  • This header file is a part of the API provided by the esp_mm component. To declare that your component depends on esp_mm, add the following to your CMakeLists.txt:

    REQUIRES esp_mm
    

    or

    PRIV_REQUIRES esp_mm
    

Functions

esp_err_t esp_cache_msync(void *addr, size_t size, int flags)

Memory sync between Cache and storage memory.

For cache-to-memory (C2M) direction:

  • For cache writeback supported chips (you can refer to SOC_CACHE_WRITEBACK_SUPPORTED in soc_caps.h)

    • This API will do a writeback to synchronise between cache and storage memory

    • With ESP_CACHE_MSYNC_FLAG_INVALIDATE, this API will also invalidate the values that just written

    • Note: although ESP32 is with PSRAM, but cache writeback isn't supported, so this API will do nothing on ESP32

  • For other chips, this API will do nothing. The out-of-sync should be already dealt by the SDK

For memory-to-cache (M2C) direction:

  • This API will by default do an invalidation

This API is cache-safe and thread-safe

备注

If you don't set direction (ESP_CACHE_MSYNC_FLAG_DIR_x flags), this API is by default C2M direction

备注

If you don't set type (ESP_CACHE_MSYNC_FLAG_TYPE_x flags), this API is by default doing msync for data

备注

You should not call this during any Flash operations (e.g. esp_flash APIs, nvs and some other APIs that are based on esp_flash APIs)

备注

If XIP_From_PSRAM is enabled (by enabling both CONFIG_SPIRAM_FETCH_INSTRUCTIONS and CONFIG_SPIRAM_RODATA), you can call this API during Flash operations

参数
  • addr -- [in] Starting address to do the msync

  • size -- [in] Size to do the msync

  • flags -- [in] Flags, see ESP_CACHE_MSYNC_FLAG_x

返回

  • ESP_OK:

    • Successful msync

    • For C2M direction, if this chip doesn't support cache writeback, if the input addr is a cache supported one, this API will return ESP_OK

  • ESP_ERR_INVALID_ARG: Invalid argument, not cache supported addr, see printed logs

Macros

ESP_CACHE_MSYNC_FLAG_INVALIDATE

Do an invalidation.

Cache msync flags

  • For cache-to-memory (C2M) direction: setting this flag will start an invalidation after the cache writeback operation

  • For memory-to-cache (M2C) direction: setting / unsetting this flag will behave similarly, trigger an invalidation

ESP_CACHE_MSYNC_FLAG_UNALIGNED

Allow msync to a address block that are not aligned to the data cache line size.

ESP_CACHE_MSYNC_FLAG_DIR_C2M

Cache msync direction: from Cache to memory.

备注

If you don't set direction (ESP_CACHE_MSYNC_FLAG_DIR_x flags), it is by default cache-to-memory (C2M) direction

ESP_CACHE_MSYNC_FLAG_DIR_M2C

Cache msync direction: from memory to Cache.

ESP_CACHE_MSYNC_FLAG_TYPE_DATA

Cache msync type: data.

备注

If you don't set type (ESP_CACHE_MSYNC_FLAG_TYPE_x flags), it is by default data type

ESP_CACHE_MSYNC_FLAG_TYPE_INST

Cache msync type: instruction.


此文档对您有帮助吗?