您的位置:首页 > 其它

官方文档翻译-ESP32-SPI Flash

2018-03-08 16:41 507 查看

SPI Flash

概述

The spi_flash component contains APIs related to reading, writing, erasing, memory mapping data in the external SPI flash. It also has higher-level APIs which work with partitions defined in the partition table.

spi_flash组件包含与外部SPI flash中的数据读取,写入,擦除和存储器映射有关的API。它还具有更高级别的API,定义于分区表 中的高级别API可用于分区。

Note that all the functionality is limited to the “main” SPI flash chip, the same SPI flash chip from which program runs. For
spi_flash_*
functions, this is a software limitation. The underlying ROM functions which work with SPI flash do not have provisions for working with flash chips attached to SPI peripherals other than SPI0.

请注意,所有功能仅限于“主”SPI flash芯片,即与其运行程序相同的SPI flash 芯片。对于
spi_flash_*
的功能,这是一个软件限制。与SPI flash 配合使用的底层ROM函数没有规定与SPI0外的其他SPI外设一起使用 flash 芯片。

SPI flash 访问API

This is the set of APIs for working with data in flash:

这是用于处理Flash中数据的一组API:

spi_flash_read()
used to read data from flash to RAM

spi_flash_write()
used to write data from RAM to flash

spi_flash_erase_sector()
used to erase individual sectors of flash

spi_flash_erase_range()
used to erase range of addresses in flash

spi_flash_get_chip_size()
returns flash chip size, in bytes, as configured in menuconfig



spi_flash_read()
用于从flash读取数据到RAM

spi_flash_write()
用于将数据从RAM写入到flash

spi_flash_erase_sector()
用于擦除 flash 的各个部分

spi_flash_erase_range()
用于擦除指定地址范围的flash

spi_flash_get_chip_size()
返回 flash 芯片大小,以字节为单位,如menuconfig中配置

Generally, try to avoid using the raw SPI flash functions in favour of partition-specific functions.

一般来说,尽量避免使用原始的SPI flash 功能,以支持特定分区的功能

SPI flash 大小

The SPI flash size is configured by writing a field in the software bootloader image header, flashed at offset 0x1000.

通过在软件bootloader映像头中写入一个字段来配置SPI flash 大小, flash 位于偏移量0x1000处。

By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct size. Alternatively, it is possible to generate a fixed flash size by setting ESPTOOLPY_FLASHSIZE in
make menuconfig
.

默认情况下,当将此bootloader 写入 flash 时,esptool.py会检测到SPI flash 大小,并使用正确的大小更新标头。此外,可以通过在
make menuconfig
设置 ESPTOOLPY_FLASHSIZE 选项来修改flash大小.

If it is necessary to override the configured flash size at runtime, is is possible to set the
chip_size
member of
g_rom_flashchip
structure. This size is used by
spi_flash_*
functions (in both software & ROM) for bounds checking.

如果需要在运行时修改配置的 flash 大小,则可以设置
g_rom_flashchip
结构体的
chip_size
成员。这个大小被
spi_flash_*
函数(在软件和ROM中)用于边界检查。

并发约束

Because the SPI flash is also used for firmware execution (via the instruction & data caches), these caches must be disabled while reading/writing/erasing. This means that both CPUs must be running code from IRAM and only reading data from DRAM while flash write operations occur.

由于SPI flash 也用于固件执行(通过指令和数据高速缓存),因此在读/写/擦除时必须禁用这些高速缓存。这意味着两个CPU必须运行IRAM中的代码,并且只能在 flash 写操作发生时从DRAM读取数据。

If you use the APIs documented here, then this happens automatically and transparently. However note that it will have some performance impact on other tasks in the system.

如果您使用这里记录的API,那么这会自动地发生。但请注意,它会对系统中的其他任务产生一些性能影响。

Refer to the application memory layout documentation for an explanation of the differences between IRAM, DRAM and flash cache.

有关IRAM,DRAM和 flash 缓存之间差异的说明,请参阅应用程序内存布局文档。

To avoid reading flash cache accidentally, when one CPU commences a flash write or erase operation the other CPU is put into a blocked state and all non-IRAM-safe interrupts are disabled on both CPUs, until the flash operation completes.

为避免意外读取 flash 缓存,当一个CPU开始 flash 写入或擦除操作时,另一个CPU将进入阻塞状态,并且在两个CPU上禁用所有非IRAM安全(non-IRAM-safe)的中断,直到 flash 操作完成。

IRAM安全(IRAM-Safe)中断处理程序

If you have an interrupt handler that you want to execute even when a flash operation is in progress (for example, for low latency operations), set the
ESP_INTR_FLAG_IRAM
flag when the interrupt handler is registered.

如果您有一个即使在进行 flash 操作时也要执行的中断处理程序(例如,需要低延迟的操作),请在注册中断处理程序时设置
ESP_INTR_FLAG_IRAM
标志。

You must ensure all data and functions accessed by these interrupt handlers are located in IRAM or DRAM. This includes any functions that the handler calls.

