spi_flash: improve documentation

This commit is contained in:
Ivan Grokhotkov 2016-10-25 11:43:00 +08:00
parent e229ec0340
commit e03b45eb0a
3 changed files with 152 additions and 21 deletions

View File

@ -24,7 +24,7 @@ extern "C"
#define ESP_PARTITION_TABLE_ADDR 0x4000
#define ESP_PARTITION_MAGIC 0x50AA
/*spi mode,saved in third byte in flash */
/* SPI flash mode, used in esp_image_header_t */
typedef enum {
ESP_IMAGE_SPI_MODE_QIO,
ESP_IMAGE_SPI_MODE_QOUT,
@ -34,7 +34,7 @@ typedef enum {
ESP_IMAGE_SPI_MODE_SLOW_READ
} esp_image_spi_mode_t;
/* spi speed*/
/* SPI flash clock frequency */
enum {
ESP_IMAGE_SPI_SPEED_40M,
ESP_IMAGE_SPI_SPEED_26M,
@ -42,7 +42,7 @@ enum {
ESP_IMAGE_SPI_SPEED_80M = 0xF
} esp_image_spi_freq_t;
/*supported flash sizes*/
/* Supported SPI flash sizes */
typedef enum {
ESP_IMAGE_FLASH_SIZE_1MB = 0,
ESP_IMAGE_FLASH_SIZE_2MB,
@ -52,22 +52,23 @@ typedef enum {
ESP_IMAGE_FLASH_SIZE_MAX
} esp_image_flash_size_t;
/* Main header of binary image */
typedef struct {
char magic;
char blocks;
char spi_mode; /* flag of flash read mode in unpackage and usage in future */
char spi_speed: 4; /* low bit */
char spi_size: 4;
unsigned int entry_addr;
uint8_t magic;
uint8_t blocks;
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
uint32_t entry_addr;
uint8_t encrypt_flag; /* encrypt flag */
uint8_t secure_boot_flag; /* secure boot flag */
char extra_header[14]; /* ESP32 additional header, unused by second bootloader */
uint8_t extra_header[14]; /* ESP32 additional header, unused by second bootloader */
} esp_image_header_t;
/* each header of flash bin block */
/* Header of binary image segment */
typedef struct {
unsigned int load_addr;
unsigned int data_len;
uint32_t load_addr;
uint32_t data_len;
} esp_image_section_header_t;
@ -85,13 +86,16 @@ typedef struct {
uint32_t size;
} esp_partition_pos_t;
/* Structure which describes the layout of partition table entry.
* See docs/partition_tables.rst for more information about individual fields.
*/
typedef struct {
uint16_t magic;
uint8_t type; /* partition Type */
uint8_t subtype; /* part_subtype */
uint8_t type;
uint8_t subtype;
esp_partition_pos_t pos;
uint8_t label[16]; /* label for the partition */
uint8_t reserved[4]; /* reserved */
uint8_t label[16];
uint8_t reserved[4];
} esp_partition_info_t;

View File

@ -1,5 +1,128 @@
Driver for SPI flash read/write/erase operations
================================================
SPI flash related APIs
======================
Overview
--------
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 partition table and partitions.
Note that all the functionality is limited to the "main" flash chip,
i.e. the flash chip from which program runs. For ``spi_flash_*`` functions,
this is software limitation. 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 access APIs
---------------------
This is the set of APIs for working with data in flash:
- ``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
There are some data alignment limitations which need to be considered when using
spi_flash_read/spi_flash_write functions:
- buffer in RAM must be 4-byte aligned
- size must be 4-byte aligned
- address in flash must be 4-byte aligned
These alignment limitations are purely software, and should be removed in future
versions.
It is assumed that correct SPI flash chip size is set at compile time using
menuconfig. While run-time detection of SPI flash chip size is possible, it is
not implemented yet. Applications which need this (e.g. to provide one firmware
binary for different flash sizes) can do flash chip size detection and set
the correct flash chip size in ``chip_size`` member of ``g_rom_flashchip``
structure. This size is used by ``spi_flash_*`` functions for bounds checking.
SPI flash APIs disable instruction and data caches while reading/writing/erasing.
See implementation notes below on details how this happens. For application
this means that at some periods of time, code can not be run from flash,
and constant data can not be fetched from flash by the CPU. This is not an
issue for normal code which runs in a task, because SPI flash APIs prevent
other tasks from running while caches are disabled. This is an issue for
interrupt handlers, which can still be called while flash operation is in
progress. If the interrupt handler is not placed into IRAM, there is a
possibility that interrupt will happen at the time when caches are disabled,
which will cause an illegal instruction exception.
To prevent this, make sure that all ISR code, and all functions called from ISR
code are placed into IRAM, or are located in ROM. Most useful C library
functions are located in ROM, so they can be called from ISR.
To place a function into IRAM, use ``IRAM_ATTR`` attribute, e.g.::
#include "esp_attr.h"
void IRAM_ATTR gpio_isr_handler(void* arg)
{
// ...
}
When flash encryption is enabled, ``spi_flash_read`` will read data as it is
stored in flash (without decryption), and ``spi_flash_write`` will write data
in plain text. In other words, ``spi_flash_read/write`` APIs don't have
provisions to deal with encrypted data.
Partition table APIs
--------------------
ESP-IDF uses 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 in docs/partition_tables.rst.
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``:
- ``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
Most application code should use ``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.
Memory mapping APIs
-------------------
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.
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.
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.
Memory mapping APIs are declared in ``esp_spi_flash.h`` and ``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
Differences between ``spi_flash_mmap`` and ``esp_partition_mmap`` are as follows:
- ``spi_flash_mmap`` must be given a 64KB aligned physical address
- ``esp_partition_mmap`` may be given an arbitrary offset within the partition, it will adjust returned pointer to mapped memory as necessary
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``.
Implementation notes
--------------------
@ -19,8 +142,10 @@ 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.
While flash operation is running, interrupts can still run on CPU B.
We assume that all interrupt code is placed into RAM.
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.
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

View File

@ -35,6 +35,8 @@ extern "C" {
*
* This function must be called exactly once, before any other
* spi_flash_* functions are called.
* Currently this function is called from startup code. There is
* no need to call it from application code.
*
*/
void spi_flash_init();