docs: updated CN translation for !16452 and !16658

This commit is contained in:
Shang Zhou
2022-05-20 03:57:51 +08:00
parent 8429ec2553
commit ed1bf1d056
4 changed files with 89 additions and 85 deletions
+35 -23
View File
@@ -5,7 +5,7 @@ SPI Flash API
概述
--------
Spi_flash 组件提供外部 flash 数据读取、写入、擦除和内存映射相关的 API 函数,同时也提供了更高层级的面向分区的 API 函数(定义在 :doc:`分区表 </api-guides/partition-tables>` 中)。
spi_flash 组件提供外部 flash 数据读取、写入、擦除和内存映射相关的 API 函数,同时也提供了更高层级的面向分区的 API 函数(定义在 :doc:`分区表 </api-guides/partition-tables>` 中)。
与 ESP-IDF V4.0 之前的 API 不同,这一版 `esp_flash_*` API 功能并不局限于主 SPI flash 芯片(即运行程序的 SPI flash 芯片)。使用不同的芯片指针,您可以访问连接到 SPI0/1 或 SPI2 总线的外部 flash 芯片。
@@ -17,20 +17,20 @@ Spi_flash 组件提供外部 flash 数据读取、写入、擦除和内存映射
.. note::
ESP-IDF V4.0 之后的 flash API 不再是原子的。因此,如果 flash 操作地址有重叠,且写操作与读操作同时执行,读操作可能会返回一部分写入之前的数据和一部分写入之后的数据。
ESP-IDF V4.0 之后的 flash API 不再是 *原子* 的。因此,如果读操作执行过程中发生写操作,且读操作和写操作的 flash 地址出现重叠,读操作返回的数据可能会包含旧数据和新数据 (新数据为写操作更新产生的数据)
Kconfig 选项 :ref:`CONFIG_SPI_FLASH_USE_LEGACY_IMPL` 可将 ``spi_flash_*`` 函数切换至 ESP-IDF V4.0 之前的实现。但是,如果同时使用新旧 API,代码量可能会增多。
便未启用 :ref:`CONFIG_SPI_FLASH_USE_LEGACY_IMPL`,加密读取和加密写入操作也均使用旧实现。因此,仅有主 flash 芯片支持加密操作,外接(经 SPI1 使用其他不同片选访问,或经其它 SPI 总线访问)的 flash 芯片则不支持加密操作。仅有主 flash 支持从 cache 当中读取,因为这是由硬件决定的
使未启用 :ref:`CONFIG_SPI_FLASH_USE_LEGACY_IMPL`,加密读取和加密写入操作也均使用旧实现。因此,仅有主 flash 芯片支持加密操作,外接(经 SPI1 使用其他不同片选访问,或经其它 SPI 总线访问)的 flash 芯片则不支持加密操作。硬件的限制也决定了仅有主 flash 支持从 cache 当中读取。
Flash 特性支持情况
Flash 功能支持情况
-----------------------------------
支持的 Flash 列表
^^^^^^^^^^^^^^^^^^^^^
不同厂家的 flash 特性有不同的操作方式,因此需要特殊的驱动支持。当前驱动支持大多数厂家 Flash 24 位地址范围内的快速/慢速读,以及二线模式 (DIO / DOUT),因为他们不需要任何厂家的自定义命令。
不同厂家的 flash 特性有不同的操作方式,因此需要特殊的驱动支持。当前驱动支持大多数厂家 flash 24 位地址范围内的快速/慢速读,以及二线模式 (DIO/DOUT),因为他们不需要任何厂家的自定义命令。
当前驱动支持以下厂家/型号的 flash 的四线模式 (QIO/QOUT)
@@ -62,7 +62,7 @@ Flash 可选的功能
- 高性能 (HPM) 模式 - 表示 flash 工作频率大于 80MHz 。
- flash 的私有ID (unique ID) - 表示 flash 支持它自己的 64-bits 独一无二的 ID 。
- flash 的私有ID (unique ID) - 表示 flash 支持它自己的 64-bits 独 ID 。
.. only:: esp32c3
@@ -70,7 +70,7 @@ Flash 可选的功能
如果您想使用这些功能,则需保证 {IDF_TARGET_NAME} 支持这些功能,且产品里所使用的 flash 芯片也要支持这些功能。请参阅 :doc:`spi_flash_optional_feature`,查看更多信息。
如果有需要,也可以自定义 flash 芯片驱动,参见 :doc:`spi_flash_override_driver`
也可以自定义 flash 芯片驱动。请参阅 :doc:`spi_flash_override_driver`,查看详细信息
.. toctree::
:hidden:
@@ -80,15 +80,15 @@ Flash 可选的功能
初始化 Flash 设备
---------------------------
在使用 ``esp_flash_*`` API 之前,您需要在 SPI 总线上初始化芯片
在使用 ``esp_flash_*`` API 之前,您需要在 SPI 总线上初始化芯片,步骤如下:
1. 调用 :cpp:func:`spi_bus_initialize` 初始化 SPI 总线此函数将初始化总线上设备间共享的资源,如 I/O、DMA中断等。
1. 调用 :cpp:func:`spi_bus_initialize` 初始化 SPI 总线此函数将初始化总线上设备间共享的资源,如 I/O、DMA中断等。
2. 调用 :cpp:func:`spi_bus_add_flash_device` 将 flash 设备连接到总线上。然后分配内存,填充 ``esp_flash_t`` 结构体,同时初始化 CS I/O。
3. 调用 :cpp:func:`esp_flash_init` 与芯片进行通信。后续操作会依据芯片类型不同而有差异。
.. note:: 当前,多个 flash 芯片连接到同一总线。但尚不支持在同一个 SPI 总线上使用 ``esp_flash_*````spi_device_*`` 设备。
.. note:: 当前,已支持多个 flash 芯片连接到同一总线。
SPI Flash 访问 API
--------------------
@@ -99,16 +99,16 @@ SPI Flash 访问 API
- :cpp:func:`esp_flash_write`:将数据从 RAM 写入到 flash;
- :cpp:func:`esp_flash_erase_region`:擦除 flash 中指定区域的数据;
- :cpp:func:`esp_flash_erase_chip`:擦除整个 flash
- :cpp:func:`spi_flash_get_chip_size`:返回 menuconfig 中设置的 flash 芯片容量(以字节为单位)。
- :cpp:func:`esp_flash_get_chip_size`:返回 menuconfig 中设置的 flash 芯片容量(以字节为单位)。
一般来说,请尽量避免对主 SPI flash 芯片直接使用原始 SPI flash 函数如需对主 SPI flash 芯片进行操作,请使用 :ref:`分区专用函数 <flash-partition-apis>`
一般来说,请尽量避免对主 SPI flash 芯片直接使用原始 SPI flash 函数如需对主 SPI flash 芯片进行操作,请使用 :ref:`分区专用函数 <flash-partition-apis>`
SPI Flash 容量
--------------
SPI flash 容量存储于引导程序镜像头部(烧录偏移量为 0x1000)的一个字段。
SPI flash 容量由引导加载程序镜像头部(烧录偏移量为 0x1000)的一个字段进行配置
默认情况下,引导程序写入 flash 时,esptool.py 将引导程序写入 flash 时,会自动检测 SPI flash 容量,同时使用正确容量更新引导程序的头部。您也可以在工程配置中设置 :ref:`CONFIG_ESPTOOLPY_FLASHSIZE`,生成固定的 flash 容量。
默认情况下,引导程序写入 flash 时,esptool.py 会自动检测 SPI flash 容量,同时使用正确容量更新引导程序的头部。您也可以在工程配置中设置 :envvar:`CONFIG_ESPTOOLPY_FLASHSIZE`,生成固定的 flash 容量。
如需在运行时覆盖已配置的 flash 容量,请配置 ``g_rom_flashchip`` 结构中的 ``chip_size````esp_flash_*`` 函数使用此容量(于软件和 ROM 中)进行边界检查。
@@ -122,19 +122,19 @@ SPI1 Flash 并发约束
.. attention::
指令/数据 cache(用以执行固件)与 SPI1 外设(由像 SPI flash 驱动一样的驱动程序控制)共享 SPI0/1 总线。因此,在 SPI1 总线上调用 SPI flash API(包括访问主 flash)会对整个系统造成显著的影响。更多细节,参见 :doc:`spi_flash_concurrency`
指令/数据 cache(用以执行固件)与 SPI1 外设(由像 SPI flash 驱动一样的驱动程序控制)共享 SPI0/1 总线。因此,在 SPI1 总线上调用 SPI flash API(包括访问主 flash)会对整个系统造成显著的影响。请参阅 :doc:`spi_flash_concurrency`,查看详细信息
.. _flash-partition-apis:
分区表 API
-------------------
ESP-IDF 工程使用分区表保存 SPI flash 各区信息,包括引导程序、各种应用程序二进制文件、数据及文件系统等。请参 :doc:`here </api-guides/partition-tables>`,查看详细信息。
ESP-IDF 工程使用分区表保存 SPI flash 各区信息,包括引导程序、各种应用程序二进制文件、数据及文件系统等。请参 :doc:`分区表 </api-guides/partition-tables>`,查看详细信息。
该组件在 ``esp_partition.h`` 中声明了一些 API 函数,用以枚举在分区表中找到的分区,并对这些分区执行操作:
- :cpp:func:`esp_partition_find`:在分区表中查找特定类型的条目,返回一个不透明迭代器;
- :cpp:func:`esp_partition_get`:返回一个结构,描述给定迭代器的分区;
- :cpp:func:`esp_partition_get`:返回一个结构,描述给定迭代器的分区;
- :cpp:func:`esp_partition_next`:将迭代器移至下一个找到的分区;
- :cpp:func:`esp_partition_iterator_release`:释放 ``esp_partition_find`` 中返回的迭代器;
- :cpp:func:`esp_partition_find_first`:返回描述 ``esp_partition_find`` 中找到的第一个分区的结构;
@@ -156,7 +156,7 @@ SPI Flash 加密
{IDF_TARGET_CACHE_SIZE:default="64 KB"}
{IDF_TARGET_NAME} 内存硬件可以将 flash 部分区域映射到指令地址空间和数据地址空间此映射仅用于读操作不能通过写入 flash 映射的存储区域来改变 flash 中的内容。
{IDF_TARGET_NAME} 内存硬件可以将 flash 部分区域映射到指令地址空间和数据地址空间此映射仅用于读操作不能通过写入 flash 映射的存储区域来改变 flash 中的内容。
Flash 在 {IDF_TARGET_CACHE_SIZE} 页进行映射。内存映射硬件既可将 flash 映射到数据地址空间,也能映射到指令地址空间。请查看技术参考手册,了解内存映射硬件的详细信息及有关限制。
@@ -183,7 +183,7 @@ Flash 在 {IDF_TARGET_CACHE_SIZE} 页进行映射。内存映射硬件既可将
SPI Flash 实现
--------------
``esp_flash_t`` 结构包含芯片数据和该 API 的三个重要部分:
``esp_flash_t`` 结构包含芯片数据和该 API 的三个重要部分:
1. 主机驱动,为访问芯片提供硬件支持;
2. 芯片驱动,为不同芯片提供兼容性服务;
@@ -214,11 +214,11 @@ SPI Flash 实现
OS 函数
^^^^^^^^^^^^
OS 函数层目前提供访问锁和延迟的方法。
OS 函数层目前支持访问锁和延迟的方法。
锁(见 :ref:`spi_bus_lock`)用于解决同一 SPI 总线上的设备访问和 SPI flash 芯片访问之间的冲突。例如:
1. 经 SPI1 总线访问 flash 芯片时,应当禁用 cache(平时用于取代码和 PSRAM 数据)。
1. 经 SPI1 总线访问 flash 芯片时,应当禁用 cache(平时用于取代码和 PSRAM 数据)。
2. 经其他总线访问 flash 芯片时,应当禁用 flash 上 SPI 主驱动器注册的 ISR 以避免冲突。
@@ -228,6 +228,18 @@ OS 函数层目前提供访问锁和延迟的方法。
顶层 API 将芯片驱动和 OS 函数封装成一个完整的组件,并提供参数检查。
使用 OS 函数还可以在一定程度上避免在擦除大块 flash 区域时出现看门狗超时的情况。在这段时间内,CPU 将被 flash 擦除任务占用,从而阻止其他任务的执行,包括为看门狗定时器 (WDT) 供电的空闲任务。若已选中配置选项 :ref:`CONFIG_ESP_TASK_WDT_PANIC`,并且 flash 操作时间长于看门狗的超时时间,系统将重新启动。
不过,由于不同的 flash 芯片擦除时间不同,flash 驱动几乎无法兼容,很难完全规避超时的风险。因此,您需要格外注意这一点。请遵照以下指南:
1. 建议启用 :ref:`CONFIG_SPI_FLASH_YIELD_DURING_ERASE` 选项,允许调度器在擦除 flash 时进行重新调度。此外,还可以使用下列参数。
- 在 menuconfig 中增加 :ref:`CONFIG_SPI_FLASH_ERASE_YIELD_TICKS` 或减少 :ref:`CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS` 的时间。
- 您也可以在 menuconfig 中增加 :ref:`CONFIG_ESP_TASK_WDT_TIMEOUT_S` 的时间以设置更长的看门狗超时周期。然而,看门狗超时周期拉长后,可能无法再检测到以前可检测到的超时。
2. 请注意,在进行长时间的 SPI flash 操作时,启用 :ref:`CONFIG_ESP_TASK_WDT_PANIC` 选项将会在超时时触发恐慌处理程序。不过,启用该选项也可以帮助处理应用程序中的意外异常,您可以根据实际情况决定是否需要启用这个选项。
3. 在开发过程中,请根据项目对擦除 flash 的具体要求和时间限制,谨慎进行 flash 操作。在配置 flash 擦除超时周期时,请在实际产品要求的基础上留出合理的冗余时间,从而提高产品的可靠性。
另请参考
------------
@@ -244,7 +256,7 @@ OS 函数层目前提供访问锁和延迟的方法。
必须确保操作期间,两个 CPU 均未从 flash 运行代码,实现细节如下:
- 单核模式下,SDK 在执行 flash 操作前将禁用中断或调度算法。
- 双核模式下,实现细节较为复杂,SDK 需确保两个 CPU 均未运行 flash 代码。
- 双核模式下,SDK 需确保两个 CPU 均未运行 flash 代码。
如果有 SPI flash API 在 CPU APRO 或 APP)上调用,它使用 ``esp_ipc_call`` API 在 CPU B 上运行 ``spi_flash_op_block_func`` 函数。``esp_ipc_call`` API 会在 CPU B 上唤醒一个高优先级任务,即运行 ``spi_flash_op_block_func`` 函数。运行该函数将禁用 CPU B 上的 cache,并使用 ``s_flash_op_can_start`` 旗帜来标志 cache 已禁用。然后,CPU A 上的任务也会禁用 cache 并继续执行 flash 操作。
@@ -275,4 +287,4 @@ SPI Flash API 参考
Flash 加密 API 参考
-----------------------------
.. include-build-file:: inc/esp_flash_encrypt.inc
.. include-build-file:: inc/esp_flash_encrypt.inc
@@ -7,30 +7,40 @@ SPI1 Flash 并发约束
.. only:: not esp32c3
在 {IDF_TARGET_NAME} 上, flash 读取/写入/擦除时 cache 必须被禁用。
在 {IDF_TARGET_NAME} 上,flash 读取/写入/擦除时 cache 必须被禁用。
.. only:: esp32c3
在 {IDF_TARGET_NAME} 上,默认启用的配置选项 :ref:`CONFIG_SPI_FLASH_AUTO_SUSPEND` 允许 flash / PSRAM 的 cache 访问和 SPI1 的操作存并发地执行。更多详情,参见 :ref:`auto-suspend`
在 {IDF_TARGET_NAME} 上,默认启用的配置选项 :ref:`CONFIG_SPI_FLASH_AUTO_SUSPEND` 允许 flash/PSRAM 的 cache 访问和 SPI1 的操作存并发地执行。请参阅 :ref:`auto-suspend`,查看详细信息
在该选项被禁用的情况下,读取/写入/擦除 flash 时,cache 必须被禁用。使用驱动访问 SPI1 的相关约束参见 :ref:`impact_disabled_cache`。这些约束会带来更多的 IRAM/DRAM 消耗。
然而当该选项被禁用时,读取/写入/擦除 flash 时, cache 必须被禁用。使用驱动访问 SPI1 的相关约束参见 :ref:`impact_disabled_cache` 。这些约束会带来更多的 IRAM / DRAM 消耗。
.. _impact_disabled_cache:
当 cache 被禁用时
----------------------------
这意味着当 flash 擦写操作发生时,所有的 CPU 都只能执行 IRAM 中的代码,而且必须从 DRAM 中读取数据。如果您使用本文档中 API 函数,上述限制将自动生效且透明(无需您额外关注),但这些限制可能会影响系统中的其他任务的性能。
此时,在 flash 擦写操作,所有的 CPU 都只能执行 IRAM 中的代码,而且必须从 DRAM 中读取数据。如果您使用本文档中 API 函数,上述限制将自动生效且透明(无需您额外关注),但这些限制可能会影响系统中的其他任务的性能。
除 SPI0/1 以外的 SPI 总线上的其它 flash 芯片则不受这种限制。
.. only:: esp32c3
请参阅 :ref:`应用程序内存分布 <memory-layout>`,查看 IRAM、DRAM 和 flash cache 的区别
然而,启用 :ref:`CONFIG_SPI_FLASH_AUTO_SUSPEND` 时,cache 不会被禁用,其中的操作将通过硬件来协调
.. only:: not CONFIG_FREERTOS_UNICORE
为避免意外读取 flash cache,一个 CPU 在启动 flash 写入或擦除操作时,另一个 CPU 将阻塞,并且在 flash 操作完成前,所有 CPU 上,所有的非 IRAM 安全的中断都会被禁用。
为避免意外读取 flash cache,一个 CPU 在启动 flash 写入或擦除操作时,另一个 CPU 将阻塞在 flash 操作完成前,所有 CPU 上,所有的非 IRAM 安全的中断都会被禁用。
.. only:: CONFIG_FREERTOS_UNICORE
为避免意外读取 flash cache,在 flash 操作完成前,所有 CPU 上,所有的非 IRAM 安全的中断都会被禁用。
另请参阅 :ref:`esp_flash_os_func`:ref:`spi_bus_lock`
除 SPI0/1 以外,SPI 总线上的其它 flash 芯片则不受这种限制。
请参阅 :ref:`应用程序内存分布 <memory-layout>`,查看内部 RAM(如 IRAM、DRAM)和 flash cache 的区别。
另请参阅 :ref:`esp_flash_os_func`:ref:`spi_bus_lock`
.. _iram-safe-interrupt-handlers:
@@ -39,37 +49,19 @@ IRAM 安全中断处理程序
如果您需要在 flash 操作期间运行中断处理程序(比如低延迟操作),请在 :doc:`注册中断处理程序 </api-reference/system/intr_alloc>` 时设置 ``ESP_INTR_FLAG_IRAM``
请确保中断处理程序访问的所有数据和函数(包括其调用的数据和函数)都存储在 IRAM 或 DRAM 中。有两种方法可供使用:
请确保中断处理程序访问的所有数据和函数(包括其调用的数据和函数)都存储在 IRAM 或 DRAM 中。参见 :ref:`how-to-place-code-in-iram`
使用属性宏
""""""""""""""""""""
在函数或符号未被正确放入 IRAM/DRAM 的情况下,中断处理程序在 flash 操作期间从 flash cache 中读取数据时,会导致程序崩溃。这可能是因为代码未被正确放入 IRAM 而产生非法指令异常,也可能是因为常数未被正确放入 DRAM 而读取到垃圾数据。
为函数添加 ``IRAM_ATTR`` 属性::
.. note::
#include "esp_attr.h"
在 ISRs 中处理字符串时,不建议使用 `printf` 和其他输出函数。为了方便调试,在从 ISRs 中获取数据时,请使用 :cpp:func:`ESP_DRAM_LOGE` 和类似的宏。请确保 ``TAG`` 和格式字符串都放置于 ``DRAM`` 中。
void IRAM_ATTR gpio_isr_handler(void* arg)
{
// ...
}
非 IRAM 安全中断处理程序
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
如果在注册时没有设置 `ESP_INTR_FLAG_IRAM` 标志,当 cache 被禁用时,将不会执行中断处理程序。一旦 cache 恢复,非 IRAM 安全的中断将重新启用,中断处理程序随即再次正常运行。这意味着,只要 cache 被禁用,将不会发生相应的硬件事件。
为常量添加 ``DRAM_ATTR````DRAM_STR`` 属性::
void IRAM_ATTR gpio_isr_handler(void* arg)
{
const static DRAM_ATTR uint8_t INDEX_DATA[] = { 45, 33, 12, 0 };
const static char *MSG = DRAM_STR("I am a string stored in RAM");
}
辨别哪些数据应标记为 ``DRAM_ATTR`` 可能会比较困难,除非明确标记为 ``DRAM_ATTR``,否则编译器依然可能将某些变量或表达式当做常量(即便没有 ``const`` 标记),并将其放入 flash。
使用链接脚本
""""""""""""""""""""""
参见 :doc:`/api-guides/linker-script-generation`
如果函数或符号未被正确放入 IRAM/DRAM 中,当中断处理程序在 flash 操作期间从 flash cache 中读取数据,则会产生非法指令异常(这是因为代码未被正确放入 IRAM)或读取垃圾数据(这是因为常数未被正确放入 DRAM),而导致崩溃。
.. only:: esp32c3