#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,
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,
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,
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;
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;
-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
--------------------
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