官方文档翻译-ESP32-SPI Flash
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中的數(shù)據(jù)讀取,寫入,擦除和存儲器映射有關(guān)的API。它還具有更高級別的API,定義于分區(qū)表 中的高級別API可用于分區(qū)。
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函數(shù)沒有規(guī)定與SPI0外的其他SPI外設(shè)一起使用 flash 芯片。
SPI flash 訪問API
This is the set of APIs for working with data in flash:
這是用于處理Flash中數(shù)據(jù)的一組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讀取數(shù)據(jù)到RAM
- spi_flash_write() 用于將數(shù)據(jù)從RAM寫入到flash
- spi_flash_erase_sector() 用于擦除 flash 的各個部分
- spi_flash_erase_range() 用于擦除指定地址范圍的flash
- spi_flash_get_chip_size() 返回 flash 芯片大小,以字節(jié)為單位,如menuconfig中配置
Generally, try to avoid using the raw SPI flash functions in favour of partition-specific functions.
一般來說,盡量避免使用原始的SPI flash 功能,以支持特定分區(qū)的功能。
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.
默認(rèn)情況下,當(dāng)將此bootloader 寫入 flash 時,esptool.py會檢測到SPI flash 大小,并使用正確的大小更新標(biāo)頭。此外,可以通過在make menuconfig設(shè)置 ESPTOOLPY_FLASHSIZE 選項來修改flash大小.
If it is necessary to override the configured flash size at runtime, is is possible to set the chip_sizemember of g_rom_flashchip structure. This size is used by spi_flash_* functions (in both software & ROM) for bounds checking.
如果需要在運行時修改配置的 flash 大小,則可以設(shè)置g_rom_flashchip結(jié)構(gòu)體的chip_size成員。這個大小被spi_flash_*函數(shù)(在軟件和ROM中)用于邊界檢查。
并發(fā)約束
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 也用于固件執(zhí)行(通過指令和數(shù)據(jù)高速緩存),因此在讀/寫/擦除時必須禁用這些高速緩存。這意味著兩個CPU必須運行IRAM中的代碼,并且只能在 flash 寫操作發(fā)生時從DRAM讀取數(shù)據(jù)。
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,那么這會自動地發(fā)生。但請注意,它會對系統(tǒng)中的其他任務(wù)產(chǎn)生一些性能影響。
Refer to the application memory layout documentation for an explanation of the differences between IRAM, DRAM and flash cache.
有關(guān)IRAM,DRAM和 flash 緩存之間差異的說明,請參閱應(yīng)用程序內(nèi)存布局文檔。
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 緩存,當(dāng)一個CPU開始 flash 寫入或擦除操作時,另一個CPU將進(jìn)入阻塞狀態(tài),并且在兩個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.
如果您有一個即使在進(jìn)行 flash 操作時也要執(zhí)行的中斷處理程序(例如,需要低延遲的操作),請在注冊中斷處理程序時設(shè)置ESP_INTR_FLAG_IRAM標(biāo)志。
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.
您必須確保這些中斷處理程序訪問的所有數(shù)據(jù)和功能位于IRAM或DRAM中。這包括處理程序調(diào)用的任何函數(shù)。
Use the IRAM_ATTR attribute for functions:
使用該IRAM_ATTR屬性的功能:
#include "esp_attr.h"void IRAM_ATTR gpio_isr_handler(void* arg) {// ... }- 1
- 2
- 3
- 4
- 5
- 6
- 7
Use the DRAM_ATTR and DRAM_STR attributes for constant data:
使用常量數(shù)據(jù)的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"); }- 1
- 2
- 3
- 4
- 5
- 6
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.
請注意,知道應(yīng)該標(biāo)記哪些數(shù)據(jù)為DRAM_ATTR可能很難,編譯器有時會認(rèn)為變量或表達(dá)式是恒定(constant )的(即使未標(biāo)記const),并將其優(yōu)化為Flash,除非標(biāo)記為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).
如果函數(shù)或符號未正確放入IRAM / DRAM中并且中斷處理程序在 flash 操作期間從 flash 緩存中讀取,則會由于非法指令異常(對于應(yīng)該在IRAM中的代碼)或讀取垃圾數(shù)據(jù)(對于應(yīng)該在DRAM中的常數(shù)數(shù)據(jù))而導(dǎo)致崩潰。
分區(qū)表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項目使用分區(qū)表來維護(hù)有關(guān)SPI flash 各個區(qū)域(bootloader ,各種應(yīng)用程序二進(jìn)制文件,數(shù)據(jù),文件系統(tǒng))的信息。有關(guān)分區(qū)表的更多信息可以在這里找到。
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來枚舉在分區(qū)表中找到的分區(qū)并對它們執(zhí)行操作。這些函數(shù)聲明于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() 用于在分區(qū)表中搜索具有特定類型的條目,并返回一個不透明的迭代器
- esp_partition_get() 返回給定迭代器的描述的分區(qū)結(jié)構(gòu)
- esp_partition_next() 獲取下一個分區(qū)
- esp_partition_iterator_release() 釋放由 esp_partition_find返回的迭代器
- esp_partition_find_first() 是一個方便的函數(shù),它返回 esp_partition_find 找到的第一個分區(qū)的結(jié)構(gòu)描述
- esp_partition_read(),esp_partition_write(),esp_partition_erase_range() 等同于spi_flash_read(),spi_flash_write(), spi_flash_erase_range(),但在分區(qū)邊界內(nèi)操作
注意
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.
大多數(shù)應(yīng)用程序代碼應(yīng)該使用這些esp_partition_*API而不是較低級別的 spi_flash_*API。分區(qū)(Partition )API根據(jù)存儲在分區(qū)表中的數(shù)據(jù)進(jìn)行邊界檢查并計算 flash 中的正確偏移量。
SPI Flash加密
It is possible to encrypt SPI flash contents, and have it transparenlty decrypted by hardware.
可以對SPI flash 內(nèi)容進(jìn)行加密,并通過硬件進(jìn)行透明解密。
Refer to the Flash Encryption documentation for more details.
有關(guān)更多詳細(xì)信息,請參閱Flash Encryption文檔。
內(nèi)存映射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具有內(nèi)存硬件,可以將 flash 區(qū)域映射到指令和數(shù)據(jù)地址空間。此映射僅適用于讀取操作,不可能通過寫入映射的內(nèi)存區(qū)域來修改 flash 的內(nèi)容。映射發(fā)生在64KB頁面中。內(nèi)存映射硬件可以將最多4兆字節(jié)的 flash 映射到數(shù)據(jù)地址空間,并將最多16兆字節(jié)的 flash 映射到指令地址空間。有關(guān)內(nèi)存映射硬件的更多詳細(xì)信息,請參閱技術(shù)參考手冊。
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頁面用于將應(yīng)用程序本身映射到內(nèi)存中,因此可用64KB頁面的實際數(shù)量可能會更少。
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.
使用內(nèi)存映射區(qū)從 flash 讀取數(shù)據(jù)是啟用 flash 加密時解密 flash 內(nèi)容的唯一方法。解密是在硬件級別執(zhí)行的。
Memory mapping APIs are declared in esp_spi_flash.h and esp_partition.h:
內(nèi)存映射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 地址的區(qū)域映射到CPU的指令空間或數(shù)據(jù)空間
- spi_flash_munmap() 取消映射先前映射的區(qū)域
- esp_partition_mmap() 將分區(qū)的一部分映射到CPU的指令空間或數(shù)據(jù)空間
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() 可能會在分區(qū)內(nèi)給出任意偏移量,它會根據(jù)需要調(diào)整返回的指向映射內(nèi)存的指針
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.
請注意,由于內(nèi)存映射發(fā)生在64KB塊中,因此可能會讀取esp_partition_mmap提供的分區(qū)以外的數(shù)據(jù)。
也可以看看
- 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.
-
分區(qū)表文檔
- Over The Air Update(OTA)API提供了用于更新存儲在 flash 中的應(yīng)用程序固件的高級API。
- 非易失性存儲(NVS)API提供了一個結(jié)構(gòu)化API,用于在SPI flash 中存儲小數(shù)據(jù)。
細(xì)節(jié)實現(xiàn)
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.
為了執(zhí)行一些 flash 操作,我們需要確保兩個CPU在 flash 操作期間沒有從 flash 中運行任何代碼。在單核設(shè)置中,這很簡單:我們禁用中斷/調(diào)度程序并執(zhí)行 flash 操作。在雙核心設(shè)置中,這稍微復(fù)雜一些。我們需要確保另一個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.
當(dāng)在CPU A上調(diào)用SPI Flash API(可以是PRO或APP)時,我們使用 esp_ipc_call API在CPU B上啟動 spi_flash_op_block_func 函數(shù)。這個API喚醒了CPU B的高優(yōu)先級任務(wù),并告訴它執(zhí)行給定的函數(shù),在這種情況下是執(zhí)行 spi_flash_op_block_func 。此功能禁用CPU B上的高速緩存,并通過設(shè)置 s_flash_op_can_start 標(biāo)志指示緩存被禁用。然后,CPU A上的任務(wù)也會禁用緩存,然后繼續(xù)執(zhí)行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,我們應(yīng)該添加一個標(biāo)志來請求在 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上的功能會設(shè)置另一個標(biāo)志 s_flash_op_complete ,讓CPU B上的任務(wù)知道它可以重新啟用緩存并釋放CPU。然后,CPU A上的功能也重新啟用CPU A上的緩存,并將控制權(quán)返回給調(diào)用代碼。
Additionally, all API functions are protected with a mutex (s_flash_op_mutex).
此外,所有的API函數(shù)都被一個互斥鎖保護(hù)(s_flash_op_mutex)。
In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply disable both caches, no inter-CPU communication takes place.
在單核心環(huán)境中(啟用 CONFIG_FREERTOS_UNICORE ),我們只需禁用兩個高速緩存,就不會發(fā)生CPU間通信。
API參考 - SPI Flash
頭文件
- spi_flash /包含/ esp_spi_flash.h
此文翻譯自:http://esp-idf.readthedocs.io/en/latest/api-reference/storage/spi_flash.html
內(nèi)容參照google翻譯,有些部分翻譯不準(zhǔn)確請參照原文理解
?
總結(jié)
以上是生活随笔為你收集整理的官方文档翻译-ESP32-SPI Flash的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 官方文档翻译-ESP32-High Re
- 下一篇: ESP8266/ESP32 NVS 基本