From e03b45eb0a9eb07eb1e78c7869af18a7faa386d5 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 25 Oct 2016 11:43:00 +0800 Subject: [PATCH] spi_flash: improve documentation --- .../esp32/include/esp_flash_data_types.h | 38 ++--- components/spi_flash/README.rst | 133 +++++++++++++++++- components/spi_flash/include/esp_spi_flash.h | 2 + 3 files changed, 152 insertions(+), 21 deletions(-) diff --git a/components/esp32/include/esp_flash_data_types.h b/components/esp32/include/esp_flash_data_types.h index b16ee59f57..4bf886c842 100644 --- a/components/esp32/include/esp_flash_data_types.h +++ b/components/esp32/include/esp_flash_data_types.h @@ -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; diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index 22f98cf02d..b479c3b0e9 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -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 diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 2aa92d9a5d..16b50a7189 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -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(); -- 2.50.1