Concurrency Constraints for flash on SPI1

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.

On ESP32-C3, the config option CONFIG_SPI_FLASH_AUTO_SUSPEND (enabled by default) allows the cache to read flash concurrently with SPI1 operations. See Flash Auto Suspend Feature for more details.

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 When the caches are disabled. This constraints will cause more IRAM/DRAM usages.

When the caches are disabled

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.

However, when CONFIG_SPI_FLASH_AUTO_SUSPEND is enabled, these APIs won’t disable the caches. The hardware will handle the arbitration between them.

The way that these APIs disable the caches will also disable non-IRAM-safe interrupts. These will be restored until the Flash operation completes.

See also OS Functions and 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 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 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).

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 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 won’t see the corresponding hardware event happening.

Flash Auto Suspend Feature

Important

  1. The flash chip you are using should have a suspend/resume feature.

  2. The MSPI hardware should support the auto-suspend feature (hardware can send suspend command automatically).

If you use suspend feature on an unsupported chip, it may cause a severe crash. Therefore, we strongly suggest you reading the flash chip datasheets first. Ensure the flash chip satisfies the following conditions at minimum.

  1. SUS bit in status registers should in SR2 bit7 (or SR bit15)(This is caused by the restriction of out software implementation).

  2. Suspend command is 75H, resume command is 7AH(This is caused by the restriction of out software implementation).

  3. When the flash is successfully suspended, all address of the flash, except from the section/block being erased, can be read correctly. And resume can be sent immediately at this state.

  4. When the flash is successfully resumed, another suspend can be sent immediately at this state.

When CONFIG_SPI_FLASH_AUTO_SUSPEND is enabled, the caches will be kept enabled (they would be disabled if CONFIG_SPI_FLASH_AUTO_SUSPEND is disabled). The hardware handles the arbitration between SPI0 and SPI1. If SPI1 operation is short (like reading operation), the CPU and the cache will wait until the SPI1 operation is done. However, if it is erasing, page programming or status register writing (e.g. SE, PP and WRSR), an auto suspend will happen, interrupting the ongoing flash operation, making the CPU able to read from cache and flash in limited time.

This way some code/variables can be put into the flash/psram instead of IRAM/DRAM, while still able to be executed during flash erasing. This reduces the some usage of IRAM/DRAM.

Please note this feature has the overhead of the flash suspend/resume. The flash erasing can be extremely long if the erasing is interrupted too often. Use FreeRTOS task priorities to ensure that only real-time critical tasks are executed at higher priority than flash erase, to allow the flash erase to complete in reasonable time.

In other words, there are three kinds of code:

  1. Critical code: inside IRAM/DRAM. This kind of code usually has high performance requirements, related to cache/flash/psram, or called very often.

  2. Cached code: inside flash/psram. This kind of code has lower performance requirements or called less often. They will execute during erasing, with some overhead.

  3. Low priority code: inside flash/psram and disabled during erasing. This kind of code should be forbidden from executed to avoid affecting the flash erasing, by setting a lower task priority than the erasing task.

Regarding the flash suspend feature usage, and corresponding response time delay, please also see this example system/flash_suspend .