SPI1 Flash 并发约束

指令/数据 cache (用以执行固件)与 SPI1 外设(由像 SPI Flash 驱动一样的驱动程序控制)共享 SPI0/1 总线。因此,对 SPI1 外设的操作会对整个系统造成显著的影响。这类操作包括调用 SPI Flash API 或者其他 SPI1 总线上的驱动,任何 flash 操作(如读取、写入、擦除)或者其他用户定义的 SPI 操作,无论是对主 flash 或者其他各类的 SPI 从机。

在 ESP32-C3 上,配置选项 CONFIG_SPI_FLASH_AUTO_SUSPEND 允许 Flash 的 cache 访问和 SPI1 的操作存并发地执行。该选项是可选的,依赖于特定的 SPI Flash 型号,因此默认是关闭的。请参阅 当使能 flash 擦除的自动暂停,查看详细信息。

在该选项被禁用的情况下,读取/写入/擦除 flash 时,cache 必须被禁用。使用驱动访问 SPI1 的相关约束参见 当 cache 被禁用时。这些约束会带来更多的 IRAM/DRAM 消耗。

当 cache 被禁用时

此时,在 flash 擦写操作中,所有的 CPU 都只能执行 IRAM 中的代码,而且必须从 DRAM 中读取数据。如果您使用本文档中 API 函数,上述限制将自动生效且透明(无需您额外关注),但这些限制可能会影响系统中的其他任务的性能。

然而,启用 CONFIG_SPI_FLASH_AUTO_SUSPEND 时,cache 不会被禁用,其中的操作将通过硬件来协调。

为避免意外读取 flash cache,在 flash 操作完成前,所有 CPU 上,所有的非 IRAM 安全的中断都会被禁用。

另请参阅 OS 函数SPI 总线锁

除 SPI0/1 以外,SPI 总线上的其它 flash 芯片则不受这种限制。

请参阅 应用程序内存分布,查看内部 RAM(如 IRAM、DRAM)和 flash cache 的区别。

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 被禁用,将不会发生相应的硬件事件。

当使能 flash 擦除的自动暂停

当使能 flash 擦除的自动暂停,访问 SPI1 时(如擦除、写入、读取主 flash ) cache 便无需被禁用。硬件会负责仲裁二者的访问。

当 SPI1 操作较短时(如读取操作), CPU 和 cache 会等待直到 SPI1 的操作结束。然而对于一个擦除操作,自动暂停会发生并打断擦除操作,允许 CPU 能够在有限时间内从 cache 读取数据。

因此,部分的代码及变量便可以放入 flash / PSRAM 而非 IRAM / DRAM ,同时仍然能够在 flash 擦除期间被执行。这样就减少了 IRAM / DRAM 的消耗。

请注意这个功能会带来 flash 暂停及恢复时的额外开销。如果被频繁打断, flash 的擦除时间可能异常的长。为了确保 flash 擦除操作在一个合理的时间内完成,请调整 FreeRTOS 任务优先级,这样仅有那些高于擦除任务优先级的任务,会在擦除进行过程中会被执行。

换句话说,代码可以分为以下三类:

  1. 关键代码:放置在 IRAM / DRAM 中。这类代码通常有较高的性能要求,与 cache / flash / PSRAM 相关,或者被频繁调用。

  2. cache 访问的代码:放置在 flash / PSRAM中。这类代码的性能要求较低,或者较少被调用。他们会在 flash 擦除的时候被执行,带来一定的开销。

  3. 低优先级代码:放置在 flash / PSRAM 中,并且在 flash 擦除的期间被禁止运行。这类代码的任务优先级应被设置的低于擦除任务,从而避免影响 flash 擦除的速度。