SPI0/1 上 Flash 的并发约束
SPI0/1 总线在缓存和 SPI1 外设(由包括此 SPI Flash 驱动在内的驱动程序控制)之间共享。对 SPI1 的操作可能会对缓存以及整个系统造成重大影响。连接到其他 SPI 总线的 flash 芯片没有此类约束和影响,不在本文档的讨论范围中。
SPI0/1 总线上可能发生三种活动:
Flash 写入操作(通过 SPI1)。例如,擦除、页面编程或状态寄存器写入命令(例如,
SE、PP和WRSR)。在这些命令期间,flash 处于不可读状态。CPU 和缓存必须等待直到写入命令完成。以下 API 可以触发写入命令:调用非加密 SPI flash 写入 API(
esp_flash_write()、esp_flash_erase_region()等)
短操作(通过 SPI1,包括非写入 flash 命令)。以下 API 可以触发短操作:
调用非加密 SPI flash 读取 API(
esp_flash_read()等)或 SPI1 总线上的其他驱动程序用于用户定义的 SPI 操作(启用实验性功能 CONFIG_SPI_FLASH_SHARE_SPI1_BUS)
缓存读取(通过 SPI0)。以下 API 和操作可以触发缓存读取:
从 SPI Flash 或 PSRAM 执行代码
从 SPI Flash 或 PSRAM 获取 .data/.rodata/.bss 段的静态数据
通过堆或 esp_himem 对 PSRAM 的所有其他读/写操作
从映射到 SPI Flash 的区域读取,包括:
类似 mmap 的函数:
spi_flash_mmap()、spi_flash_mmap_pages()、esp_mmu_map()、bootloader_mmap()和esp_partition_mmap()。依赖
spi_flash_mmap()的函数:esp_partition_find()、esp_partition_register_external()。加密 flash 读/写 API:
esp_flash_read_encrypted()和esp_flash_write_encrypted()(在 esp32 上,或用于数据验证)。
在所有 SPI1 操作期间缓存会被禁用,因此无法访问 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,就不会发生相应的硬件事件。