您必须确保这些中断处理程序访问的所有数据和功能位于IRAM或DRAM中。这包括处理程序调用的任何函数。

Use the
IRAM_ATTR
attribute for functions:

使用该
IRAM_ATTR
属性的功能:

#include "esp_attr.h"

void IRAM_ATTR gpio_isr_handler(void* arg)
{
// ...
}


Use the
DRAM_ATTR
and
DRAM_STR
attributes for constant data:

使用常量数据的
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");
}


Note that knowing which data should be marked with
DRAM_ATTR
can be hard, the compiler will sometimes recognise that a variable or expression is constant (even if it is not marked
const
) and optimise it into flash, unless it is marked with
DRAM_ATTR
.

请注意,知道应该标记哪些数据为
DRAM_ATTR
可能很难,编译器有时会认为变量或表达式是恒定(constant )的(即使未标记
const
),并将其优化为Flash,除非标记为
DRAM_ATTR


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).

如果函数或符号未正确放入IRAM / DRAM中并且中断处理程序在 flash 操作期间从 flash 缓存中读取,则会由于非法指令异常(对于应该在IRAM中的代码)或读取垃圾数据(对于应该在DRAM中的常数数据)而导致崩溃。

分区表API

ESP-IDF projects use a partition table to maintain information about various regions of SPI flash memory (bootloader, various application binaries, data, filesystems). More information about partition tables can be found here.

ESP-IDF项目使用分区表来维护有关SPI flash 各个区域(bootloader ,各种应用程序二进制文件,数据,文件系统)的信息。有关分区表的更多信息可以在这里找到。

This component provides APIs to enumerate partitions found in the partition table and perform operations on them. These functions are declared in
esp_partition.h
:

该组件提供了API来枚举在分区表中找到的分区并对它们执行操作。这些函数声明于
esp_partition.h


esp_partition_find()
used to search partition table for entries with specific type, returns an opaque iterator

esp_partition_get()
returns a structure describing the partition, for the given iterator

esp_partition_next()
advances iterator to the next partition found

esp_partition_iterator_release()
releases iterator returned by
esp_partition_find


esp_partition_find_first()
is a convenience function which returns structure describing the first partition found by esp_partition_find

esp_partition_read()
,
esp_partition_write()
,
esp_partition_erase_range()
are equivalent to
spi_flash_read()
,
spi_flash_write()
,
spi_flash_erase_range()
, but operate within partition boundaries

esp_partition_find()
用于在分区表中搜索具有特定类型的条目,并返回一个不透明的迭代器

esp_partition_get()
返回给定迭代器的描述的分区结构

esp_partition_next()
获取下一个分区

esp_partition_iterator_release()
释放由
esp_partition_find
返回的迭代器

esp_partition_find_first()
是一个方便的函数,它返回
esp_partition_find
找到的第一个分区的结构描述

esp_partition_read()
esp_partition_write()
esp_partition_erase_range()
等同于
spi_flash_read()
spi_flash_write()
spi_flash_erase_range()
,但在分区边界内操作

注意

Most application code should use these
esp_partition_*
APIs instead of lower level
spi_flash_*
APIs. Partition APIs do bounds checking and calculate correct offsets in flash based on data stored in partition table.

大多数应用程序代码应该使用这些
esp_partition_*
API而不是较低级别的
spi_flash_*
API。分区(Partition )API根据存储在分区表中的数据进行边界检查并计算 flash 中的正确偏移量。

SPI Flash加密

It is possible to encrypt SPI flash contents, and have it transparenlty decrypted by hardware.

可以对SPI flash 内容进行加密,并通过硬件进行透明解密。

Refer to the Flash Encryption documentation for more details.

有关更多详细信息,请参阅Flash Encryption文档

内存映射API

ESP32 features memory hardware which allows regions of flash memory to be mapped into instruction and data address spaces. This mapping works only for read operations, it is not possible to modify contents of flash memory by writing to mapped memory region. Mapping happens in 64KB pages. Memory mapping hardware can map up to 4 megabytes of flash into data address space, and up to 16 megabytes of flash into instruction address space. See the technical reference manual for more details about memory mapping hardware.

ESP32具有内存硬件,可以将 flash 区域映射到指令和数据地址空间。此映射仅适用于读取操作,不可能通过写入映射的内存区域来修改 flash 的内容。映射发生在64KB页面中。内存映射硬件可以将最多4兆字节的 flash 映射到数据地址空间,并将最多16兆字节的 flash 映射到指令地址空间。有关内存映射硬件的更多详细信息,请参阅技术参考手册。

Note that some number of 64KB pages is used to map the application itself into memory, so the actual number of available 64KB pages may be less.

请注意,一些64KB页面用于将应用程序本身映射到内存中,因此可用64KB页面的实际数量可能会更少。

Reading data from flash using a memory mapped region is the only way to decrypt contents of flash when flash encryption is enabled. Decryption is performed at hardware level.

使用内存映射区从 flash 读取数据是启用 flash 加密时解密 flash 内容的唯一方法。解密是在硬件级别执行的。

Memory mapping APIs are declared in
esp_spi_flash.h
and
esp_partition.h
:

