mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
fix(mmap): fixed some API read wrong data via mmap when flash being erased/written while XIP on PSRAM
Before: The cache won't be disabled when XIP on psram. But during flash erasing/programming, read data will be courrupt. When XIP in psram is enabled, the image is not mapped to the cache so usually there will be no flash access. The only way to read from flash is via the driver or use mmap. The driver has protection during erasing, while th mmap region not. Now: Mmap APIs provide a flag to make mmap->unmap region mutually exclusive to flash erase/programming when XIP from psram. SPI Flash write APIs will benefit from this. When the flag is used, no concurrent access to mapped region will happen while writing; otherwise the cache will be disable to avoid data corruption. Most ESP-IDF APIs calls mmap with this flag. As for users calling mmap-like APIs directly, they can choose whether to enable this by a flag. Closes https://github.com/espressif/esp-idf/issues/14897
This commit is contained in:
committed by
Michael (XIAO Xufeng)
parent
fd0b33dfda
commit
3d76ced5bb
@@ -172,6 +172,31 @@ Note that since memory mapping happens in pages, it may be possible to read data
|
||||
|
||||
mmap is supported by cache, so it can only be used on main flash.
|
||||
|
||||
.. only:: not esp32
|
||||
|
||||
.. _blocks_write_flag:
|
||||
|
||||
About the :cpp:enumerator:`SPI_FLASH_MMAP_FLAG_BLOCKS_WRITE` flag
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When flash erasing/writing happen while cache mapping exists, it often causes some cache region to be invalidated and reloaded again. To improve the performance, it is suggested to specify this flag when you are sure:
|
||||
|
||||
1. This mapping will end in a short time, and
|
||||
2. Before the mapping ends, you don't need to erase or write the flash.
|
||||
|
||||
This flag will prevent all writes until the corresponding munmap is called. Most ESP-IDF APIs that rely on the mapping to flash internally use this flag.
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND or SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
This flag also helps to prevent the cache being disabled when you are using following modes. See their documentation for more details.
|
||||
|
||||
.. list::
|
||||
|
||||
:SOC_SPIRAM_XIP_SUPPORTED: - :ref:`xip_from_psram`
|
||||
:SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND: - :ref:`auto-suspend`
|
||||
|
||||
This flag is implemented by a lock in the SPI Flash driver. The lock is taken when :cpp:func:`spi_flash_mmap` (or mmap-like APIs) is called with the flag and released until corresponding unmap is called. There is a reference counter internally allowing concurrent mapping to the flash. Only after the last mapping to Flash with the flag is revoked (counter equals 0) can the flash erasing/writing APIs start execution.
|
||||
|
||||
SPI Flash Implementation
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -1,61 +1,90 @@
|
||||
.. _concurrency-constraints-flash:
|
||||
|
||||
Concurrency Constraints for Flash on SPI1
|
||||
=========================================
|
||||
Concurrency Constraints for Flash on SPI0/1
|
||||
===========================================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
The SPI0/1 bus is shared between the instruction & data cache (for firmware execution) and the SPI1 peripheral (controlled by the drivers including this SPI Flash driver). Hence, operations to SPI1 will cause significant influence to the whole system. This kind of operations include calling SPI Flash API or other drivers on SPI1 bus, any operations like read/write/erase or other user defined SPI operations, regardless to the main flash or other SPI slave devices.
|
||||
The SPI0/1 bus is shared between the cache and the SPI1 peripheral (controlled by the drivers including this SPI Flash driver). Operations to SPI1 may cause significant influence to the cache and hence the whole system. There are no such constraints and impacts for flash chips connected to other SPI buses, which are not covered in this document.
|
||||
|
||||
.. only:: not (esp32c3 or SOC_SPIRAM_XIP_SUPPORTED)
|
||||
There are three kinds of activities that can happen on SPI0/1 bus:
|
||||
|
||||
On {IDF_TARGET_NAME}, these caches must be disabled while reading/writing/erasing.
|
||||
- Flash writing operations (via SPI1). For example, erasing, page programming, or status register writing commands (e.g., ``SE``, ``PP``, and ``WRSR``). During these commands, the flash is in a unreadable state. The CPU and the cache have to wait until the writing command is completed. APIs below can trigger writing commands:
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
|
||||
- Calling non_encrypted SPI flash write API (:cpp:func:`esp_flash_write`, :cpp:func:`esp_flash_erase_region`, etc.)
|
||||
- Calling :cpp:func:`esp_flash_write_encrypted`
|
||||
|
||||
On {IDF_TARGET_NAME}, the config option :ref:`CONFIG_SPI_FLASH_AUTO_SUSPEND` allows the cache to read flash concurrently with SPI1 operations. This is an optional feature that depends on special SPI Flash models, hence disabled by default. See :ref:`auto-suspend` for more details.
|
||||
- Short operations (via SPI1, includes non-writing flash commands). APIs below can trigger short operations:
|
||||
|
||||
If this option is disabled, the caches must be disabled while reading/writing/erasing operations. There are some constraints using driver on the SPI1 bus, see :ref:`impact_disabled_cache`. These constraints will cause more IRAM/DRAM usages.
|
||||
.. list::
|
||||
|
||||
.. only:: SOC_SPIRAM_XIP_SUPPORTED
|
||||
- Calling non_encrypted SPI flash read API (:cpp:func:`esp_flash_read`, etc.)
|
||||
:esp32: - Or other drivers on SPI1 bus for user defined SPI operations (enable experimental feature :ref:`CONFIG_SPI_FLASH_SHARE_SPI1_BUS`)
|
||||
|
||||
On {IDF_TARGET_NAME}, the config options :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` (disabled by default) allows the cache to read/write PSRAM concurrently with SPI1 operations. See :ref:`xip_from_psram` for more details.
|
||||
- Cache read (via SPI0). Following API and operations can trigger cache read:
|
||||
|
||||
If these options are disabled, the caches must be disabled while reading/writing/erasing operations. There are some constraints using driver on the SPI1 bus, see :ref:`impact_disabled_cache`. These constraints will cause more IRAM/DRAM usages.
|
||||
- Code execution from SPI Flash or PSRAM
|
||||
- Fetch static data of .data/.rodata/.bss segment from SPI Flash or PSRAM
|
||||
- All other read/write operation to the PSRAM via the heap or `esp_himem`
|
||||
- Read from area mapped to SPI Flash, includes:
|
||||
|
||||
.. _impact_disabled_cache:
|
||||
- mmap-like functions: :cpp:func:`spi_flash_mmap`, :cpp:func:`spi_flash_mmap_pages`, :cpp:func:`esp_mmu_map`, :cpp:func:`bootloader_mmap`, and :cpp:func:`esp_partition_mmap`.
|
||||
- Functions relying on :cpp:func:`spi_flash_mmap`: :cpp:func:`esp_partition_find`, :cpp:func:`esp_partition_register_external`.
|
||||
- Encrypted flash read/write APIs :cpp:func:`esp_flash_read_encrypted` and :cpp:func:`esp_flash_write_encrypted` (on esp32, or for data validation).
|
||||
|
||||
When the Caches Are Disabled
|
||||
----------------------------
|
||||
.. only:: esp32
|
||||
|
||||
Under this condition, all CPUs should always execute code and access data from internal RAM. The APIs documented in this file will disable the caches automatically and transparently.
|
||||
Caches are disabled during all SPI1 operations. Most tasks will be disabled, and access to Flash/PSRAM is forbidden. See :ref:`cache_disabled` for more details.
|
||||
|
||||
.. only:: esp32c3
|
||||
.. only:: not esp32
|
||||
|
||||
.. note::
|
||||
All SPI flash APIs are exclusive to each other by some internal mutex provided by the driver.
|
||||
|
||||
When :ref:`CONFIG_SPI_FLASH_AUTO_SUSPEND` is enabled, these APIs will not disable the caches. The hardware will handle the arbitration between them.
|
||||
For all SPI1 operations (read/write), caches are disabled during these operations by default. Most tasks will be disabled, and access to Flash/PSRAM is forbidden. See :ref:`cache_disabled` for more details.
|
||||
|
||||
.. only:: SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
.. note::
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND or SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
When :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` is enabled, these APIs will not disable the caches.
|
||||
Some options help reduce the impact of cache disabling. The impact of write operations differs between modes.
|
||||
|
||||
.. only:: SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
- **XIP from PSRAM**: In this mode, all segments that were previously executed from Flash are loaded and executed from PSRAM instead. As a result, the cache can remain enabled while the flash is being erased or written, and code execution is not affected by write operations in most cases. See :ref:`xip_from_psram` for more details.
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
|
||||
|
||||
- **Auto Suspend**: In this mode, when cache access to flash misses during flash erase/write operations, it is allowed to suspend the flash writing to read from it transparently with some latency. As a result, caches are kept enabled and code execution won't be affected so much during writing operations.
|
||||
|
||||
This is an optional feature that depends on special SPI Flash models, hence disabled by default. See :doc:`spi_flash_optional_feature` and :ref:`auto-suspend` for more details.
|
||||
|
||||
|
||||
See :ref:`esp_flash_os_func` and :ref:`spi_bus_lock` for the detailed information of software implementation.
|
||||
|
||||
|
||||
.. _cache_disabled:
|
||||
|
||||
Cache Disabled (Default)
|
||||
------------------------
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
Caches are disabled during SPI1 operations. All SPI1 operations will automatically and transparently disable the caches.
|
||||
|
||||
.. only:: not esp32
|
||||
|
||||
By default, caches are disabled during SPI1 operations (read/write). All SPI1 operations will automatically and transparently disable the caches.
|
||||
|
||||
.. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES
|
||||
|
||||
The way that these APIs disable the caches suspends all the other tasks. Besides, all non-IRAM-safe interrupts will be disabled. The other core will be polling in a busy loop. These will be restored until the Flash operation completes.
|
||||
When the caches are disabled, all non-IRAM-safe interrupts will be disabled, and all other tasks are suspended. The other core will be polling in a busy loop. Only IRAM-safe interrupt handlers will be executed. These will be restored when the Flash operation completes.
|
||||
|
||||
.. only:: not SOC_HP_CPU_HAS_MULTIPLE_CORES
|
||||
|
||||
The way that these APIs disable the caches also disables non-IRAM-safe interrupts. These will be restored until the Flash operation completes.
|
||||
When the caches are disabled, all non-IRAM-safe interrupts will be disabled, and all other tasks are suspended. Only IRAM-safe interrupt handlers will be executed. These will be restored when the Flash operation completes.
|
||||
|
||||
See also :ref:`esp_flash_os_func` and :ref:`spi_bus_lock`.
|
||||
|
||||
There are no such constraints and impacts for flash chips on other SPI buses than SPI0/1.
|
||||
|
||||
For differences between internal RAM (e.g., IRAM, DRAM) and flash cache, please refer to the :ref:`application memory layout <memory-layout>` documentation.
|
||||
See :ref:`iram-safe-interrupt-handlers` for information on how to prevent an interrupt handler from being disabled when the cache is disabled.
|
||||
|
||||
When the cache is disabled, all CPUs should execute code and access data only from internal RAM. For differences between internal RAM (e.g., IRAM, DRAM) and flash cache, please refer to the :ref:`application memory layout <memory-layout>` documentation.
|
||||
|
||||
.. _iram-safe-interrupt-handlers:
|
||||
|
||||
@@ -66,7 +95,7 @@ For interrupt handlers which need to execute when the cache is disabled (e.g., f
|
||||
|
||||
You must ensure that all data and functions accessed by these interrupt handlers, including the ones that handlers call, are located in IRAM or DRAM. See :ref:`how-to-place-code-in-iram`.
|
||||
|
||||
If a function or symbol is not correctly put into IRAM/DRAM, and the interrupt handler reads from the flash cache during a flash operation, it will cause a crash due to Illegal Instruction exception (for code which should be in IRAM) or garbage data to be read (for constant data which should be in DRAM).
|
||||
If a function or symbol is not correctly put into IRAM/DRAM, and the interrupt handler reads from the flash cache during a flash operation, it will cause a crash. This may be due to an Illegal Instruction exception (for code which should be in IRAM) or garbage data being read (for constant data which should be in DRAM).
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -75,15 +104,16 @@ If a function or symbol is not correctly put into IRAM/DRAM, and the interrupt h
|
||||
Non-IRAM-Safe Interrupt Handlers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If the ``ESP_INTR_FLAG_IRAM`` flag is not set when registering, the interrupt handler will not get executed when the caches are disabled. Once the caches are restored, the non-IRAM-safe interrupts will be re-enabled. After this moment, the interrupt handler will run normally again. This means that as long as caches are disabled, users will not see the corresponding hardware event happening.
|
||||
If the ``ESP_INTR_FLAG_IRAM`` flag is not set when registering, the interrupt handler will not be executed when the caches are disabled. Once the caches are restored, the non-IRAM-safe interrupts will be re-enabled. After this moment, the interrupt handler will run normally again. This means that as long as caches are disabled, the corresponding hardware events will not occur.
|
||||
|
||||
.. only:: SOC_DMA_CAN_ACCESS_FLASH
|
||||
|
||||
When DMA Read Data from Flash
|
||||
-----------------------------
|
||||
|
||||
When DMA is reading data from Flash, erase/write operations from SPI1 take higher priority in hardware, resulting in unpredictable data read by DMA if auto-suspend is not enabled. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM.
|
||||
The Flash device doesn't allow reading while it is being erased/programmed, even when the data is not in the region being erased/programmed.
|
||||
|
||||
When the flash is being erased/programmed, the Flash data read by DMA is unpredictable. It is recommended to stop DMA access to Flash before erasing or writing to it. If DMA cannot be stopped (for example, the LCD needs to continuously refresh image data stored in Flash), it is advisable to copy such data to PSRAM or internal SRAM.
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
|
||||
|
||||
@@ -92,3 +122,4 @@ If the ``ESP_INTR_FLAG_IRAM`` flag is not set when registering, the interrupt ha
|
||||
.. only:: SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
.. include:: xip_from_psram.inc
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ The support for ESP32-P4 may be added in the future.
|
||||
|
||||
List of flash chips that support this feature:
|
||||
|
||||
1. XM25QxxC series
|
||||
1. XM25xxD series
|
||||
2. GD25QxxE series
|
||||
3. FM25Q32
|
||||
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
.. _xip_from_psram:
|
||||
|
||||
XIP from PSRAM Feature
|
||||
----------------------
|
||||
Executing Code from PSRAM
|
||||
-------------------------
|
||||
|
||||
If :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` is enabled, the flash ``.text`` sections (used for instructions) and the flash ``.rodata`` sections (used for read only data) will be placed in PSRAM.
|
||||
Select :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` config to enable this mode. In this mode, code is executed from PSRAM, and the cache will not be disabled during write APIs in most cases.
|
||||
|
||||
The corresponding virtual memory range will be mapped to PSRAM.
|
||||
In this mode, the flash ``.text`` sections (used for instructions) and the flash ``.rodata`` sections (used for read-only data) will be loaded into PSRAM at startup. The corresponding virtual addresses will be mapped to PSRAM. You do not need to ensure that code and data executed while the flash is being erased or programmed reside in IRAM.
|
||||
|
||||
If both of the above options are enabled, the Cache won't be disabled during an SPI1 Flash operation. You don't need to make sure ISRs, ISR callbacks and involved data are placed in internal RAM.
|
||||
Exception: Cache-Mapped Regions in Flash
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Due to the restriction from SPI Nor Flash parts, access to cache mapped regions in flash (mapped via APIs like spi_flash_mmap) is still not allowed while the flash is being erased/written, regardless of whether the erase/write region and the mapped region overlap. In this case, cache should still be disabled to prevent reading corrupted data from the cache.
|
||||
|
||||
To prevent cache disabling, a lock is implemented inside the SPI Flash driver to ensure mutual exclusion between cache mapping and flash writing, and most ESP-IDF APIs that perform flash mapping use this flag. If mmap-like APIs are called by yourself, you can specify this flag :cpp:enumerator:`SPI_FLASH_MMAP_FLAG_BLOCKS_WRITE` to prevent cache disabling. You cannot use this flag in a task that uses ``esp_flash_erase_*`` or ``esp_flash_write`` between ``spi_flash_mmap`` and ``spi_flash_munmap`` (regardless of whether the write region and mapped region overlap), otherwise it will cause a deadlock. See :ref:`blocks_write_flag` for more details about the flag.
|
||||
|
||||
If mmap-like APIs are called without this flag, the cache will still be disabled when flash erasing or writing happens.
|
||||
|
||||
@@ -172,6 +172,31 @@ flash 在 {IDF_TARGET_CACHE_SIZE} 页进行映射。内存映射硬件既可将
|
||||
|
||||
由于 mmap 是由 cache 支持的,因此,mmap 也仅能用在主 flash 上。
|
||||
|
||||
.. only:: not esp32
|
||||
|
||||
.. _blocks_write_flag:
|
||||
|
||||
关于 :cpp:enumerator:`SPI_FLASH_MMAP_FLAG_BLOCKS_WRITE` 标志
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
当缓存映射存在时发生 flash 擦除/写入,通常会导致某些缓存区域被无效化并重新加载。为提高性能,在确定以下条件时,建议指定此标志:
|
||||
|
||||
1. 此映射将在短时间内结束,且
|
||||
2. 在映射结束之前,不需要擦除或写入 flash。
|
||||
|
||||
此标志将阻止所有写入,直到对应的 munmap 被调用。大多数依赖于 flash 映射的 ESP-IDF API 内部使用此标志。
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND or SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
此标志还有助于在使用以下模式时防止缓存被禁用。有关更多详细信息,请参阅相应文档。
|
||||
|
||||
.. list::
|
||||
|
||||
:SOC_SPIRAM_XIP_SUPPORTED: - :ref:`xip_from_psram`
|
||||
:SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND: - :ref:`auto-suspend`
|
||||
|
||||
此标志通过 SPI Flash 驱动程序中的锁来实现。当调用带有此标志的 :cpp:func:`spi_flash_mmap` (或类似 mmap 的 API)时获取锁,直到对应的 unmap 被调用时释放。内部有一个引用计数器,允许对 flash 进行并发映射。只有在最后一个带有此标志的 flash 映射被撤销(计数器等于 0)后,flash 擦除/写入 API 才能开始执行。
|
||||
|
||||
SPI flash 实现
|
||||
--------------
|
||||
|
||||
|
||||
@@ -1,60 +1,90 @@
|
||||
.. _concurrency-constraints-flash:
|
||||
|
||||
SPI1 flash 并发约束
|
||||
=========================================
|
||||
SPI0/1 上 Flash 的并发约束
|
||||
===========================================
|
||||
|
||||
:link_to_translation:`en:[English]`
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
指令/数据 cache(用以执行固件)与 SPI1 外设(由像 SPI flash 驱动一样的驱动程序控制)共享 SPI0/1 总线。因此,SPI1 外设上的操作会对整个系统造成显著的影响。这类操作包括调用 SPI flash API 或者 SPI1 总线上的其他驱动、任何 flash 操作(如读取、写入、擦除)或是由其他用户定义的 SPI 操作(对主 flash 或是其他 SPI 从机)。
|
||||
SPI0/1 总线在缓存和 SPI1 外设(由包括此 SPI Flash 驱动在内的驱动程序控制)之间共享。对 SPI1 的操作可能会对缓存以及整个系统造成重大影响。连接到其他 SPI 总线的 flash 芯片没有此类约束和影响,不在本文档的讨论范围中。
|
||||
|
||||
.. only:: not (esp32c3 or SOC_SPIRAM_XIP_SUPPORTED)
|
||||
SPI0/1 总线上可能发生三种活动:
|
||||
|
||||
在 {IDF_TARGET_NAME} 上,flash 读取/写入/擦除时,必须禁用 cache。
|
||||
- Flash 写入操作(通过 SPI1)。例如,擦除、页面编程或状态寄存器写入命令(例如,``SE``、``PP`` 和 ``WRSR``)。在这些命令期间,flash 处于不可读状态。CPU 和缓存必须等待直到写入命令完成。以下 API 可以触发写入命令:
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
|
||||
- 调用非加密 SPI flash 写入 API(:cpp:func:`esp_flash_write`、:cpp:func:`esp_flash_erase_region` 等)
|
||||
- 调用 :cpp:func:`esp_flash_write_encrypted`
|
||||
|
||||
在 {IDF_TARGET_NAME} 上,配置选项 :ref:`CONFIG_SPI_FLASH_AUTO_SUSPEND` 允许 flash/PSRAM 的 cache 访问和 SPI1 的操作并发执行。该选项是可选的,依赖于特定的 SPI Flash 型号,因此默认是关闭的。请参阅 :ref:`auto-suspend`,查看详细信息。
|
||||
- 短操作(通过 SPI1,包括非写入 flash 命令)。以下 API 可以触发短操作:
|
||||
|
||||
禁用该选项时,在读取/写入/擦除 flash 期间,必须禁用 cache。使用驱动访问 SPI1 的相关约束参见 :ref:`impact_disabled_cache`。这些约束会带来更多的 IRAM/DRAM 消耗。
|
||||
.. list::
|
||||
|
||||
.. only:: SOC_SPIRAM_XIP_SUPPORTED
|
||||
- 调用非加密 SPI flash 读取 API(:cpp:func:`esp_flash_read` 等)
|
||||
:esp32: - 或 SPI1 总线上的其他驱动程序用于用户定义的 SPI 操作(启用实验性功能 :ref:`CONFIG_SPI_FLASH_SHARE_SPI1_BUS`)
|
||||
|
||||
在 {IDF_TARGET_NAME} 上,启用配置选项 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` (默认禁用)后将允许 flash/PSRAM 的 cache 访问和 SPI1 的操作并发执行。请参阅 :ref:`xip_from_psram`,查看详细信息。
|
||||
- 缓存读取(通过 SPI0)。以下 API 和操作可以触发缓存读取:
|
||||
|
||||
禁用该选项时,在读取/写入/擦除 flash 期间,必须禁用 cache。使用驱动访问 SPI1 的相关约束参见 :ref:`impact_disabled_cache`。这些约束会带来更多的 IRAM/DRAM 消耗。
|
||||
- 从 SPI Flash 或 PSRAM 执行代码
|
||||
- 从 SPI Flash 或 PSRAM 获取 .data/.rodata/.bss 段的静态数据
|
||||
- 通过堆或 `esp_himem` 对 PSRAM 的所有其他读/写操作
|
||||
- 从映射到 SPI Flash 的区域读取,包括:
|
||||
|
||||
.. _impact_disabled_cache:
|
||||
- 类似 mmap 的函数::cpp:func:`spi_flash_mmap`、:cpp:func:`spi_flash_mmap_pages`、:cpp:func:`esp_mmu_map`、:cpp:func:`bootloader_mmap` 和 :cpp:func:`esp_partition_mmap`。
|
||||
- 依赖 :cpp:func:`spi_flash_mmap` 的函数::cpp:func:`esp_partition_find`、:cpp:func:`esp_partition_register_external`。
|
||||
- 加密 flash 读/写 API::cpp:func:`esp_flash_read_encrypted` 和 :cpp:func:`esp_flash_write_encrypted` (在 esp32 上,或用于数据验证)。
|
||||
|
||||
禁用 cache 时
|
||||
----------------------------
|
||||
.. only:: esp32
|
||||
|
||||
此时,在 flash 擦写操作中,所有的 CPU 都只能执行 IRAM 中的代码,而且必须从 DRAM 中读取数据。如果使用本文档中的 API 函数,上述限制将自动生效且透明(无需额外关注),但这些限制可能会影响系统中的其他任务的性能。
|
||||
在所有 SPI1 操作期间缓存会被禁用,因此无法访问 Flash/PSRAM,大多数任务将被禁用。有关更多详细信息,请参阅 :ref:`cache_disabled`。
|
||||
|
||||
.. only:: esp32c3
|
||||
.. only:: not esp32
|
||||
|
||||
.. note::
|
||||
所有 SPI flash API 通过驱动程序提供的某些内部互斥锁实现互斥访问。
|
||||
|
||||
启用 :ref:`CONFIG_SPI_FLASH_AUTO_SUSPEND` 时,不会禁用 cache,其中的操作将通过硬件仲裁器来协调。
|
||||
对于所有 SPI1 操作(读/写),默认情况下在这些操作期间缓存会被禁用,因此无法访问 Flash/PSRAM,大多数任务将被禁用。有关更多详细信息,请参阅 :ref:`cache_disabled`。
|
||||
|
||||
.. only:: SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
.. note::
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND or SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
启用 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` 选项后,不会禁用 cache。
|
||||
有一些选项可以帮助减轻缓存禁用的影响。写入操作的影响在不同模式下是不同的。
|
||||
|
||||
.. only:: SOC_SPIRAM_XIP_SUPPORTED
|
||||
|
||||
- **XIP from PSRAM**:在此模式下,所有过去从 Flash 执行的段都改为从 PSRAM 加载和执行。因此,缓存能在 flash 擦除/写入期间保持启用状态,代码执行在大多数情况下不会受到写入操作的影响。有关更多详细信息,请参阅 :ref:`xip_from_psram`。
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
|
||||
|
||||
- **Auto Suspend**:在此模式下,当 flash 区域发生缓存未命中时,允许暂停 flash 写入以透明地从中读取,但会有一些延迟。因此,缓存保持启用状态,代码在写入操作期间影响不会很大。
|
||||
|
||||
这是一个可选功能,依赖于特殊的 SPI Flash 型号,因此默认禁用。有关更多详细信息,请参阅 :doc:`spi_flash_optional_feature` 和 :ref:`auto-suspend`。
|
||||
|
||||
|
||||
有关软件实现的详细信息,请参阅 :ref:`esp_flash_os_func` 和 :ref:`spi_bus_lock`。
|
||||
|
||||
|
||||
.. _cache_disabled:
|
||||
|
||||
缓存禁用(默认)
|
||||
------------------------
|
||||
|
||||
.. only:: esp32
|
||||
|
||||
在 SPI1 操作期间缓存会被禁用。所有 SPI1 操作将自动透明地禁用缓存。
|
||||
|
||||
.. only:: not esp32
|
||||
|
||||
默认情况下,在 SPI1 操作期间缓存会被禁用。所有 SPI1 操作将自动透明地禁用缓存。
|
||||
|
||||
.. only:: SOC_HP_CPU_HAS_MULTIPLE_CORES
|
||||
|
||||
为避免意外读取 flash cache,一个 CPU 在启动 flash 写入或擦除操作时,另一个 CPU 将阻塞。在 flash 操作完成前,会禁用所有在 CPU 上非 IRAM 安全的中断。
|
||||
当禁用缓存时,所有非 IRAM 安全的中断将被禁用,所有其他任务将被暂停。另一个核心将在一个忙循环中空转。只有 IRAM 安全的中断处理程序将被执行。这些将在 Flash 操作完成时恢复。
|
||||
|
||||
.. only:: not SOC_HP_CPU_HAS_MULTIPLE_CORES
|
||||
|
||||
为避免意外读取 flash cache,在 flash 操作完成前,所有 CPU 上,会禁用所有在 CPU 上非 IRAM 安全的中断。
|
||||
当禁用缓存时,所有非 IRAM 安全的中断将被禁用,所有其他任务将被暂停。只有 IRAM 安全的中断处理程序将被执行。这些将在 Flash 操作完成时恢复。
|
||||
|
||||
另请参阅 :ref:`esp_flash_os_func` 和 :ref:`spi_bus_lock`。
|
||||
有关如何在禁用缓存时防止中断处理程序被禁用的信息,请参阅 :ref:`iram-safe-interrupt-handlers`。
|
||||
|
||||
除 SPI0/1 以外,SPI 总线上的其他 flash 芯片则不受这种限制。
|
||||
|
||||
请参阅 :ref:`应用程序内存分布 <memory-layout>`,查看内部 RAM(如 IRAM、DRAM)和 flash cache 的区别。
|
||||
当禁用缓存时,所有 CPU 应该只从内部 RAM 执行代码和访问数据。有关内部 RAM(例如,IRAM、DRAM)和 flash 缓存之间的差异,请参阅 :ref:`应用程序内存布局 <memory-layout>` 文档。
|
||||
|
||||
|
||||
.. _iram-safe-interrupt-handlers:
|
||||
@@ -79,10 +109,12 @@ IRAM 安全中断处理程序
|
||||
|
||||
.. only:: SOC_DMA_CAN_ACCESS_FLASH
|
||||
|
||||
当 DMA 也可以访问 Flash 中的数据时
|
||||
----------------------------------
|
||||
当 DMA 从 Flash 读取数据时
|
||||
-----------------------------
|
||||
|
||||
当 DMA 正在从 Flash 中读取数据时,来自 SPI1 的擦/写操作优先级会更高,如果 Flash 的 auto-suspend 功能没有开启,将会导致 DMA 读到错误的数据。建议在擦写 Flash 之前先停止 DMA 对 Flash 的访问。如果 DMA 不可以停止,比如 LCD 需要持续刷新保存在 Flash 中的图像数据,建议将此类数据拷贝到 PSRAM 或者内部的 SRAM 中。
|
||||
Flash 器件不允许在擦除/编程时读取,即使数据不在正在被擦除/编程的区域中。
|
||||
|
||||
当 flash 正在被擦除/编程时,DMA 读取的 Flash 数据是不可预测的。建议在擦除或写入之前停止 DMA 对 Flash 的访问。如果无法停止 DMA(例如,LCD 需要持续刷新存储在 Flash 中的图像数据),建议将此类数据复制到 PSRAM 或内部 SRAM。
|
||||
|
||||
|
||||
.. only:: SOC_SPI_MEM_SUPPORT_AUTO_SUSPEND
|
||||
|
||||
@@ -40,7 +40,7 @@ flash 的可选功能
|
||||
|
||||
支持此功能的 flash 芯片列表:
|
||||
|
||||
1. XM25QxxC 系列
|
||||
1. XM25xxD 系列
|
||||
2. GD25QxxE 系列
|
||||
3. FM25Q32
|
||||
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
.. _xip_from_psram:
|
||||
|
||||
在 PSRAM 中执行代码
|
||||
从 PSRAM 执行代码功能
|
||||
----------------------
|
||||
|
||||
启用 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` 选项后,flash 中 ``.text`` 部分的数据(用于指令)和 flash 中 ``.rodata`` 部分的数据(用于只读数据)将被放入 PSRAM。
|
||||
选择 :ref:`CONFIG_SPIRAM_XIP_FROM_PSRAM` 配置以启用此模式。在此模式下,代码从 PSRAM 执行,在大多数情况下,缓存不会在写入 API 期间被禁用。
|
||||
|
||||
相应的虚拟内存地址将被映射到 PSRAM。
|
||||
在此模式下,flash ``.text`` 段(用于指令)和 flash ``.rodata`` 段(用于只读数据)将在启动时加载到 PSRAM。相应的虚拟地址将映射到 PSRAM。您无需确保在 flash 被擦除/编程时执行的代码/数据位于 IRAM 中。
|
||||
|
||||
如果同时启用以上两个选项,则在 SPI1 flash 操作期间 cache 不会被禁用,无需确保 ISR、ISR 回调及相关数据放置在内部 RAM 中。
|
||||
例外:当缓存映射 flash 中的区域时
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
由于 SPI Nor Flash 器件的限制,在 flash 被擦除/写入时,仍然不允许访问 Flash 中的缓存映射区域(通过 spi_flash_mmap 等 API 映射),无论擦写区域和映射区域是否重合。在这种情况下,在擦写 Flash 时仍应禁用缓存以防止从缓存读取错误的数据。
|
||||
|
||||
为了防止缓存禁用,在 SPI Flash 驱动程序中实现了一个锁,以确保缓存映射的存在和 Flash 写入是互斥的,大多数进行了 Flash 映射的 ESP-IDF API 都使用了该标志。如果您自己调用类似 mmap 的 API,可以指定此标志 :cpp:enumerator:`SPI_FLASH_MMAP_FLAG_BLOCKS_WRITE` 以防止缓存禁用。您不能在 ``spi_flash_mmap`` 和 ``spi_flash_munmap`` 之间使用 ``esp_flash_erase_*`` 或者 ``esp_flash_write`` 的任务中使用此标志(无论写入区域和映射区域是否重叠),否则会造成死锁。有关该标志的详细信息,请参阅 :ref:`blocks_write_flag`。
|
||||
|
||||
如果在没有此标志的情况下调用类似 mmap 的 API,当 Flash 发生擦除或者写入时,缓存仍将被禁用。
|
||||
|
||||
Reference in New Issue
Block a user