SPI0/1 上 Flash 的并发约束

[中文]

SPI0/1 总线在缓存和 SPI1 外设(由包括此 SPI Flash 驱动在内的驱动程序控制)之间共享。对 SPI1 的操作可能会对缓存以及整个系统造成重大影响。连接到其他 SPI 总线的 flash 芯片没有此类约束和影响,不在本文档的讨论范围中。

SPI0/1 总线上可能发生三种活动:

所有 SPI flash API 通过驱动程序提供的某些内部互斥锁实现互斥访问。

对于所有 SPI1 操作(读/写),默认情况下在这些操作期间缓存会被禁用,因此无法访问 Flash/PSRAM,大多数任务将被禁用。有关更多详细信息,请参阅 缓存禁用(默认)

有一些选项可以帮助减轻缓存禁用的影响。写入操作的影响在不同模式下是不同的。

  • XIP from PSRAM:在此模式下,所有过去从 Flash 执行的段都改为从 PSRAM 加载和执行。因此,缓存能在 flash 擦除/写入期间保持启用状态,代码执行在大多数情况下不会受到写入操作的影响。有关更多详细信息,请参阅 从 PSRAM 执行代码功能

有关软件实现的详细信息,请参阅 OS 函数SPI 总线锁

缓存禁用(默认)

默认情况下,在 SPI1 操作期间缓存会被禁用。所有 SPI1 操作将自动透明地禁用缓存。

当禁用缓存时,所有非 IRAM 安全的中断将被禁用,所有其他任务将被暂停。只有 IRAM 安全的中断处理程序将被执行。这些将在 Flash 操作完成时恢复。

有关如何在禁用缓存时防止中断处理程序被禁用的信息,请参阅 IRAM 安全中断处理程序

当禁用缓存时,所有 CPU 应该只从内部 RAM 执行代码和访问数据。有关内部 RAM(例如,IRAM、DRAM)和 flash 缓存之间的差异,请参阅 应用程序内存布局 文档。

IRAM 安全中断处理程序

如果需要在 flash 操作期间运行中断处理程序(比如低延迟操作),请在 注册中断处理程序 时设置 ESP_INTR_FLAG_IRAM

请确保中断处理程序访问的所有数据和函数(包括其调用的数据和函数)都存储在 IRAM 或 DRAM 中。参见 如何将代码放入 IRAM

在未将函数或符号正确放入 IRAM/DRAM 的情况下,在 flash 操作期间,中断处理程序从 flash cache 中读取数据时,会导致程序崩溃。这可能是因为代码未正确放入 IRAM,产生了非法指令异常,也可能是因为常数未正确放入 DRAM,读取到了垃圾数据。

备注

在 ISRs 中处理字符串时,不建议使用 printf 和其他输出函数。为了方便调试,在从 ISRs 中获取数据时,请使用 ESP_DRAM_LOGE() 和类似的宏。请确保 TAG 和格式字符串都放置于 DRAM 中。

非 IRAM 安全中断处理程序

如果在注册时没有设置 ESP_INTR_FLAG_IRAM 标志,当禁用 cache 时,将不会执行中断处理程序。一旦 cache 恢复,非 IRAM 安全的中断将重新启用,中断处理程序随即再次正常运行。这意味着,只要禁用了 cache,就不会发生相应的硬件事件。

从 PSRAM 执行代码功能

选择 CONFIG_SPIRAM_XIP_FROM_PSRAM 配置以启用此模式。在此模式下,代码从 PSRAM 执行,在大多数情况下,缓存不会在写入 API 期间被禁用。

在此模式下,flash .text 段(用于指令)和 flash .rodata 段(用于只读数据)将在启动时加载到 PSRAM。相应的虚拟地址将映射到 PSRAM。您无需确保在 flash 被擦除/编程时执行的代码/数据位于 IRAM 中。

例外:当缓存映射 flash 中的区域时

由于 SPI Nor Flash 器件的限制,在 flash 被擦除/写入时,仍然不允许访问 Flash 中的缓存映射区域(通过 spi_flash_mmap 等 API 映射),无论擦写区域和映射区域是否重合。在这种情况下,在擦写 Flash 时仍应禁用缓存以防止从缓存读取错误的数据。

为了防止缓存禁用,在 SPI Flash 驱动程序中实现了一个锁,以确保缓存映射的存在和 Flash 写入是互斥的,大多数进行了 Flash 映射的 ESP-IDF API 都使用了该标志。如果您自己调用类似 mmap 的 API,可以指定此标志 SPI_FLASH_MMAP_FLAG_BLOCKS_WRITE 以防止缓存禁用。您不能在 spi_flash_mmapspi_flash_munmap 之间使用 esp_flash_erase_* 或者 esp_flash_write 的任务中使用此标志(无论写入区域和映射区域是否重叠),否则会造成死锁。有关该标志的详细信息,请参阅 关于 SPI_FLASH_MMAP_FLAG_BLOCKS_WRITE 标志

如果在没有此标志的情况下调用类似 mmap 的 API,当 Flash 发生擦除或者写入时,缓存仍将被禁用。


此文档对您有帮助吗?