内存映射API在
esp_spi_flash.h
esp_partition.h
中声明:

spi_flash_mmap()
maps a region of physical flash addresses into instruction space or data space of the CPU

spi_flash_munmap()
unmaps previously mapped region

esp_partition_mmap()
maps part of a partition into the instruction space or data space of the CPU

spi_flash_mmap()
将物理 flash 地址的区域映射到CPU的指令空间或数据空间

spi_flash_munmap()
取消映射先前映射的区域

esp_partition_mmap()
将分区的一部分映射到CPU的指令空间或数据空间

Differences between
spi_flash_mmap()
and
esp_partition_mmap()
are as follows:

spi_flash_mmap()
esp_partition_mmap()
之间的差异如下:

spi_flash_mmap()
must be given a 64KB aligned physical address

esp_partition_mmap()
may be given any arbitrary offset within the partition, it will adjust returned pointer to mapped memory as necessary

spi_flash_mmap()
必须给予一个64KB的对齐物理地址

esp_partition_mmap()
可能会在分区内给出任意偏移量,它会根据需要调整返回的指向映射内存的指针

Note that because memory mapping happens in 64KB blocks, it may be possible to read data outside of the partition provided to
esp_partition_mmap
.

请注意,由于内存映射发生在64KB块中,因此可能会读取
esp_partition_mmap
提供的分区以外的数据。

也可以看看

Partition Table documentation

Over The Air Update (OTA) API provides high-level API for updating app firmware stored in flash.

Non-Volatile Storage (NVS) API provides a structured API for storing small items of data in SPI flash.

分区表文档

Over The Air Update(OTA)API提供了用于更新存储在 flash 中的应用程序固件的高级API。

非易失性存储(NVS)API提供了一个结构化API,用于在SPI flash 中存储小数据。

细节实现

In order to perform some flash operations, we need to make sure both CPUs are not running any code from flash for the duration of the flash operation. In a single-core setup this is easy: we disable interrupts/scheduler and do the flash operation. In the dual-core setup this is slightly more complicated. We need to make sure that the other CPU doesn’t run any code from flash.

为了执行一些 flash 操作,我们需要确保两个CPU在 flash 操作期间没有从 flash 中运行任何代码。在单核设置中,这很简单:我们禁用中断/调度程序并执行 flash 操作。在双核心设置中,这稍微复杂一些。我们需要确保另一个CPU不会从 flash 中运行任何代码。

When SPI flash API is called on CPU A (can be PRO or APP), we start
spi_flash_op_block_func
function on CPU B using
esp_ipc_call
API. This API wakes up high priority task on CPU B and tells it to execute given function, in this case
spi_flash_op_block_func
. This function disables cache on CPU B and signals that cache is disabled by setting
s_flash_op_can_start
flag. Then the task on CPU A disables cache as well, and proceeds to execute flash operation.

当在CPU A上调用SPI Flash API(可以是PRO或APP)时,我们使用
esp_ipc_call
API在CPU B上启动
spi_flash_op_block_func
函数。这个API唤醒了CPU B的高优先级任务,并告诉它执行给定的函数,在这种情况下是执行
spi_flash_op_block_func
。此功能禁用CPU B上的高速缓存,并通过设置
s_flash_op_can_start
标志指示缓存被禁用。然后,CPU A上的任务也会禁用缓存,然后继续执行Flash操作。

While flash operation is running, interrupts can still run on CPUs A and B. We assume that all interrupt code is placed into RAM. Once interrupt allocation API is added, we should add a flag to request interrupt to be disabled for the duration of flash operations.

在 flash 操作正在运行时,中断仍然可以在CPU A和B上运行。我们假定所有的中断代码都被放入RAM中。一旦添加了中断分配API,我们应该添加一个标志来请求在 flash 操作期间禁用中断。

Once flash operation is complete, function on CPU A sets another flag,
s_flash_op_complete
, to let the task on CPU B know that it can re-enable cache and release the CPU. Then the function on CPU A re-enables the cache on CPU A as well and returns control to the calling code.

一旦 flash 操作完成,CPU A上的功能会设置另一个标志
s_flash_op_complete
,让CPU B上的任务知道它可以重新启用缓存并释放CPU。然后,CPU A上的功能也重新启用CPU A上的缓存,并将控制权返回给调用代码。

Additionally, all API functions are protected with a mutex (
s_flash_op_mutex
).

此外,所有的API函数都被一个互斥锁保护(
s_flash_op_mutex
)。

In a single core environment (
CONFIG_FREERTOS_UNICORE
enabled), we simply disable both caches, no inter-CPU communication takes place.

在单核心环境中(启用
CONFIG_FREERTOS_UNICORE
),我们只需禁用两个高速缓存,就不会发生CPU间通信。

API参考 - SPI Flash

头文件

spi_flash /包含/ esp_spi_flash.h

此文翻译自:http://esp-idf.readthedocs.io/en/latest/api-reference/storage/spi_flash.html

内容参照google翻译,有些部分翻译不准确请参照原文理解
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: