]> granicus.if.org Git - esp-idf/blobdiff - components/spi_flash/README.rst
console/linenoise: support buffered stdout
[esp-idf] / components / spi_flash / README.rst
index 22f98cf02d014434f9dd5af1edc01a596f6cd3d9..807b592d2818483bdcb025dc9dc7ec0aff4635dd 100644 (file)
-Driver for SPI flash read/write/erase operations
-================================================
+SPI Flash APIs
+==============
 
-Implementation notes
+Overview
+--------
+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 :doc:`partition table </api-guides/partition-tables>`.
+
+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 access APIs
+---------------------
+
+This is the set of APIs for working with data in flash:
+
+- :cpp:func:`spi_flash_read` used to read data from flash to RAM
+- :cpp:func:`spi_flash_write` used to write data from RAM to flash
+- :cpp:func:`spi_flash_erase_sector` used to erase individual sectors of flash
+- :cpp:func:`spi_flash_erase_range` used to erase range of addresses in flash
+- :cpp:func:`spi_flash_get_chip_size` returns flash chip size, in bytes, as configured in menuconfig
+
+Generally, try to avoid using the raw SPI flash functions in favour of
+:ref:`partition-specific functions <flash-partition-apis>`.
+
+SPI Flash Size
+--------------
+
+The SPI flash size is configured by writing a field in the software bootloader
+image header, flashed at offset 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
+:envvar:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``.
+
+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.
+
+Concurrency Constraints
+-----------------------
+
+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.
+
+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.
+
+Refer to the :ref:`application memory layout <memory-layout>` documentation for
+an explanation of the differences between IRAM, DRAM and flash cache.
+
+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.
+
+.. _iram-safe-interrupt-handlers:
+
+IRAM-Safe Interrupt Handlers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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 :doc:`interrupt handler is registered
+</api-reference/system/intr_alloc>`.
+
+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.
+
+Use the ``IRAM_ATTR`` attribute for functions::
+
+    #include "esp_attr.h"
+
+    void IRAM_ATTR gpio_isr_handler(void* arg)
+    {
+        // ...
+    }
+
+Use the ``DRAM_ATTR`` and ``DRAM_STR`` attributes for constant data::
+
+    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``.
+
+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).
+
+.. _flash-partition-apis:
+
+Partition table APIs
+--------------------
+
+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 :doc:`here </api-guides/partition-tables>`.
+
+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``:
+
+- :cpp:func:`esp_partition_find` used to search partition table for entries with
+  specific type, returns an opaque iterator
+- :cpp:func:`esp_partition_get` returns a structure describing the partition, for the given iterator
+- :cpp:func:`esp_partition_next` advances iterator to the next partition found
+- :cpp:func:`esp_partition_iterator_release` releases iterator returned by ``esp_partition_find``
+- :cpp:func:`esp_partition_find_first` is a convenience function which returns structure
+  describing the first partition found by ``esp_partition_find``
+- :cpp:func:`esp_partition_read`, :cpp:func:`esp_partition_write`, :cpp:func:`esp_partition_erase_range`
+  are equivalent to :cpp:func:`spi_flash_read`, :cpp:func:`spi_flash_write`,
+  :cpp:func:`spi_flash_erase_range`, but operate within partition boundaries
+
+.. note::
+    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.
+
+SPI Flash Encryption
 --------------------
 
-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.
+It is possible to encrypt SPI flash contents, and have it transparenlty decrypted by hardware.
+
+Refer to the :doc:`Flash Encryption documentation </security/flash-encryption>` for more details.
+
+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 :doc:`flash encryption </security/flash-encryption>` is enabled.
+Decryption is performed at hardware level.
 
-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.
+Memory mapping APIs are declared in ``esp_spi_flash.h`` and ``esp_partition.h``:
 
-While flash operation is running, interrupts can still run on CPU B.
-We assume that all interrupt code is placed into RAM.
+- :cpp:func:`spi_flash_mmap` maps a region of physical flash addresses into instruction space or data space of the CPU
+- :cpp:func:`spi_flash_munmap` unmaps previously mapped region
+- :cpp:func:`esp_partition_mmap` maps part of a partition into the instruction space or data space of the CPU
 
-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.
+Differences between :cpp:func:`spi_flash_mmap` and :cpp:func:`esp_partition_mmap` are as follows:
 
-Additionally, all API functions are protected with a mutex (s_flash_op_mutex).
+- :cpp:func:`spi_flash_mmap` must be given a 64KB aligned physical address
+- :cpp:func:`esp_partition_mmap` may be given any arbitrary offset within the partition,
+  it will adjust returned pointer to mapped memory as necessary
 
-In a single core environment (CONFIG_FREERTOS_UNICORE enabled), we simply
-disable both caches, no inter-CPU communication takes place.
+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``.