mirror of
https://github.com/espressif/esp-idf.git
synced 2025-11-02 16:11:41 +01:00
docs: update format issues for EN and CN files under api-reference/provisioning and api-reference/storage
This commit is contained in:
@@ -239,7 +239,7 @@ After session establishment, the client can also request Wi-Fi scan results from
|
||||
|
||||
* ``passive`` (input) - If true, the scan is started in passive mode, which may be slower, instead of active mode.
|
||||
|
||||
* ``group_channels`` (input) - This specifies whether to scan all channels in one go when zero, or perform scanning of channels in groups, with 120 ms delay between scanning of consecutive groups, and the value of this parameter sets the number of channels in each group. This is useful when transport mode is SoftAP, where scanning all channels in one go may not give the Wi-Fi driver enough time to send out beacons, and hence may cause disconnection with any connected stations. When scanning in groups, the manager waits for at least 120 ms after completing the scan on a group of channels, and thus allows the driver to send out the beacons. For example, given that the total number of Wi-Fi channels is 14, then setting ``group_channels`` to 3 creates 5 groups, with each group having 3 channels, except the last one which has 14 % 3 = 2 channels. So, when the scan is started, the first 3 channels will be scanned, followed by a 120 ms delay, and then the next 3 channels, and so on, until all the 14 channels have been scanned.One may need to adjust this parameter as having only a few channels in a group may increase the overall scan time, while having too many may again cause disconnection. Usually, a value of 4 should work for most cases. Note that for any other mode of transport, e.g. Bluetooth LE, this can be safely set to 0, and hence achieve the shortest overall scanning time.
|
||||
* ``group_channels`` (input) - This specifies whether to scan all channels in one go when zero, or perform scanning of channels in groups, with 120 ms delay between scanning of consecutive groups, and the value of this parameter sets the number of channels in each group. This is useful when transport mode is SoftAP, where scanning all channels in one go may not give the Wi-Fi driver enough time to send out beacons, and hence may cause disconnection with any connected stations. When scanning in groups, the manager waits for at least 120 ms after completing the scan on a group of channels, and thus allows the driver to send out the beacons. For example, given that the total number of Wi-Fi channels is 14, then setting ``group_channels`` to 3 creates 5 groups, with each group having 3 channels, except the last one which has 14 % 3 = 2 channels. So, when the scan is started, the first 3 channels will be scanned, followed by a 120 ms delay, and then the next 3 channels, and so on, until all the 14 channels have been scanned.One may need to adjust this parameter as having only a few channels in a group may increase the overall scan time, while having too many may again cause disconnection. Usually, a value of 4 should work for most cases. Note that for any other mode of transport, e.g., Bluetooth LE, this can be safely set to 0, and hence achieve the shortest overall scanning time.
|
||||
|
||||
* ``period_ms`` (input) - The scan parameter specifying how long to wait on each channel.
|
||||
|
||||
@@ -283,7 +283,7 @@ One can also choose to call :cpp:func:`wifi_prov_mgr_endpoint_unregister()` to m
|
||||
When/How to Stop the Provisioning Service?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The default behavior is that once the device successfully connects using the Wi-Fi credentials set by the ``apply_config`` command, the provisioning service stops, and Bluetooth LE or SoftAP turns off, automatically after responding to the next ``get_status`` command. If ``get_status`` command is not received by the device, the service stops after a 30s timeout.
|
||||
The default behavior is that once the device successfully connects using the Wi-Fi credentials set by the ``apply_config`` command, the provisioning service stops, and Bluetooth LE or SoftAP turns off, automatically after responding to the next ``get_status`` command. If ``get_status`` command is not received by the device, the service stops after a 30 s timeout.
|
||||
|
||||
On the other hand, if device is not able to connect using the provided Wi-Fi credentials, due to incorrect SSID or passphrase, the service keeps running, and ``get_status`` keeps responding with disconnected status and reason for disconnection. Any further attempts to provide another set of Wi-Fi credentials, are to be rejected. These credentials are preserved, unless the provisioning service is force started, or NVS erased.
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Most applications use the following workflow when working with ``esp_vfs_fat_``
|
||||
1. Call :cpp:func:`esp_vfs_fat_register` to specify:
|
||||
- Path prefix where to mount the filesystem (e.g., ``"/sdcard"``, ``"/spiflash"``)
|
||||
- FatFs drive number
|
||||
- A variable which will receive the pointer to the ``FATFS`` structure
|
||||
- A variable which receives the pointer to the ``FATFS`` structure
|
||||
|
||||
2. Call :cpp:func:`ff_diskio_register` to register the disk I/O driver for the drive number used in Step 1.
|
||||
|
||||
@@ -30,7 +30,7 @@ Most applications use the following workflow when working with ``esp_vfs_fat_``
|
||||
|
||||
4. Call the C standard library and POSIX API functions to perform such actions on files as open, read, write, erase, copy, etc. Use paths starting with the path prefix passed to :cpp:func:`esp_vfs_register` (for example, ``"/sdcard/hello.txt"``). The filesystem uses `8.3 filenames <https://en.wikipedia.org/wiki/8.3_filename>`_ format (SFN) by default. If you need to use long filenames (LFN), enable the :ref:`CONFIG_FATFS_LONG_FILENAMES` option. More details on the FatFs filenames are available `here <http://elm-chan.org/fsw/ff/doc/filename.html>`_.
|
||||
|
||||
5. Optionally, by enabling the option :ref:`CONFIG_FATFS_USE_FASTSEEK`, you can use the POSIX lseek function to perform it faster. The fast seek will not work for files in write mode, so to take advantage of fast seek, you should open (or close and then reopen) the file in read-only mode.
|
||||
5. Optionally, by enabling the option :ref:`CONFIG_FATFS_USE_FASTSEEK`, you can use the POSIX lseek function to perform it faster. The fast seek does not work for files in write mode, so to take advantage of fast seek, you should open (or close and then reopen) the file in read-only mode.
|
||||
|
||||
6. Optionally, call the FatFs library functions directly. In this case, use paths without a VFS prefix (for example, ``"/hello.txt"``).
|
||||
|
||||
@@ -66,7 +66,7 @@ The convenience function :cpp:func:`esp_vfs_fat_sdmmc_unmount` unmounts the file
|
||||
Using FatFs with VFS in Read-Only Mode
|
||||
--------------------------------------
|
||||
|
||||
The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` also defines the convenience functions :cpp:func:`esp_vfs_fat_spiflash_mount_ro` and :cpp:func:`esp_vfs_fat_spiflash_unmount_ro`. These functions perform Steps 1-3 and 7-9 respectively for read-only FAT partitions. These are particularly helpful for data partitions written only once during factory provisioning which will not be changed by production application throughout the lifetime of the hardware.
|
||||
The header file :component_file:`fatfs/vfs/esp_vfs_fat.h` also defines the convenience functions :cpp:func:`esp_vfs_fat_spiflash_mount_ro` and :cpp:func:`esp_vfs_fat_spiflash_unmount_ro`. These functions perform Steps 1-3 and 7-9 respectively for read-only FAT partitions. These are particularly helpful for data partitions written only once during factory provisioning, which will not be changed by production application throughout the lifetime of the hardware.
|
||||
|
||||
.. doxygenfunction:: esp_vfs_fat_spiflash_mount_ro
|
||||
.. doxygenfunction:: esp_vfs_fat_spiflash_unmount_ro
|
||||
@@ -92,11 +92,11 @@ These APIs provide implementation of disk I/O functions for SD/MMC cards and can
|
||||
FatFs Partition Generator
|
||||
-------------------------
|
||||
|
||||
We provide a partition generator for FatFs (:component_file:`wl_fatfsgen.py<fatfs/wl_fatfsgen.py>`) which is integrated into the build system and could be easily used in the user project.
|
||||
We provide a partition generator for FatFs (:component_file:`wl_fatfsgen.py <fatfs/wl_fatfsgen.py>`) which is integrated into the build system and could be easily used in the user project.
|
||||
|
||||
The tool is used to create filesystem images on a host and populate it with content of the specified host folder.
|
||||
|
||||
The script is based on the partition generator (:component_file:`fatfsgen.py<fatfs/fatfsgen.py>`). Apart from generating partition, it can also initialize wear levelling.
|
||||
The script is based on the partition generator (:component_file:`fatfsgen.py <fatfs/fatfsgen.py>`). Apart from generating partition, it can also initialize wear levelling.
|
||||
|
||||
The latest version supports both short and long file names, FAT12 and FAT16. The long file names are limited to 255 characters and can contain multiple periods (``.``) characters within the filename and additional characters ``+``, ``,``, ``;``, ``=``, ``[`` and ``]``.
|
||||
|
||||
@@ -120,7 +120,7 @@ If you decide for any reason to use ``fatfs_create_rawflash_image`` (without wea
|
||||
|
||||
The arguments of the function are as follows:
|
||||
|
||||
1. partition - the name of the partition as defined in the partition table (e.g. :example_file:`storage/fatfsgen/partitions_example.csv`).
|
||||
1. partition - the name of the partition as defined in the partition table (e.g., :example_file:`storage/fatfsgen/partitions_example.csv`).
|
||||
|
||||
2. base_dir - the directory that will be encoded to FatFs partition and optionally flashed into the device. Beware that you have to specify the suitable size of the partition in the partition table.
|
||||
|
||||
@@ -141,9 +141,9 @@ For an example, see :example:`storage/fatfsgen`.
|
||||
FatFs Partition Analyzer
|
||||
------------------------
|
||||
|
||||
(:component_file:`fatfsparse.py<fatfs/fatfsparse.py>`) is a partition analyzing tool for FatFs.
|
||||
(:component_file:`fatfsparse.py <fatfs/fatfsparse.py>`) is a partition analyzing tool for FatFs.
|
||||
|
||||
It is a reverse tool of (:component_file:`fatfsgen.py<fatfs/fatfsgen.py>`), i.e. it can generate the folder structure on the host based on the FatFs image.
|
||||
It is a reverse tool of (:component_file:`fatfsgen.py <fatfs/fatfsgen.py>`), i.e., it can generate the folder structure on the host based on the FatFs image.
|
||||
|
||||
Usage::
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
Generating and Parsing FATFS on Host
|
||||
====================================
|
||||
|
||||
This chapter is intended mainly for developers of Python tools :component_file:`fatfsgen.py<fatfs/fatfsgen.py>` and :component_file:`fatfsparse.py<fatfs/fatfsparse.py>`, and people with special interest in these tools and implementation of the FAT file system in ESP-IDF. If you are interested in using these tools, please refer to the user guide at :ref:`fatfs-partition-generator`.
|
||||
This chapter is intended mainly for developers of Python tools :component_file:`fatfsgen.py <fatfs/fatfsgen.py>` and :component_file:`fatfsparse.py <fatfs/fatfsparse.py>`, and people with special interest in these tools and implementation of the FAT file system in ESP-IDF. If you are interested in using these tools, please refer to the user guide at :ref:`fatfs-partition-generator`.
|
||||
|
||||
The FAT file system is composed of various logical units. The units are used to store general information about the filesystem, allocations, content of files and directories, and file's metadata. The tools `fatfsgen.py` and `fatfsparse.py` implement the FAT filesystem considering all these logical units and they can also support wear levelling.
|
||||
The FAT file system is composed of various logical units. The units are used to store general information about the filesystem, allocations, content of files and directories, and file's metadata. The tools ``fatfsgen.py`` and ``fatfsparse.py`` implement the FAT filesystem considering all these logical units and they can also support wear levelling.
|
||||
|
||||
|
||||
FAT Filesystem Generator/Parser Design
|
||||
@@ -27,12 +27,12 @@ This is the most general entity responsible for modeling the FAT file system. It
|
||||
Class WLFATFS
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The class extends the functionality of the class **FATFS**. It implements an encapsulation of the filesystem into the wear levelling, by adding the "dummy" sector for balancing the load (a redundant sector, see the section :ref:`fafsgen-wear-levelling`), configuration sector and state sector. This class generates a binary FATFS partition with initialized wear levelling layer. For further analysis, it also provides an option to remove the wear levelling completely. The class is instantiated and invoked by the `wl_fatfsgen.py` script.
|
||||
The class extends the functionality of the class **FATFS**. It implements an encapsulation of the filesystem into the wear levelling, by adding the "dummy" sector for balancing the load (a redundant sector, see the section :ref:`fafsgen-wear-levelling`), configuration sector and state sector. This class generates a binary FATFS partition with initialized wear levelling layer. For further analysis, it also provides an option to remove the wear levelling completely. The class is instantiated and invoked by the ``wl_fatfsgen.py`` script.
|
||||
|
||||
Class BootSectorState
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The instance of this class contains the metadata required for building a boot sector and BPB (BIOS Parameter Block). Boot sector is basically implemented for the cross-platform compatibility, i.e. when ESP chipsets are connected with other platforms, it will always follow all the FAT filesystem standards. However, during partition generation, chip does not consume the data in this boot sector and all the other data needed, as the data is constant. In other words, changing the fields with the prefix "BS" is usually unnecessary and often does not work. If you want to add new features, please focus on fields with the prefix "BPB". Another critical role of this class is to share access to the metadata and binary image over the whole class system. Because of this, every class in the system can access this singleton.
|
||||
The instance of this class contains the metadata required for building a boot sector and BPB (BIOS Parameter Block). Boot sector is basically implemented for the cross-platform compatibility, i.e., when ESP chipsets are connected with other platforms, it will always follow all the FAT filesystem standards. However, during partition generation, chip does not consume the data in this boot sector and all the other data needed, as the data is constant. In other words, changing the fields with the prefix "BS" is usually unnecessary and often does not work. If you want to add new features, please focus on fields with the prefix "BPB". Another critical role of this class is to share access to the metadata and binary image over the whole class system. Because of this, every class in the system can access this singleton.
|
||||
|
||||
Class FATFSState
|
||||
^^^^^^^^^^^^^^^^
|
||||
@@ -42,11 +42,11 @@ The class **FATFSState** might be obsolete in the future, so developers could tr
|
||||
Class FAT
|
||||
^^^^^^^^^
|
||||
|
||||
FAT represents the File Allocation Table. FAT is a sequence of bytes spread over one or more sectors. The number of sectors is determined by the number of clusters and is calculated by the function `get_fat_sectors_count` in `utils.py`. The aim is to have as few sectors for one FAT as possible when you refer to every physical cluster in the file system. The FAT works as follows: For every physical cluster at ``i * some_constant`` address, FAT contains an entry at the ``i``-th location which represents next address of the clusters in the file chain. Each version of the FAT file system uses a different size for FAT entries. FAT12 uses 12 bits per entry, thus two entries span 3 bytes. FAT16 uses 16 bits per entry, thus one entry spans 2 bytes. FAT32 uses 32 bits per FAT entry, thus one entry spans 4 bytes. All entries are in little-endian byte order.
|
||||
FAT represents the File Allocation Table. FAT is a sequence of bytes spread over one or more sectors. The number of sectors is determined by the number of clusters and is calculated by the function ``get_fat_sectors_count`` in ``utils.py``. The aim is to have as few sectors for one FAT as possible when you refer to every physical cluster in the file system. The FAT works as follows: For every physical cluster at ``i * some_constant`` address, FAT contains an entry at the ``i``-th location which represents next address of the clusters in the file chain. Each version of the FAT file system uses a different size for FAT entries. FAT12 uses 12 bits per entry, thus two entries span 3 bytes. FAT16 uses 16 bits per entry, thus one entry spans 2 bytes. FAT32 uses 32 bits per FAT entry, thus one entry spans 4 bytes. All entries are in little-endian byte order.
|
||||
|
||||
All zeros at the ``i``-th entry indicates that corresponding cluster is free, while all ones at the ``i``-th entry indicates that corresponding cluster is occupied and is the last cluster in the file chain. The other number at ``ith``-th entry determines the next cluster's address in the file chain. These clusters are not necessarily stored adjacent to one another in the memory but instead are often fragmented throughout the data region.
|
||||
|
||||
For partition generation, the file is divided into several parts to fit the cluster, and the allocated chain is usually conquest. Notice that the structure allocation of the files is a linked list. Every cluster in the file allocation chain has entry in the FAT which refers to the next cluster or the information about the last cluster in the file chain. As mentioned, FAT12 uses 12 bits per FAT entry, thus it can sets a maximum number of 4096 clusters, as with 12 bits (one and a half bytes), it can enumerate 4096 clusters at most. However, because of other overhead, FAT12 can have 4085 clusters at most. Similarly, FAT16 can have 65525 clusters at most and for FAT32 can have 268435445 clusters at most (as practically only 28 bits out of 32 bits are used to denote each FAT entry). The current implementation doesn't allow forcibly redefining the FAT filesystem with less than 4085 clusters to FAT16, even though the documentation claims it is possible. Notice that it would be meaningless to define it vice versa, i.e. to FAT12 with more than 4085 clusters (which implies clusters on higher addresses being inaccessible).
|
||||
For partition generation, the file is divided into several parts to fit the cluster, and the allocated chain is usually conquest. Notice that the structure allocation of the files is a linked list. Every cluster in the file allocation chain has entry in the FAT which refers to the next cluster or the information about the last cluster in the file chain. As mentioned, FAT12 uses 12 bits per FAT entry, thus it can sets a maximum number of 4096 clusters, as with 12 bits (one and a half bytes), it can enumerate 4096 clusters at most. However, because of other overhead, FAT12 can have 4085 clusters at most. Similarly, FAT16 can have 65525 clusters at most and for FAT32 can have 268435445 clusters at most (as practically only 28 bits out of 32 bits are used to denote each FAT entry). The current implementation doesn't allow forcibly redefining the FAT filesystem with less than 4085 clusters to FAT16, even though the documentation claims it is possible. Notice that it would be meaningless to define it vice versa, i.e., to FAT12 with more than 4085 clusters (which implies clusters on higher addresses being inaccessible).
|
||||
|
||||
Class Cluster
|
||||
^^^^^^^^^^^^^
|
||||
@@ -76,16 +76,16 @@ Class Entry
|
||||
:align: center
|
||||
:alt: Tree diagram
|
||||
|
||||
`fatfsgen.py`
|
||||
-------------
|
||||
``fatfsgen.py``
|
||||
---------------
|
||||
|
||||
:component_file:`fatfsgen.py<fatfs/fatfsgen.py>` generates FAT file systems on the host.
|
||||
:component_file:`fatfsgen.py <fatfs/fatfsgen.py>` generates FAT file systems on the host.
|
||||
|
||||
`fatfsgen.py` recursively traverses the given folder's directory structure and adds files and/or directories inside the binary partition. Users can set if the script generates the partition with wear levelling support, long file names support, and support for preserving the modification date and time from the original folder on the host.
|
||||
``fatfsgen.py`` recursively traverses the given folder's directory structure and adds files and/or directories inside the binary partition. Users can set if the script generates the partition with wear levelling support, long file names support, and support for preserving the modification date and time from the original folder on the host.
|
||||
|
||||
The ``./fatfsgen.py Espressif`` command generates a simple binary partition with the default settings. Here ``Espressif`` is the local folder (containing files and/or sub-directories) from which binary image will be generated.
|
||||
The ``./fatfsgen.py Espressif`` command generates a simple binary partition with the default settings. Here ``Espressif`` is the local folder (containing files and/or sub-directories) from which binary image is generated.
|
||||
|
||||
There exist two scripts for that purpose, :component_file:`fatfsgen.py<fatfs/fatfsgen.py>` and :component_file:`wl_fatfsgen.py<fatfs/wl_fatfsgen.py>`. The difference is that `wl_fatfsgen.py` firstly uses `fatfsgen.py` for generating the partition and then initializes wear leveling.
|
||||
There exist two scripts for that purpose, :component_file:`fatfsgen.py <fatfs/fatfsgen.py>` and :component_file:`wl_fatfsgen.py <fatfs/wl_fatfsgen.py>`. The difference is that ``wl_fatfsgen.py`` firstly uses ``fatfsgen.py`` for generating the partition and then initializes wear leveling.
|
||||
|
||||
The script command line arguments are as follows::
|
||||
|
||||
@@ -98,12 +98,12 @@ The script command line arguments are as follows::
|
||||
--use_default_datetime - this flag forces using default dates and times (date == 0x2100, time == 0x0000), not using argument preserves the original filesystem metadata
|
||||
input_directory - required argument - name of the directory being encoded to the binary fat-compatibile partition
|
||||
|
||||
`fatfsparse.py`
|
||||
---------------
|
||||
``fatfsparse.py``
|
||||
-----------------
|
||||
|
||||
:component_file:`fatfsparse.py<fatfs/fatfsparse.py>` translates the binary image into the internal representation and generates the folder with equivalent content on the host. If user requires a parsing partition with initialized wear levelling, the fatfsparse.py will remove the wear levelling sectors using the function `remove_wl` provided by `wl_fatfsgen.py`. After the sectors are removed, parsing of the partition is the same as with no initial wear levelling.
|
||||
:component_file:`fatfsparse.py <fatfs/fatfsparse.py>` translates the binary image into the internal representation and generates the folder with equivalent content on the host. If user requires a parsing partition with initialized wear levelling, the ``fatfsparse.py`` will remove the wear levelling sectors using the function ``remove_wl`` provided by ``wl_fatfsgen.py``. After the sectors are removed, parsing of the partition is the same as with no initial wear levelling.
|
||||
|
||||
``./fatfsparse.py fatfs_image.img`` command yields the directory with the equivalent content as the binary data image `fatfs_image.img`.
|
||||
``./fatfsparse.py fatfs_image.img`` command yields the directory with the equivalent content as the binary data image ``fatfs_image.img``.
|
||||
|
||||
The script command line arguments are as follows::
|
||||
|
||||
@@ -120,7 +120,7 @@ Features
|
||||
FAT12/16
|
||||
^^^^^^^^
|
||||
|
||||
The supported FAT types are FAT12 and FAT16. For smaller partitions, FAT12 is sufficient. The type is detected according to the count of clusters, and cannot be changed by the user. If there are less than 4085 clusters, the selected type is FAT12 (FAT's entries have 12 bits). For partitions with 4085 to 65526 clusters (with 4085 and 65526 excluded), the type is FAT16. Currently `fatfsgen.py` or `fatfsparse.py` cannot process filesystems with more than 65525 clusters.
|
||||
The supported FAT types are FAT12 and FAT16. For smaller partitions, FAT12 is sufficient. The type is detected according to the count of clusters, and cannot be changed by the user. If there are less than 4085 clusters, the selected type is FAT12 (FAT's entries have 12 bits). For partitions with 4085 to 65526 clusters (with 4085 and 65526 excluded), the type is FAT16. Currently ``fatfsgen.py`` or ``fatfsparse.py`` cannot process filesystems with more than 65525 clusters.
|
||||
|
||||
.. _fafsgen-wear-levelling:
|
||||
|
||||
@@ -145,8 +145,8 @@ When a new image with WL support is generated, the script initialises few extra
|
||||
- reserved — 7x 32-bit words, set to 0
|
||||
- crc32 — crc32 of all the previous fields, including reserved
|
||||
|
||||
Also, the state sector will be appended by 16-byte `pos update record` for every value of `pos`. Thus, this record will help us to determine the position of the dummy sector.
|
||||
Since `erase + write` operation of the state sector is not atomic, we may lose the data if the power is cut off between "erase" and "write". However, two copies of the state are maintained to recover the state after the power outage. On each update, both copies are updated. Thus, after power outage, we can revert the original valid state.
|
||||
Also, the state sector will be appended by 16-byte ``pos update record`` for every value of ``pos``. Thus, this record will help us to determine the position of the dummy sector.
|
||||
Since ``erase + write`` operation of the state sector is not atomic, we may lose the data if the power is cut off between "erase" and "write". However, two copies of the state are maintained to recover the state after the power outage. On each update, both copies are updated. Thus, after power outage, we can revert the original valid state.
|
||||
|
||||
- The config sector: This sector contains the information about the partition used by the WL layer.
|
||||
- start_addr — start address of partition (always zero)
|
||||
@@ -162,10 +162,10 @@ When a new image with WL support is generated, the script initialises few extra
|
||||
2. Removing Wear Levelling:
|
||||
While removing WL records, we have to find the position of the dummy sector, and the original and valid orders of the partition (because traversing the dummy sector shuffles the partition). The script can remove other WL sectors from the partition. Steps to remove WL records are given below.
|
||||
|
||||
- Find the `pos`, position of the dummy sector, which will be determined by the number of `pos update records` in the state sector.
|
||||
- Find the ``pos``, position of the dummy sector, which will be determined by the number of ``pos update records`` in the state sector.
|
||||
- Create the new image by removing dummy sector and merging remaining sectors before and after dummy sector.
|
||||
- Then remove the WL state sectors and config sector which are placed at the end of the partition.
|
||||
- Reorder the new image to get its original order. `move_count` helps us to find the beginning of the partition. The partition will start at the position `end_of_partition - move_count`. Thus the beginning of the partition after removing WL sectors will be `partition[end_of_partition - (move_count*page_size)]`.
|
||||
- Reorder the new image to get its original order. ``move_count`` helps us to find the beginning of the partition. The partition will start at the position ``end_of_partition - move_count``. Thus the beginning of the partition after removing WL sectors will be ``partition[end_of_partition - (move_count*page_size)]``.
|
||||
|
||||
File Names Encoding
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
@@ -180,12 +180,12 @@ The SFN is mandatory for the implementation of file names. SFN refer to the 8.3
|
||||
0x000000: 46 49 4C 45 4E 41 4D 45 45 58 54 20 18 00 00 00 FILENAMEEXT.....
|
||||
0x000010: 21 00 21 00 00 00 00 00 21 00 02 00 1E 00 00 00 !.!.....!.......
|
||||
|
||||
The entry denotes the file with 8.3 file name ("FILENAME.EXT") __(0x00/00-0A)__ of size 0x1E = 30 bytes __(0x10/0x0C)__, with default times of modification and creation (0x0021) __(0x10/00,02 and 08)__. The relevant cluster for the file is located at __0x02 (0x10/0A)__. Please notice that a character is encoded using one byte (e.g. __0x46 == 'F'__)
|
||||
The entry denotes the file with 8.3 file name ("FILENAME.EXT") __(0x00/00-0A)__ of size 0x1E = 30 bytes __(0x10/0x0C)__, with default times of modification and creation (0x0021) __(0x10/00,02 and 08)__. The relevant cluster for the file is located at __0x02 (0x10/0A)__. Please notice that a character is encoded using one byte (e.g., __0x46 == 'F'__)
|
||||
|
||||
Long File Names (LFN)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The LFN supports 255 characters excluding the trailing `NULL`. The LFN supports any character as short file names with an additional period (`.`) and the following special characters: `+ , ; = [ ]`. LFN uses UNICODE, so the character is encoded using 2 bytes.
|
||||
The LFN supports 255 characters excluding the trailing ``NULL``. The LFN supports any character as short file names with an additional period (``.``) and the following special characters: ``+ , ; = [ ]``. LFN uses UNICODE, so the character is encoded using 2 bytes.
|
||||
|
||||
The structure of one name encoded using LFN is as follows::
|
||||
|
||||
@@ -198,17 +198,17 @@ The structure of one name encoded using LFN is as follows::
|
||||
|
||||
The above example encodes a file name ``thisislongfile.txt``. The record is composed of multiple entries. The first entry contains metadata and is equivalent to the SFN entry. This entry might be final if the file name conforms to the 8.3 file name convention. In such scenarios, the SFN pattern is used. Otherwise, the generator adds various entries with the LFN structure above the SFN entry. These entries hold information about the file name and its checksum for consistency. Every LFN record can hold 13 characters (26 bytes). The file name is firstly cut into some amount of 13-character substrings and these are added above the SFN entry.
|
||||
|
||||
We add LFN entries in reversed order, so the first entry in the directory is the last part of the file name and the last is SFN entry. In the above example, we can see that the first entry contains text ``e.txt``, while another one contains the beginning of the name ``thisislongfil``. The first byte in LFN entries denotes an order or the sequence number (numbered from 1). To determine the first entry of the LFN, the first byte is masked with 0x40 (`first_byte =| 0x40`). The specification says that the last entry value will be ORed with 0x40 and it is the mark for the last entry. For example, when the record is the second and also the last in the LFN entry, its first byte is `0x42`.
|
||||
We add LFN entries in reversed order, so the first entry in the directory is the last part of the file name and the last is SFN entry. In the above example, we can see that the first entry contains text ``e.txt``, while another one contains the beginning of the name ``thisislongfil``. The first byte in LFN entries denotes an order or the sequence number (numbered from 1). To determine the first entry of the LFN, the first byte is masked with 0x40 (``first_byte =| 0x40``). The specification says that the last entry value will be ORed with 0x40 and it is the mark for the last entry. For example, when the record is the second and also the last in the LFN entry, its first byte is ``0x42``.
|
||||
|
||||
The LFN entry is signed at field **DIR_Attr** with value `ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID` (see the file long_filename_utils.py). The SFN entry (possibly also within LFN) contains either `ATTR_DIRECTORY` or `ATTR_ARCHIVE` in this field for directory or file respectively.
|
||||
The LFN entry is signed at field **DIR_Attr** with value ``ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID`` (see the file long_filename_utils.py). The SFN entry (possibly also within LFN) contains either ``ATTR_DIRECTORY`` or ``ATTR_ARCHIVE`` in this field for directory or file respectively.
|
||||
|
||||
The LFN entry is tagged at the field **DIR_NTRes** with the value `0x00`. This is a sign of the SFN entry in the LFN record, if the entry is a whole SFN record, the value is `0x18`. As you can see in the first example, the value at this field is `0x18`, because the name **"FILENAME.EXT"** fits the SFN. However, the recent example showing **"thisislongfile.txt"** has value `0x00` at field **DIR_NTRes** in the last entry, since it is a LFN. The SFN needs to be unique. For that purpose, the `fatfsgen.py` uses the first 6 characters from the file name, concatenating with `~` and with ID denoting the order of the name with the same prefix. The ID is between 0 to 127, which is the maximal amount of files with the same prefix.
|
||||
The LFN entry is tagged at the field **DIR_NTRes** with the value ``0x00``. This is a sign of the SFN entry in the LFN record, if the entry is a whole SFN record, the value is ``0x18``. As you can see in the first example, the value at this field is ``0x18``, because the name **"FILENAME.EXT"** fits the SFN. However, the recent example showing **"thisislongfile.txt"** has value ``0x00`` at field **DIR_NTRes** in the last entry, since it is a LFN. The SFN needs to be unique. For that purpose, the ``fatfsgen.py`` uses the first 6 characters from the file name, concatenating with ``~`` and with ID denoting the order of the name with the same prefix. The ID is between 0 to 127, which is the maximal amount of files with the same prefix.
|
||||
|
||||
Calculation of the checksum is described and implemented in the `utils.py` by function `lfn_checksum`. The `fatfsparse.py` assumes that the LFN entries might not be right next to each other, but it assumes the relative order is preserved. The approach is first to find the SFN belonging to some LFN record (using **DIR_NTRes** field). From then, the script starts to search by moving upwards to the beginning of the respective sector, until it finds the last entry in the LFN record (the one with the first half byte equal to 4). The entries are distinguished by their checksums. When finished, the file name can be composed.
|
||||
Calculation of the checksum is described and implemented in the ``utils.py`` by function ``lfn_checksum``. The ``fatfsparse.py`` assumes that the LFN entries might not be right next to each other, but it assumes the relative order is preserved. The approach is first to find the SFN belonging to some LFN record (using **DIR_NTRes** field). From then, the script starts to search by moving upwards to the beginning of the respective sector, until it finds the last entry in the LFN record (the one with the first half byte equal to 4). The entries are distinguished by their checksums. When finished, the file name can be composed.
|
||||
|
||||
Date and Time in FAT Filesystem
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The FAT filesystem protocol used by ESP-IDF does not preserve the date/time on the chips' media, so all the images extracted from the device have the same default timestamp for all the FAT-specified date-time fields (creation and the last modification timestamp as well as creation, last modification and last access dates).
|
||||
|
||||
There are a couple of fields in the SFN entry describing time, such as **DIR_CrtTime** and **DIR_WrtTime**. Some fields are ignored by the FAT implementation used by ESP-IDF (see the file `entry.py`). However, changes in the fields **DIR_WrtTime** and **DIR_WrtDate** are preserved in the chip. Both time and data entry are 16-bit, where the granularity of the time is 2 seconds.
|
||||
There are a couple of fields in the SFN entry describing time, such as **DIR_CrtTime** and **DIR_WrtTime**. Some fields are ignored by the FAT implementation used by ESP-IDF (see the file ``entry.py``). However, changes in the fields **DIR_WrtTime** and **DIR_WrtDate** are preserved in the chip. Both time and data entry are 16-bit, where the granularity of the time is 2 seconds.
|
||||
|
||||
@@ -13,7 +13,8 @@ This section contains reference of the high-level storage APIs. They are based o
|
||||
- :doc:`Wear Levelling <wear-levelling>` library implements a flash translation layer (FTL) suitable for SPI NOR Flash. It is used as a container for FAT partitions in Flash.
|
||||
|
||||
.. note::
|
||||
It's suggested to use high-level APIs (``esp_partition`` or file system) instead of low-level driver APIs to access the SPI NOR Flash.
|
||||
|
||||
It is suggested to use high-level APIs (``esp_partition`` or file system) instead of low-level driver APIs to access the SPI NOR Flash.
|
||||
|
||||
Due to the restriction of NOR Flash and ESP hardware, accessing the main flash will affect the performance of the whole system. See :doc:`SPI Flash Documents </api-reference/peripherals/spi_flash/index>` to learn more about the limitations.
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ Overview
|
||||
|
||||
This guide provides an overview of the NVS Encryption feature. NVS encryption helps to achieve secure storage on the device flash memory.
|
||||
|
||||
Data stored in NVS partitions can be encrypted using XTS-AES in the manner similar to the one mentioned in disk encryption standard IEEE P1619. For the purpose of encryption, each entry is treated as one `sector` and relative address of the entry (w.r.t. partition-start) is fed to the encryption algorithm as `sector-number`.
|
||||
Data stored in NVS partitions can be encrypted using XTS-AES in the manner similar to the one mentioned in disk encryption standard IEEE P1619. For the purpose of encryption, each entry is treated as one `sector` and relative address of the entry (w.r.t., partition-start) is fed to the encryption algorithm as `sector-number`.
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
NVS Encryption can be facilitated by enabling :ref:`CONFIG_NVS_ENCRYPTION` and :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` -> ``CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC`` or ``CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC`` depending on the scheme to be used.
|
||||
NVS Encryption can be facilitated by enabling :ref:`CONFIG_NVS_ENCRYPTION` and :ref:`CONFIG_NVS_SEC_KEY_PROTECTION_SCHEME` > ``CONFIG_NVS_SEC_KEY_PROTECT_USING_FLASH_ENC`` or ``CONFIG_NVS_SEC_KEY_PROTECT_USING_HMAC`` depending on the scheme to be used.
|
||||
|
||||
|
||||
NVS Encryption: Flash Encryption-based Scheme
|
||||
@@ -49,9 +49,11 @@ The XTS encryption keys in the :ref:`nvs_encr_key_partition` can be generated in
|
||||
|
||||
* Then the API function automatically generates and stores the NVS keys in that partition by making use of the :cpp:func:`nvs_flash_generate_keys` API function provided by :component_file:`nvs_flash/include/nvs_flash.h`. New keys are generated and stored only when the respective key partition is empty. The same key partition can then be used to read the security configurations for initializing a custom encrypted NVS partition with help of :cpp:func:`nvs_flash_secure_init_partition`.
|
||||
|
||||
* The API functions :cpp:func:`nvs_flash_secure_init` and :cpp:func:`nvs_flash_secure_init_partition` do not generate the keys internally. When these API functions are used for initializing encrypted NVS partitions, the keys can be generated after startup using the :cpp:func:`nvs_flash_generate_keys` API function provided by ``nvs_flash.h``. The API function will then write those keys onto the key-partition in encrypted form.
|
||||
* The API functions :cpp:func:`nvs_flash_secure_init` and :cpp:func:`nvs_flash_secure_init_partition` do not generate the keys internally. When these API functions are used for initializing encrypted NVS partitions, the keys can be generated after startup using the :cpp:func:`nvs_flash_generate_keys` API function provided by ``nvs_flash.h``. The API function then writes those keys onto the key-partition in encrypted form.
|
||||
|
||||
.. note:: Please note that ``nvs_keys`` partition must be completely erased before you start the application in this approach. Otherwise the application may generate :c:macro:`ESP_ERR_NVS_CORRUPT_KEY_PART` error code assuming that ``nvs_keys`` partition is not empty and contains malformatted data. You can use the following command for this:
|
||||
.. note::
|
||||
|
||||
Please note that ``nvs_keys`` partition must be completely erased before you start the application in this approach. Otherwise the application may generate :c:macro:`ESP_ERR_NVS_CORRUPT_KEY_PART` error code assuming that ``nvs_keys`` partition is not empty and contains malformatted data. You can use the following command for this:
|
||||
::
|
||||
|
||||
parttool.py --port PORT --partition-table-file=PARTITION_TABLE_FILE --partition-table-offset PARTITION_TABLE_OFFSET erase_partition --partition-type=data --partition-subtype=nvs_keys
|
||||
@@ -81,7 +83,7 @@ It is possible for an application to use different keys for different NVS partit
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
NVS Encryption: HMAC peripheral-based Scheme
|
||||
NVS Encryption: HMAC Peripheral-Based Scheme
|
||||
--------------------------------------------
|
||||
|
||||
In this scheme, the XTS keys required for NVS encryption are derived from an HMAC key programmed in eFuse with the purpose :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`. Since the encryption keys are derived at runtime, they are not stored anywhere in the flash. Thus, this feature does not require a separate :ref:`nvs_encr_key_partition`.
|
||||
@@ -92,13 +94,13 @@ It is possible for an application to use different keys for different NVS partit
|
||||
|
||||
.. important::
|
||||
|
||||
Please take note that this scheme will use one eFuse block for storing the HMAC key required for deriving the encryption keys.
|
||||
Please take note that this scheme uses one eFuse block for storing the HMAC key required for deriving the encryption keys.
|
||||
|
||||
- When NVS encryption is enabled, the :cpp:func:`nvs_flash_init` API function can be used to initialize the encrypted default NVS partition. The API function first checks whether an HMAC key is present at :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID`.
|
||||
|
||||
.. note::
|
||||
|
||||
The valid range for the config :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID` is from ``0`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY0`) to ``5`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY5`). By default, the config is set to ``6`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY_MAX`), which will have to configured before building the user application.
|
||||
The valid range for the config :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID` is from ``0`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY0`) to ``5`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY5`). By default, the config is set to ``6`` (:cpp:enumerator:`hmac_key_id_t::HMAC_KEY_MAX`), which have to be configured before building the user application.
|
||||
|
||||
- If no key is found, a key is generated internally and stored at the eFuse block specified at :ref:`CONFIG_NVS_SEC_HMAC_EFUSE_KEY_ID`.
|
||||
- If a key is found with the purpose :cpp:enumerator:`esp_efuse_purpose_t::ESP_EFUSE_KEY_PURPOSE_HMAC_UP`, the same is used for the derivation of the XTS encryption keys.
|
||||
@@ -190,7 +192,7 @@ The component :component:`nvs_sec_provider` stores all the implementation-specif
|
||||
|
||||
.. only:: SOC_HMAC_SUPPORTED
|
||||
|
||||
This component offers factory functions with which a particular security scheme can be registered without having to worry about the APIs to generate and read the encryption keys (e.g. :cpp:func:`nvs_sec_provider_register_hmac`). Refer to the :example:`security/nvs_encryption_hmac` example for API usage.
|
||||
This component offers factory functions with which a particular security scheme can be registered without having to worry about the APIs to generate and read the encryption keys (e.g., :cpp:func:`nvs_sec_provider_register_hmac`). Refer to the :example:`security/nvs_encryption_hmac` example for API usage.
|
||||
|
||||
|
||||
API Reference
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Non-volatile Storage Library
|
||||
Non-Volatile Storage Library
|
||||
============================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
@@ -60,7 +60,8 @@ There are the following functions available:
|
||||
- :cpp:func:`nvs_entry_info` returns information about each key-value pair
|
||||
|
||||
In general, all iterators obtained via :cpp:func:`nvs_entry_find` have to be released using :cpp:func:`nvs_release_iterator`, which also tolerates ``NULL`` iterators.
|
||||
:cpp:func:`nvs_entry_find` and :cpp:func:`nvs_entry_next` will set the given iterator to ``NULL`` or a valid iterator in all cases except a parameter error occured (i.e., return ``ESP_ERR_NVS_NOT_FOUND``). In case of a parameter error, the given iterator will not be modified. Hence, it is best practice to initialize the iterator to ``NULL`` before calling :cpp:func:`nvs_entry_find` to avoid complicated error checking before releasing the iterator.
|
||||
|
||||
:cpp:func:`nvs_entry_find` and :cpp:func:`nvs_entry_next` set the given iterator to ``NULL`` or a valid iterator in all cases except a parameter error occured (i.e., return ``ESP_ERR_NVS_NOT_FOUND``). In case of a parameter error, the given iterator will not be modified. Hence, it is best practice to initialize the iterator to ``NULL`` before calling :cpp:func:`nvs_entry_find` to avoid complicated error checking before releasing the iterator.
|
||||
|
||||
|
||||
Security, Tampering, and Robustness
|
||||
@@ -102,7 +103,7 @@ You can find code examples in the :example:`storage` directory of ESP-IDF exampl
|
||||
|
||||
The value checked in this example holds the number of the {IDF_TARGET_NAME} module restarts. The value's function as a counter is only possible due to its storing in NVS.
|
||||
|
||||
The example also shows how to check if a read / write operation was successful, or if a certain value has not been initialized in NVS. The diagnostic procedure is provided in plain text to help you track the program flow and capture any issues on the way.
|
||||
The example also shows how to check if a read/write operation was successful, or if a certain value has not been initialized in NVS. The diagnostic procedure is provided in plain text to help you track the program flow and capture any issues on the way.
|
||||
|
||||
:example:`storage/nvs_rw_blob`
|
||||
|
||||
@@ -111,7 +112,7 @@ You can find code examples in the :example:`storage` directory of ESP-IDF exampl
|
||||
* value - tracks the number of the {IDF_TARGET_NAME} module soft and hard restarts.
|
||||
* blob - contains a table with module run times. The table is read from NVS to dynamically allocated RAM. A new run time is added to the table on each manually triggered soft restart, and then the added run time is written to NVS. Triggering is done by pulling down GPIO0.
|
||||
|
||||
The example also shows how to implement the diagnostic procedure to check if the read / write operation was successful.
|
||||
The example also shows how to implement the diagnostic procedure to check if the read/write operation was successful.
|
||||
|
||||
:example:`storage/nvs_rw_value_cxx`
|
||||
|
||||
@@ -144,7 +145,7 @@ Erasing
|
||||
Non-erased key-value pairs are being moved into another page so that the current page can be erased. This is a transient state, i.e., page should never stay in this state at the time when any API call returns. In case of a sudden power off, the move-and-erase process will be completed upon the next power-on.
|
||||
|
||||
Corrupted
|
||||
Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. The corresponding flash sector will not be erased immediately and will be kept along with sectors in *uninitialized* state for later use. This may be useful for debugging.
|
||||
Page header contains invalid data, and further parsing of page data was canceled. Any items previously written into this page will not be accessible. The corresponding flash sector will not be erased immediately and will be kept along with sectors in **uninitialized** state for later use. This may be useful for debugging.
|
||||
|
||||
Mapping from flash sectors to logical pages does not have any particular order. The library will inspect sequence numbers of pages found in each flash sector and organize pages in a list based on these numbers.
|
||||
|
||||
@@ -281,7 +282,7 @@ Data
|
||||
- CRC32
|
||||
(Only for strings and blobs.) Checksum calculated over all bytes of data.
|
||||
|
||||
Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. The `Span` field of the first entry indicates how many entries are used.
|
||||
Variable length values (strings and blobs) are written into subsequent entries, 32 bytes per entry. The ``Span`` field of the first entry indicates how many entries are used.
|
||||
|
||||
|
||||
Namespaces
|
||||
@@ -305,7 +306,7 @@ As mentioned above, each key-value pair belongs to one of the namespaces. Namesp
|
||||
Item Hash List
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
To reduce the number of reads from flash memory, each member of the Page class maintains a list of pairs: item index; item hash. This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, `Page::findItem` first performs a search for the item hash in the hash list. This gives the item index within the page if such an item exists. Due to a hash collision, it is possible that a different item will be found. This is handled by falling back to iteration over items in flash.
|
||||
To reduce the number of reads from flash memory, each member of the Page class maintains a list of pairs: item index; item hash. This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, `Page::findItem` first performs a search for the item hash in the hash list. This gives the item index within the page if such an item exists. Due to a hash collision, it is possible that a different item is found. This is handled by falling back to iteration over items in flash.
|
||||
|
||||
Each node in the hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace, key name, and ChunkIndex. CRC32 is used for calculation; the result is truncated to 24 bits. To reduce the overhead for storing 32-bit entries in a linked list, the list is implemented as a double-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and a 32-bit count field. The minimum amount of extra RAM usage per page is therefore 128 bytes; maximum is 640 bytes.
|
||||
|
||||
|
||||
@@ -36,13 +36,13 @@ An example which combines the SDMMC driver with the FATFS library is provided in
|
||||
|
||||
.. only:: SOC_SDMMC_HOST_SUPPORTED
|
||||
|
||||
Protocol layer API
|
||||
Protocol Layer API
|
||||
------------------
|
||||
|
||||
The protocol layer is given the :cpp:class:`sdmmc_host_t` structure. This structure describes the SD/MMC host driver, lists its capabilities, and provides pointers to functions of the driver. The protocol layer stores card-specific information in the :cpp:class:`sdmmc_card_t` structure. When sending commands to the SD/MMC host driver, the protocol layer uses the :cpp:class:`sdmmc_command_t` structure to describe the command, arguments, expected return values, and data to transfer if there is any.
|
||||
|
||||
|
||||
Using API with SD memory cards
|
||||
Using API with SD Memory Cards
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. To initialize the host, call the host driver functions, e.g., :cpp:func:`sdmmc_host_init`, :cpp:func:`sdmmc_host_init_slot`.
|
||||
@@ -51,7 +51,7 @@ An example which combines the SDMMC driver with the FATFS library is provided in
|
||||
4. If the card is not used anymore, call the host driver function - e.g., :cpp:func:`sdmmc_host_deinit` - to disable the host peripheral and free the resources allocated by the driver.
|
||||
|
||||
|
||||
Using API with eMMC chips
|
||||
Using API with eMMC Chips
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
From the protocol layer's perspective, eMMC memory chips behave exactly like SD memory cards. Even though eMMCs are chips and do not have a card form factor, the terminology for SD cards can still be applied to eMMC due to the similarity of the protocol (`sdmmc_card_t`, `sdmmc_card_init`). Note that eMMC chips cannot be used over SPI, which makes them incompatible with the SD SPI host driver.
|
||||
@@ -59,7 +59,7 @@ An example which combines the SDMMC driver with the FATFS library is provided in
|
||||
To initialize eMMC memory and perform read/write operations, follow the steps listed for SD cards in the previous section.
|
||||
|
||||
|
||||
Using API with SDIO cards
|
||||
Using API with SDIO Cards
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Initialization and the probing process are the same as with SD memory cards. The only difference is in data transfer commands in SDIO mode.
|
||||
@@ -99,13 +99,13 @@ An example which combines the SDMMC driver with the FATFS library is provided in
|
||||
|
||||
There is a component ESSL (ESP Serial Slave Link) to use if you are communicating with an ESP32 SDIO slave. See :doc:`/api-reference/protocols/esp_serial_slave_link` and example :example:`peripherals/sdio/host`.
|
||||
|
||||
Combo (memory + IO) cards
|
||||
Combo (Memory + IO) Cards
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The driver does not support SD combo cards. Combo cards are treated as IO cards.
|
||||
|
||||
|
||||
Thread safety
|
||||
Thread Safety
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Most applications need to use the protocol layer only in one task. For this reason, the protocol layer does not implement any kind of locking on the :cpp:class:`sdmmc_card_t` structure, or when accessing SDMMC or SD SPI host drivers. Such locking is usually implemented on a higher layer, e.g., in the filesystem driver.
|
||||
|
||||
@@ -15,15 +15,15 @@ Notes
|
||||
- It is not a real-time stack. One write operation might take much longer than another.
|
||||
- For now, it does not detect or handle bad blocks.
|
||||
- SPIFFS is able to reliably utilize only around 75% of assigned partition space.
|
||||
- When the filesystem is running out of space, the garbage collector is trying to find free space by scanning the filesystem multiple times, which can take up to several seconds per write function call, depending on required space. This is caused by the SPIFFS design and the issue has been reported multiple times (e.g. `here <https://github.com/espressif/esp-idf/issues/1737>`_) and in the official `SPIFFS github repository <https://github.com/pellepl/spiffs/issues/>`_. The issue can be partially mitigated by the `SPIFFS configuration <https://github.com/pellepl/spiffs/wiki/Configure-spiffs>`_.
|
||||
- When the filesystem is running out of space, the garbage collector is trying to find free space by scanning the filesystem multiple times, which can take up to several seconds per write function call, depending on required space. This is caused by the SPIFFS design and the issue has been reported multiple times (e.g., `here <https://github.com/espressif/esp-idf/issues/1737>`_) and in the official `SPIFFS github repository <https://github.com/pellepl/spiffs/issues/>`_. The issue can be partially mitigated by the `SPIFFS configuration <https://github.com/pellepl/spiffs/wiki/Configure-spiffs>`_.
|
||||
- Deleting a file does not always remove the whole file, which leaves unusable sections throughout the filesystem.
|
||||
- When the chip experiences a power loss during a file system operation it could result in SPIFFS corruption. However the file system still might be recovered via ``esp_spiffs_check`` function. More details in the official SPIFFS `FAQ <https://github.com/pellepl/spiffs/wiki/FAQ>`_.
|
||||
|
||||
Tools
|
||||
-----
|
||||
|
||||
spiffsgen.py
|
||||
^^^^^^^^^^^^
|
||||
``spiffsgen.py``
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
:component_file:`spiffsgen.py<spiffs/spiffsgen.py>` is a write-only Python SPIFFS implementation used to create filesystem images from the contents of a host folder. To use ``spiffsgen.py``, open Terminal and run::
|
||||
|
||||
@@ -47,9 +47,9 @@ Aside from invoking the ``spiffsgen.py`` standalone by manually running it from
|
||||
|
||||
spiffs_create_partition_image(<partition> <base_dir> [FLASH_IN_PROJECT] [DEPENDS dep dep dep...])
|
||||
|
||||
This is more convenient as the build configuration is automatically passed to the tool, ensuring that the generated image is valid for that build. An example of this is while the *image_size* is required for the standalone invocation, only the *partition* name is required when using ``spiffs_create_partition_image`` -- the image size is automatically obtained from the project's partition table.
|
||||
This is more convenient as the build configuration is automatically passed to the tool, ensuring that the generated image is valid for that build. An example of this is while the **image_size** is required for the standalone invocation, only the **partition** name is required when using ``spiffs_create_partition_image`` -- the image size is automatically obtained from the project's partition table.
|
||||
|
||||
``spiffs_create_partition_image`` must be called from one of the component CMakeLists.txt files.
|
||||
``spiffs_create_partition_image`` must be called from one of the component ``CMakeLists.txt`` files.
|
||||
|
||||
Optionally, users can opt to have the image automatically flashed together with the app binaries, partition tables, etc. on ``idf.py flash`` by specifying ``FLASH_IN_PROJECT``. For example::
|
||||
|
||||
@@ -65,8 +65,8 @@ There are cases where the contents of the base directory itself is generated at
|
||||
|
||||
For an example, see :example:`storage/spiffsgen`.
|
||||
|
||||
mkspiffs
|
||||
^^^^^^^^
|
||||
``mkspiffs``
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Another tool for creating SPIFFS partition images is `mkspiffs <https://github.com/igrr/mkspiffs>`_. Similar to ``spiffsgen.py``, it can be used to create an image from a given folder and then flash that image using ``esptool.py``
|
||||
|
||||
@@ -85,7 +85,7 @@ To flash the image onto {IDF_TARGET_NAME} at offset 0x110000, run::
|
||||
|
||||
python esptool.py --chip {IDF_TARGET_PATH_NAME} --port [port] --baud [baud] write_flash -z 0x110000 spiffs.bin
|
||||
|
||||
Notes on which SPIFFS tool to use
|
||||
Notes on Which SPIFFS Tool to Use
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The two tools presented above offer very similar functionality. However, there are reasons to prefer one over the other, depending on the use case.
|
||||
@@ -100,7 +100,7 @@ Use ``mkspiffs`` in the following cases:
|
||||
1. If you need to unpack SPIFFS images in addition to image generation. For now, it is not possible with ``spiffsgen.py``.
|
||||
2. If you have an environment where a Python interpreter is not available, but a host compiler is available. Otherwise, a pre-compiled ``mkspiffs`` binary can do the job. However, there is no build system integration for ``mkspiffs`` and the user has to do the corresponding work: compiling ``mkspiffs`` during build (if a pre-compiled binary is not used), creating build rules/targets for the output files, passing proper parameters to the tool, etc.
|
||||
|
||||
See also
|
||||
See Also
|
||||
--------
|
||||
|
||||
- :doc:`Partition Table documentation <../../api-guides/partition-tables>`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Virtual filesystem component
|
||||
Virtual Filesystem Component
|
||||
============================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
@@ -10,10 +10,10 @@ Virtual filesystem (VFS) component provides a unified interface for drivers whic
|
||||
|
||||
This component allows C library functions, such as fopen and fprintf, to work with FS drivers. At a high level, each FS driver is associated with some path prefix. When one of C library functions needs to open a file, the VFS component searches for the FS driver associated with the file path and forwards the call to that driver. VFS also forwards read, write, and other calls for the given file to the same FS driver.
|
||||
|
||||
For example, one can register a FAT filesystem driver with the ``/fat`` prefix and call ``fopen("/fat/file.txt", "w")``. The VFS component will then call the function ``open`` of the FAT driver and pass the argument ``/file.txt`` to it together with appropriate mode flags. All subsequent calls to C library functions for the returned ``FILE*`` stream will also be forwarded to the FAT driver.
|
||||
For example, one can register a FAT filesystem driver with the ``/fat`` prefix and call ``fopen("/fat/file.txt", "w")``. Then the VFS component calls the function ``open`` of the FAT driver and pass the argument ``/file.txt`` to it together with appropriate mode flags. All subsequent calls to C library functions for the returned ``FILE*`` stream will also be forwarded to the FAT driver.
|
||||
|
||||
|
||||
FS registration
|
||||
FS Registration
|
||||
---------------
|
||||
|
||||
To register an FS driver, an application needs to define an instance of the :cpp:type:`esp_vfs_t` structure and populate it with function pointers to FS APIs:
|
||||
@@ -65,7 +65,7 @@ Case 2: API functions are declared with an extra context pointer (the FS driver
|
||||
myfs_t* myfs_inst2 = myfs_mount(partition2->offset, partition2->size);
|
||||
ESP_ERROR_CHECK(esp_vfs_register("/data2", &myfs, myfs_inst2));
|
||||
|
||||
Synchronous input/output multiplexing
|
||||
Synchronous Input/Output Multiplexing
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Synchronous input/output multiplexing by :cpp:func:`select` is supported in the VFS component. The implementation works in the following way.
|
||||
@@ -82,7 +82,7 @@ Synchronous input/output multiplexing by :cpp:func:`select` is supported in the
|
||||
|
||||
6. The :cpp:func:`select` call ends and returns the appropriate results.
|
||||
|
||||
Non-socket VFS drivers
|
||||
Non-Socket VFS Drivers
|
||||
""""""""""""""""""""""
|
||||
|
||||
If you want to use :cpp:func:`select` with a file descriptor belonging to a non-socket VFS driver, then you need to register the driver with functions :cpp:func:`start_select` and :cpp:func:`end_select` similarly to the following example:
|
||||
@@ -101,6 +101,7 @@ If you want to use :cpp:func:`select` with a file descriptor belonging to a non-
|
||||
:cpp:func:`end_select` is called to stop/deinitialize/free the environment which was setup by :cpp:func:`start_select`.
|
||||
|
||||
.. note::
|
||||
|
||||
:cpp:func:`end_select` might be called without a previous :cpp:func:`start_select` call in some rare circumstances. :cpp:func:`end_select` should fail gracefully if this is the case (i.e., should not crash but return an error instead).
|
||||
|
||||
Please refer to the reference implementation for the UART peripheral in :component_file:`vfs/vfs_uart.c` and most particularly to the functions :cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select`, and :cpp:func:`uart_end_select` for more information.
|
||||
@@ -111,7 +112,7 @@ Please check the following examples that demonstrate the use of :cpp:func:`selec
|
||||
- :example:`system/select`
|
||||
|
||||
|
||||
Socket VFS drivers
|
||||
Socket VFS Drivers
|
||||
""""""""""""""""""
|
||||
|
||||
A socket VFS driver is using its own internal implementation of :cpp:func:`select` and non-socket VFS drivers notify it upon read/write/error conditions.
|
||||
@@ -131,7 +132,7 @@ A socket VFS driver needs to be registered with the following functions defined:
|
||||
|
||||
:cpp:func:`socket_select` is the internal implementation of :cpp:func:`select` for the socket driver. It works only with file descriptors belonging to the socket VFS.
|
||||
|
||||
:cpp:func:`get_socket_select_semaphore` returns the signalization object (semaphore) which will be used in non-socket drivers to stop the waiting in :cpp:func:`socket_select`.
|
||||
:cpp:func:`get_socket_select_semaphore` returns the signalization object (semaphore) which is used in non-socket drivers to stop the waiting in :cpp:func:`socket_select`.
|
||||
|
||||
:cpp:func:`stop_socket_select` call is used to stop the waiting in :cpp:func:`socket_select` by passing the object returned by :cpp:func:`get_socket_select_semaphore`.
|
||||
|
||||
@@ -157,7 +158,7 @@ Then:
|
||||
|
||||
- FS 1 will be used when opening a file called ``/data/log.txt``
|
||||
- FS 2 will be used when opening a file called ``/data/static/index.html``
|
||||
- Even if ``/index.html"`` does not exist in FS 2, FS 1 will *not* be searched for ``/static/index.html``.
|
||||
- Even if ``/index.html"`` does not exist in FS 2, FS 1 will **not** be searched for ``/static/index.html``.
|
||||
|
||||
As a general rule, mount point names must start with the path separator (``/``) and must contain at least one character after path separator. However, an empty mount point name is also supported and might be used in cases when an application needs to provide a "fallback" filesystem or to override VFS functionality altogether. Such filesystem will be used if no prefix matches the path given.
|
||||
|
||||
@@ -173,18 +174,18 @@ When opening files, the FS driver receives only relative paths to files. For exa
|
||||
VFS does not impose any limit on total file path length, but it does limit the FS path prefix to ``ESP_VFS_PATH_MAX`` characters. Individual FS drivers may have their own filename length limitations.
|
||||
|
||||
|
||||
File descriptors
|
||||
File Descriptors
|
||||
----------------
|
||||
|
||||
File descriptors are small positive integers from ``0`` to ``FD_SETSIZE - 1``, where ``FD_SETSIZE`` is defined in newlib's ``sys/types.h``. The largest file descriptors (configured by ``CONFIG_LWIP_MAX_SOCKETS``) are reserved for sockets. The VFS component contains a lookup-table called ``s_fd_table`` for mapping global file descriptors to VFS driver indexes registered in the ``s_vfs`` array.
|
||||
|
||||
|
||||
Standard IO streams (stdin, stdout, stderr)
|
||||
Standard IO Streams (stdin, stdout, stderr)
|
||||
-------------------------------------------
|
||||
|
||||
If the menuconfig option ``UART for console output`` is not set to ``None``, then ``stdin``, ``stdout``, and ``stderr`` are configured to read from, and write to, a UART. It is possible to use UART0 or UART1 for standard IO. By default, UART0 is used with 115200 baud rate; TX pin is GPIO1; RX pin is GPIO3. These parameters can be changed in menuconfig.
|
||||
|
||||
Writing to ``stdout`` or ``stderr`` will send characters to the UART transmit FIFO. Reading from ``stdin`` will retrieve characters from the UART receive FIFO.
|
||||
Writing to ``stdout`` or ``stderr`` sends characters to the UART transmit FIFO. Reading from ``stdin`` retrieves characters from the UART receive FIFO.
|
||||
|
||||
By default, VFS uses simple functions for reading from and writing to UART. Writes busy-wait until all data is put into UART FIFO, and reads are non-blocking, returning only the data present in the FIFO. Due to this non-blocking read behavior, higher level C library calls, such as ``fscanf("%d\n", &var);``, might not have desired results.
|
||||
|
||||
@@ -193,7 +194,7 @@ Applications which use the UART driver can instruct VFS to use the driver's inte
|
||||
VFS also provides an optional newline conversion feature for input and output. Internally, most applications send and receive lines terminated by the LF (''\n'') character. Different terminal programs may require different line termination, such as CR or CRLF. Applications can configure this separately for input and output either via menuconfig, or by calls to the functions ``esp_vfs_dev_uart_port_set_rx_line_endings`` and ``esp_vfs_dev_uart_port_set_tx_line_endings``.
|
||||
|
||||
|
||||
Standard streams and FreeRTOS tasks
|
||||
Standard Streams and FreeRTOS Tasks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``FILE`` objects for ``stdin``, ``stdout``, and ``stderr`` are shared between all FreeRTOS tasks, but the pointers to these objects are stored in per-task ``struct _reent``.
|
||||
@@ -212,7 +213,7 @@ The ``__getreent()`` function returns a per-task pointer to ``struct _reent`` in
|
||||
Such a design has the following consequences:
|
||||
|
||||
- It is possible to set ``stdin``, ``stdout``, and ``stderr`` for any given task without affecting other tasks, e.g., by doing ``stdin = fopen("/dev/uart/1", "r")``.
|
||||
- Closing default ``stdin``, ``stdout``, or ``stderr`` using ``fclose`` will close the ``FILE`` stream object, which will affect all other tasks.
|
||||
- Closing default ``stdin``, ``stdout``, or ``stderr`` using ``fclose`` closes the ``FILE`` stream object, which will affect all other tasks.
|
||||
- To change the default ``stdin``, ``stdout``, ``stderr`` streams for new tasks, modify ``_GLOBAL_REENT->_stdin`` (``_stdout``, ``_stderr``) before creating the task.
|
||||
|
||||
Event fds
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.. include:: ../../../../components/wear_levelling/README.rst
|
||||
|
||||
See also
|
||||
See Also
|
||||
--------
|
||||
|
||||
- :doc:`FAT Filesystem <./fatfs>`
|
||||
@@ -11,7 +11,7 @@ Application Example
|
||||
|
||||
An example which combines the wear levelling driver with the FATFS library is provided in the :example:`storage/wear_levelling` directory. This example initializes the wear levelling driver, mounts FATFS partition, as well as writes and reads data from it using POSIX and C library APIs. See the :example_file:`storage/wear_levelling/README.md` file for more information.
|
||||
|
||||
High level API Reference
|
||||
High-Level API Reference
|
||||
------------------------
|
||||
|
||||
Header Files
|
||||
@@ -27,7 +27,7 @@ Functions
|
||||
:members:
|
||||
.. doxygenfunction:: esp_vfs_fat_spiflash_unmount_rw_wl
|
||||
|
||||
Mid level API Reference
|
||||
Mid-Level API Reference
|
||||
-----------------------
|
||||
|
||||
.. include-build-file:: inc/wear_levelling.inc
|
||||
|
||||
Reference in New Issue
Block a user