Concurrency Constraints for Flash on SPI0/1

[中文]

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.

There are three kinds of activities that can happen on SPI0/1 bus:

All SPI flash APIs are exclusive to each other by some internal mutex provided by the driver.

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 Cache Disabled (Default) for more details.

Some options help reduce the impact of cache disabling. The impact of write operations differs between modes.

  • 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 Executing Code from PSRAM for more details.

See OS Functions and SPI Bus Lock for the detailed information of software implementation.

Cache Disabled (Default)

By default, caches are disabled during SPI1 operations (read/write). All SPI1 operations will automatically and transparently disable the caches.

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 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 application memory layout documentation.

IRAM-Safe Interrupt Handlers

For interrupt handlers which need to execute when the cache is disabled (e.g., for low latency operations), set the ESP_INTR_FLAG_IRAM flag when the interrupt handler is registered.

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

When working with strings in ISRs, it is not advised to use printf and other output functions. For debugging purposes, use ESP_DRAM_LOGE() and similar macros when logging from ISRs. Make sure that both TAG and format string are placed into DRAM in that case.

Non-IRAM-Safe Interrupt Handlers

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.

Executing Code from PSRAM

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

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.

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 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 About the SPI_FLASH_MMAP_FLAG_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.


Was this page helpful?