ESP32 Storage programming — различия между версиями

Материал из razgovorov.ru
Перейти к: навигация, поиск
(Partition table)
(Non Volatile Storage)
 
(не показано 13 промежуточных версий этого же участника)
Строка 41: Строка 41:
 
• esp_vfs_fat_register
 
• esp_vfs_fat_register
  
===Non Volatile Storage===
+
===[http://esp-idf.readthedocs.io/en/latest/api-reference/storage/nvs_flash.html Non Volatile Storage]===
Non volatile storage is memory that can be written to such that after a power off or
+
Энергонезависимое хранилище - это память, которая может быть записана так, чтобы после выключения или перезапуска, те же данные могут быть прочитаны из него снова без потерь. В рамках этих данных мы можем хранить конфигурационные и эксплуатационные значения для наших приложений. Например, мы можем сохранить сетевой SSID и пароль таким образом, чтобы когда устройство перезапускается, он знает, к какой сети подключиться, и пароль для представления.
restart, the same data can be read from it again without loss. It is preserved over a
 
restart. Within this data we can store configuration and operational values for our
 
applications. For example, we might store the network SSID and password such that
 
when the device is restarted, it know which network to connect to and the password to
 
present.
 
  
The storage is partitioned into named areas. For a given named area, we can then
+
Хранилище разделено на именованные области. Для данной именованной области мы можем сохранить и прочитать пару имя / значение в хранилище. Существуют функции getter / setter для большинства типов данных, включая целые числа с знаком и без знака, строки и двоичные данные.
write name/value pairs to the storage and also read name/value pairs. There are
 
getter/setter functions for most data types including signed and unsigned integers,
 
strings and blobs of data.
 
  
A named area is opened for access with a call to nvs_open(). The name of the area is
+
Именованная область открывается для доступа вызовом nvs_open (). Имя области передается как параметр. Нам возвращен логический «дескриптор», который мы впоследствии можем использовать для ссылки на эту область хранения. Как только мы получим дескриптор, мы можем записать и прочитать элементы именованных данных. Элементы данных ссылаются на имя ключа эффективно превращая область хранения в хэш-карту. Если мы изменим данные, выполнив функцию set, это не приведет к тому, что данные будут записаны в энергонезависимое хранилище. Вместо этого хранилище обновляется, когда мы вызываем nvs_commit (). Это зависит от внутренней реализации того, когда выполняется фактическое обновление, и это может произойти до nvs_commit (). Контракт заключается в том, что, когда мы возвращаемся из nvs_commit (), мы уверены, что все обновления обработаны. Когда мы выполнили все наши наборы и получили, мы должны вызвать nvs_close (), чтобы объявить, что мы больше не будем работать с хранилищем в это время, чтобы время выполнения могло очистить любые ресурсы, которые он мог открыть.
passed in as a parameter. We are returned a logical "handle" that we can subsequently
 
use to refer to this storage area. Once we have a handle, we can get/set items of
 
named data. The data items are referenced by a key name … effectively turning the
 
storage area into a hash map. If we change data by performing a set function, this
 
does not automatically cause the data to be written to the nonvolatile storage. Instead,
 
the storage is updated when we call nvs_commit(). It is up to the internal
 
implementation as to when the actual update is performed and it could happen prior to
 
nvs_commit(). The contract is that when we return from nvs_commit() then we are
 
assured that all updates have been processed. When we have done all our sets and
 
gets, we should call nvs_close() to declare that we are not going to work with storage
 
any more at this time so that the run-time can clean up any resources it may have
 
opened.
 
  
The details of the algorithms used to manage NVS are exposed in the documentation.
+
Детали алгоритмов, используемых для управления NVS, раскрываются в документации.
The high level intent of NVS is to store simple strings and integers and other flags as
+
Цель NVS на высоком уровне - хранить простые строки и целые числа и другие флаги, а не быть богатой структурой «файловой системы». В настоящее время дефрагментация не выполняется в хранилище.
opposed to be a rich "file system" like structure. There is currently no de-fragmentation
 
performed on the storage.
 
  
 
See also:
 
See also:
nvs_open
+
* [http://esp-idf.readthedocs.io/en/latest/api-reference/storage/nvs_flash.html?highlight=nvs_open#_CPPv28nvs_openPKc13nvs_open_modeP10nvs_handle nvs_open]
nvs_commit
+
* [http://esp-idf.readthedocs.io/en/latest/api-reference/storage/nvs_flash.html?highlight=nvs_open#_CPPv210nvs_commit10nvs_handle nvs_commit]
nvs_close
+
* [http://esp-idf.readthedocs.io/en/latest/api-reference/storage/nvs_flash.html?highlight=nvs_open#_CPPv29nvs_close10nvs_handle nvs_close]
  
 
===Virtual File System===
 
===Virtual File System===
The Virtual File System (VFS) is the architecture provided by the ESP-IDF that gives us
+
Виртуальная файловая система (VFS) - это архитектура, предоставляемая ESP-IDF, которая дает нам возможность сохранять и загружать данные из наших приложений с использованием ввода-вывода файловой системы.
the capability of saving and loading data from our applications using a file system I/O.
 
The VFS isn't tied to any one particular technology but is instead an architectural
 
abstraction used to provide the I/O interface to a variety of different implementations.
 
The key to the VFS is a data type called esp_vfs_t. This structure contains the
 
following:
 
• fd_offset –
 
• flags – Operational flags. Use ESP_VFS_FLAG_DEFAULT.
 
• close/close_p – Close a previously opened file.
 
• closedir/closedir_p – Close a previously opened directory.
 
• fstat/fstat_p – Get stats/details of a file.
 
• link/link_p – Create a new link to a file.
 
• lseek/lseek_p – Change the data pointer within a file.
 
• mkdir/mkdir_p – Create a new directory entry.
 
• open/open_p – Open a named file.
 
• opendir/opendir_p – Open a directory for reading.
 
• read/read_p – Read the contents of a file.
 
• readdir/readdir_p – Read a record from a directory.
 
• rename/rename_p – Rename a file.
 
• rmdir/rmdir_p – Delete a directory entry.
 
• seekdir/seekdir_p – Set the position of the next readdir().
 
• stat/stat_p – Get stats/details of a file.
 
• telldir/telldir_p – Return the current direction stream.
 
• unlink/unlink_p – Remove a file.
 
• write/write_p – Write into a file.
 
  
After populating the structure, we need to register our new virtual file system with a call
+
VFS не привязан к какой-либо одной конкретной технологии, а вместо этого является архитектурной абстракцией, используемой для обеспечения интерфейса ввода-вывода для множества различных реализаций.
to esp_vfs_register().
+
 
We need to be cognizant that the intended caller of file I/O expects a POSIX like environment.
+
Ключом к VFS является тип данных, называемый esp_vfs_t. Эта структура содержит следующее:
 +
 
 +
* fd_offset –
 +
* flags – Operational flags. Use ESP_VFS_FLAG_DEFAULT.
 +
* close/close_p – Close a previously opened file.
 +
* closedir/closedir_p – Close a previously opened directory.
 +
* fstat/fstat_p – Get stats/details of a file.
 +
* link/link_p – Create a new link to a file.
 +
* lseek/lseek_p – Change the data pointer within a file.
 +
* mkdir/mkdir_p – Create a new directory entry.
 +
* open/open_p – Open a named file.
 +
* opendir/opendir_p – Open a directory for reading.
 +
* read/read_p – Read the contents of a file.
 +
* readdir/readdir_p – Read a record from a directory.
 +
* rename/rename_p – Rename a file.
 +
* rmdir/rmdir_p – Delete a directory entry.
 +
* seekdir/seekdir_p – Set the position of the next readdir().
 +
* stat/stat_p – Get stats/details of a file.
 +
* telldir/telldir_p – Return the current direction stream.
 +
* unlink/unlink_p – Remove a file.
 +
* write/write_p – Write into a file.
 +
 
 +
После заполнения структуры нам необходимо зарегистрировать нашу новую виртуальную файловую систему с вызовом esp_vfs_register ().
 +
 
 +
Нам нужно знать, что предполагаемый вызывающий файл ввода-вывода ожидает среду, похожую на POSIX.
  
 
See also:
 
See also:
Строка 113: Строка 91:
 
• Virtual filesystem componen t
 
• Virtual filesystem componen t
  
===VFS Implementations===
+
====VFS Implementations====
Since the VFS provides an architectural model, we need to consider actual
+
Поскольку VFS предоставляет архитектурную модель, нам необходимо рассмотреть ее фактические реализации. По состоянию на 2016-11 реализаций пока нет. Первыми ожидаемыми реализациями будут файловые системы, хранящиеся во флэш-памяти. Они будут обеспечивать постоянное хранение данных через API файлов. Первыми кандидатами на реализацию являются FAT и/или SPIFFS.
implementations of it. As of 2016-11, none are yet available. The first anticipated
+
 
implementations will be file systems stored in flash. These will provide persistent
+
Мы также можем создавать собственные специализированные реализации. Одной из интересных идей - позволить ESP32 быть сетевым клиентом внешних файловых систем. Например для:
storage of data through a file API. Potential implementations will include FAT or
+
* NFS
SPIFFS.
+
* SSH
 +
* FTP
 +
* TFTP
 +
* HTTP servers
 +
* Google Drive
 +
* Other cloud based systems
  
We can also produce our own specialized implementations. One interesting idea is to
+
Может показаться странным иметь доступ к данным сетевого устройства через файловый механизм только для того, чтобы он затем обрабатывал запросы в качестве другого сетевого вызова ... однако могут быть преимущества. ESP32 может кэшировать полученные данные либо в ОЗУ, либо в локальной флэш-памяти и выполнять только внешние сетевые запросы, если запрашиваемые данные недоступны в другом месте.
allow the ESP32 to be a network client of external file systems. Possibilities include:
 
• NFS
 
• SSH
 
• FTP
 
• TFTP
 
• HTTP servers
 
• Google Drive
 
• Other cloud based systems
 
  
It may seem strange to have a network device access data through a file mechanism
+
При работе с файловыми вводами-выводами мы можем использовать механизмы файлов потоков, импортированные через «stdio.h», или использовать ввод / вывод файлов нижнего уровня, импортированных через «fcntl.h».
only to have it then farm out the requests as another network call … however there may
 
be benefits. The ESP32 could cache the received data either in RAM or local flash and
 
only perform external network requests if the requested data is not available elsewhere.
 
  
When working with file I/O, we can use the streams file mechanisms imported via
 
"stdio.h" or use the lower level file I/O imported through "fcntl.h".
 
 
See also:
 
See also:
VFS mapping to SPIFFS
+
* VFS mapping to SPIFFS
  
 
===FATFS File System===
 
===FATFS File System===
The FatFs file system is an implementation of the FAT/exFAT file system as found in
+
Файловая система FatFs представляет собой реализацию файловой системы FAT / exFAT, как показано в более ранних операционных системах ПК, таких как MS-DOS и ранние версии Windows (до FAT32 и NTFS).
earlier PC operating systems such as MS-DOS and early Windows (before FAT32 and
+
 
NTFS). The implementation is open source and is supplied "pre-ported" to the ESP32
+
Реализация является открытым исходным кодом и поставляется «предварительно перенесенной» в ESP32 как часть дистрибутива ESP-IDF. Отображение ESP-IDF для FATFS сопоставляет файловую систему с функциями posix IO. Это означает, что нам не нужно изучать какие-либо специальные API-интерфейсы для чтения и записи файлов. Мы можем использовать функции open (), close (), read (), write () и другие методы, открытые через виртуальную файловую систему.
as part of the ESP-IDF distribution.
 
The ESP-IDF mapping for the FATFS maps the file system to the posix IO functions.
 
This means that we don't need to learn any special APIs in order to read and write files.
 
We can use open(), close(), read(), write() and the other methods exposed through
 
Virtual File System.
 
Before we can use these APIs, we need to perform some preliminary setup.
 
1. Call esp_vfs_fat_register
 
2. Call ff_diskio_register
 
3. Call f_mount
 
  
To unregister
+
Прежде чем мы сможем использовать эти API, нам нужно выполнить предварительную настройку.
1. Close all open files
+
# Вызовите esp_vfs_fat_register
2. Call f_mount with NULL
+
# Вызовите ff_diskio_register
3. Call ff_diskio_register with NULL
+
# Вызовите f_mount
4. Call esp_vfs_fat_unregister
 
  
By default, the filenames are constrained to the old 8.3 format (short names), however,
+
Отменить регистрацию
should we choose, we can enable long file name control in the make menuconfig
+
# Закройте все открытые файлы
settings.
+
# Вызвать f_mount с помощью NULL
 +
# Вызовите ff_diskio_register с помощью NULL
 +
# Вызовите esp_vfs_fat_unregister
 +
 
 +
По умолчанию имена файлов ограничены старым форматом 8.3 (короткие имена), однако, если мы выберем, мы можем включить длительное управление именами файлов в настройках make menuconfig.
 +
 
 +
См. Также:
 +
* FatFS – Generic FAT File System Module
 +
* Virtual File System
 +
* FatFs file system
  
See also:
 
• FatFS – Generic FAT File System Module
 
• Virtual File System
 
• FatFs file system
 
 
===Spiffs File System===
 
===Spiffs File System===
The SPI Flash File System (SPIFFS) is a file system mechanism intended for
+
Файловая система SPI (SPIFFS) - это механизм файловой системы, предназначенный для встроенных устройств. Чтобы настроить SPIFF, нам нужно определить некоторые числа. Во-первых, это размер физической страницы. Далее следует размер физического блока. Затем мы определяем размер логического блока. Это будет некоторый целочисленный множитель размера физического блока.
embedded devices. To configure SPIFFs we need to determine some numbers.
+
 
First is the physical page size. Next comes the physical block size. Next we decide on
+
Вся файловая система SPIFFS должна быть кратной размеру логического блока. Далее следует размер логической страницы, который является некоторым множителем размера логического блока.
the logical block size. This will be some integer multiplier of the physical block size.
+
 
 +
Общий размер ESP32 составляет 64 КБ для размера логического блока и 256 для размера логической страницы.
  
The whole SPIFFS file system must be a multiple of the logical block size. Next comes
+
Чтобы было ясно, 1 блок - это n x страниц.
the logical page size which is some multiplier of the logical block size.
 
A common ESP32 sizing is 64K for the logical block size and 256 for the logical page
 
size.
 
  
To be clear a 1 block is n x pages.
+
Когда выполняется вызов API SPIFFS, нулевой или положительный ответ указывает на успех, а значение <0 указывает на ошибку. Характер ошибки можно получить через вызов SPIFFS_errno (). Реализация SPIFFS не обеспечивает прямой доступ к флэш-памяти. Вместо этого функциональная область, называемая уровнем абстракции оборудования («hal»), предоставляет эту услугу. Для интеграции SPIFFS необходимо создать три функции, которые имеют следующие заголовки:
  
When a SPIFFS API call is made, a zero or positive response indicates success while a
+
<source lang=c>
value < 0 indicates an error. The nature of the error can be retrieved through the
 
SPIFFS_errno() call.
 
The SPIFFS implementation does not directly access the flash memory. Instead, a
 
functional area called a hardware abstraction layer ("hal") provides this service. A
 
SPIFFS integration requires that three functions be created that have the following
 
signatures:
 
 
s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst)
 
s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst)
 
s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src)
 
s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src)
 
s32_t (*spiffs_erase)(u32_t addr, u32_t size)
 
s32_t (*spiffs_erase)(u32_t addr, u32_t size)
If they succeed, the return code should be SPIFFS_OK (0). On an ESP32, these will map
+
</source>
to the SPI flash APIs.
+
 
To use a SPIFFS file system, we must perform a call to SPIFFS_mount(). This takes as
+
В случае успешного выполнения, код возврата SPIFFS_OK (0). На ESP32 они будут сопоставляться с API-интерфейсами SPI.
input a configuration structure that tells SPIFFS how much flash is available and a
+
 
variety of other properties. In addition, some working storage must be allocated for
+
Чтобы использовать файловую систему SPIFFS, мы должны выполнить вызов SPIFFS_mount (). В результате создается структура конфигурации, которая сообщает SPIFFS, сколько флэш-памяти доступно и множество других свойств. Кроме того, некоторые рабочие хранилища должны быть выделены для различных внутренних операций. Эти размеры могут быть настроены.
various internal operations. These sizes can be tuned.
+
Ниже приведен пример конфигурации для установки файловых систем:
Here is an example of configuration for mounting a file systems:
+
 
 +
<source lang=c>
 
#define LOG_PAGE_SIZE 256
 
#define LOG_PAGE_SIZE 256
 +
 
static uint8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
 
static uint8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
 
static uint8_t spiffs_fds[32*sizeof(uint32_t)];
 
static uint8_t spiffs_fds[32*sizeof(uint32_t)];
 
static uint8_t spiffs_cache_buf[(LOG_PAGE_SIZE+32)*4];
 
static uint8_t spiffs_cache_buf[(LOG_PAGE_SIZE+32)*4];
 +
 
spiffs fs;
 
spiffs fs;
 
spiffs_config cfg;
 
spiffs_config cfg;
Строка 209: Строка 169:
 
cfg.log_block_size = 65536; // let us not complicate things
 
cfg.log_block_size = 65536; // let us not complicate things
 
cfg.log_page_size = LOG_PAGE_SIZE; // as we said
 
cfg.log_page_size = LOG_PAGE_SIZE; // as we said
 +
 
cfg.hal_read_f = esp32_spi_flash_read;
 
cfg.hal_read_f = esp32_spi_flash_read;
 
cfg.hal_write_f = esp32_spi_flash_write;
 
cfg.hal_write_f = esp32_spi_flash_write;
 
cfg.hal_erase_f = esp32_spi_flash_erase;
 
cfg.hal_erase_f = esp32_spi_flash_erase;
int res = SPIFFS_mount(&fs,
+
int res = SPIFFS_mount(&fs, &cfg, spiffs_work_buf, spiffs_fds, sizeof(spiffs_fds), spiffs_cache_buf, sizeof(spiffs_cache_buf), 0);
&cfg,
+
</source>
spiffs_work_buf,
+
 
spiffs_fds,
+
После того, как мы установили файловую систему, мы можем открыть файл, записать в него контент и закрыть его. Например:
sizeof(spiffs_fds),
+
 
spiffs_cache_buf,
+
<source lang=c>
sizeof(spiffs_cache_buf),
 
0);
 
Once we have mounted the file system, we can then open a file, write content into it and
 
close it. For example:
 
 
char *fileName = "/f1/my_file";
 
char *fileName = "/f1/my_file";
 
spiffs_file fd = SPIFFS_open(&fs, fileName,
 
spiffs_file fd = SPIFFS_open(&fs, fileName,
Строка 227: Строка 184:
 
SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12);
 
SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12);
 
SPIFFS_close(&fs, fd);
 
SPIFFS_close(&fs, fd);
Similarly, if we wish to read data from the file we can perform the following:
+
</source>
 +
 
 +
Аналогично, если мы хотим прочитать данные из файла, мы можем выполнить следующее:
 +
 
 +
<source lang=c>
 
char buf[12];
 
char buf[12];
 
spiffs_file fd = SPIFFS_open(&fs, fileName, SPIFFS_RDWR, 0);
 
spiffs_file fd = SPIFFS_open(&fs, fileName, SPIFFS_RDWR, 0);
 
SPIFFS_read(&fs, fd, (u8_t *)buf, 12);
 
SPIFFS_read(&fs, fd, (u8_t *)buf, 12);
 
SPIFFS_close(&fs, fd);
 
SPIFFS_close(&fs, fd);
Using the
+
</source>
The SPIFFS file system could be hierarchical in nature such that it contains both
+
 
directories and files but it seems that in reality it is not. There is only one directory
+
Использование файловой системы SPIFFS может быть иерархической по своей природе, так что она содержит как каталоги, так и файлы, но, похоже, на самом деле это не так. Существует только один каталог с именем root. Корневой каталог - «/». Чтобы определить членов каталога, мы можем открыть каталог для чтения с помощью API SPIFFS_opendir (), и, когда мы закончим, закройте операцию чтения с помощью вызова API SPIFFS_closedir (). Мы можем пройти через записи каталога с вызовами SPIFFS_readdir ().
called the root. The root directory is "/". To determine the members of a directory, we
+
 
can open a directory for reading with the SPIFFS_opendir() API and, when we are
+
Например:
finished, close the reading operation with a SPIFFS_closedir() API call. We can walk
+
 
through the directory entries with calls to SPIFFS_readdir().
+
<source lang=c>
For example:
 
 
spiffs_DIR spiffsDir;
 
spiffs_DIR spiffsDir;
 
SPIFFS_opendir(&fs, "/", &spiffsDir);
 
SPIFFS_opendir(&fs, "/", &spiffsDir);
 
struct spiffs_dirent spiffsDirEnt;
 
struct spiffs_dirent spiffsDirEnt;
 
while(SPIFFS_readdir(&spiffsDir, &spiffsDirEnt) != 0) {
 
while(SPIFFS_readdir(&spiffsDir, &spiffsDirEnt) != 0) {
printf("Got a directory entry: %s\n", spiffsDirEnt.name);
+
  printf("Got a directory entry: %s\n", spiffsDirEnt.name);
 
}
 
}
 
SPIFFS_closedir(&spiffsDir);
 
SPIFFS_closedir(&spiffsDir);
To make this clear, in Linux, if we created "/a/b/c.txt" this would normally create a file
+
</source>
called "c.txt" in a directory called "b" in a directory called "c". In SPIFFS, this actually
+
 
creates a single file called "/a/b/c.txt" where the "/" characters are merely part of the
+
Чтобы это стало ясно, в Linux, если мы создали «/a/b/c.txt», это обычно создало бы файл c.txt в каталоге с именем «b» в каталоге с именем «a». В SPIFFS это фактически создает один файл с именем «/a/b/c.txt», где символы «/» являются просто частью имени файла. Когда мы выполняем SPIFFS_opendir (), на самом деле нет структуры каталогов, а всего лишь один плоский список ВСЕХ файлов, которые могут иметь или не иметь «слэши» в их именах.
file name. When we perform SPIFFS_opendir(), there isn't actually a directory structure
+
Чтобы создать файл, мы можем использовать API SPIFFS_open (), предоставив флаг SPIFFS_CREAT.
but just one single flat list of ALL files which may or may not have "slashes" in their
+
 
names.
 
To create a file, we can use the SPIFFS_open() API by supplying a SPIFFS_CREAT flag.
 
 
See also:
 
See also:
SPIFFs API
+
* SPIFFs API
Github: pellepl/spiffs
+
* Github: pellepl/spiffs
Github: igrr/mkspiffs – The mkspiffs tool.
+
* Github: igrr/mkspiffs – The mkspiffs tool.
SPI Flash
+
* SPI Flash
Virtual File System mapping to SPIFFS
+
* Virtual File System mapping to SPIFFS
 +
 
 +
====Building SPIFFs for the ESP32====
 +
Под заголовком «"let's build on each other» была проделана отличная работа портирования SPIFF в ESP32 командой LUA (Jaume Olivé Petrus). Исходный код
 +
можно найти на [https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/spiffs github]. Они упаковали его как компонент ESP-IDF.
 +
 
 +
====mkspiffs tool====
 +
В дополнение к фантастической библиотеке SPIFF существует также инструмент под названием «mkspiffs», который может принимать структуру каталогов в вашей файловой системе и создавать из него образ SPIFF, который затем может быть загружен во флэш-память для предоставления предварительно загруженных данных.
 +
 
 +
Можно скачать репозиторий Git для mkspiffs и скомпилировать его. Я не обнаружил проблем и скомпилировал их с первого раза.
 +
 
 +
Пример:
  
===Building SPIFFs for the ESP32===
+
<source lang=bash>
Under the heading of "let's build on each other", an excellent job has been done of
 
porting SPIFFs to the ESP32 by the LUA team (Jaume Olivé Petrus). The source code
 
can be found:
 
https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/spiffs.
 
They have packaged it as an ESP-IDF component.
 
mkspiffs tool
 
In addition to the fantastic SPIFFs library, there is also a tool called "mkspiffs" that can
 
take a directory structure on your file system and build a SPIFFs image from it that can
 
then be loaded into flash memory to provide pre-loaded data.
 
One can download the Git repository for mkspiffs and compile it. I found no issues and
 
it compiled at first go.
 
The syntax is:
 
 
mkspiffs { -c <packdir> | -u <destdir>|-l|-i} \
 
mkspiffs { -c <packdir> | -u <destdir>|-l|-i} \
 
-b <number> -p <number> -s <number>
 
-b <number> -p <number> -s <number>
 +
</source>
 +
 
One of:
 
One of:
-c <directory to pack>
+
* -c <directory to pack>
-u <dest to unpack into>
+
* -u <dest to unpack into>
-l – list content
+
* -l – list content
-i – visualize content
+
* -i – visualize content
 
and
 
and
-b <number> – Block size in bytes (for example 65536)
+
* -b <number> – Block size in bytes (for example 65536)
-p <number> – Page size in bytes (for example 256)
+
* -p <number> – Page size in bytes (for example 256)
-s <number> – fs image size in bytes.
+
* -s <number> – fs image size in bytes.
Page 401
+
 
Visualizing an image file shows results such as:
+
В результате получим файл образа:
 +
 
 +
<source lang=bash>
 
0 idid___________ era_cnt: 0
 
0 idid___________ era_cnt: 0
 +
 
1 _______________ era_cnt: 0
 
1 _______________ era_cnt: 0
 +
 
2 _______________ era_cnt: 0
 
2 _______________ era_cnt: 0
 +
 
3 _______________ era_cnt: 0
 
3 _______________ era_cnt: 0
 +
 
4 _______________ era_cnt: 0
 
4 _______________ era_cnt: 0
 +
 
5 _______________ era_cnt: 0
 
5 _______________ era_cnt: 0
 +
 
6 _______________ era_cnt: 0
 
6 _______________ era_cnt: 0
 +
 
7 _______________ era_cnt: 0
 
7 _______________ era_cnt: 0
 +
 
8 _______________ era_cnt: 0
 
8 _______________ era_cnt: 0
 +
 
9 _______________ era_cnt: 0
 
9 _______________ era_cnt: 0
 +
 
10 _______________ era_cnt: 0
 
10 _______________ era_cnt: 0
 +
 
11 _______________ era_cnt: 0
 
11 _______________ era_cnt: 0
 +
 
12 _______________ era_cnt: 0
 
12 _______________ era_cnt: 0
 +
 
13 _______________ era_cnt: 0
 
13 _______________ era_cnt: 0
 +
 
14 _______________ era_cnt: 0
 
14 _______________ era_cnt: 0
 +
 
15 _______________ era_cnt: 0
 
15 _______________ era_cnt: 0
 +
 
era_cnt_max: 1
 
era_cnt_max: 1
 +
 
last_errno: 0
 
last_errno: 0
 +
 
blocks: 16
 
blocks: 16
 +
 
free_blocks: 15
 
free_blocks: 15
 +
 
page_alloc: 4
 
page_alloc: 4
 +
 
page_delet: 0
 
page_delet: 0
 +
 
used: 1004 of 52961
 
used: 1004 of 52961
 +
 
total: 52961
 
total: 52961
 +
 
used: 1004
 
used: 1004
Once we have an image file, we can the load it to flash with:
+
</source>
 +
 
 +
Когда у нас есть файл образа, чтобы его загрузить выполняем:
 +
 
 +
<source lang=bash>
 
esptool.py --chip esp32 --port "/dev/ttyUSB0" --baud 115200 write_flash -z
 
esptool.py --chip esp32 --port "/dev/ttyUSB0" --baud 115200 write_flash -z
 
--flash_mode "dio" --flash_freq "40m" <address> <file>
 
--flash_mode "dio" --flash_freq "40m" <address> <file>
 +
</source>
 +
 
See also:
 
See also:
 
• Github: igrr/mkspiffs – The mkspiffs tool.
 
• Github: igrr/mkspiffs – The mkspiffs tool.
  
 
===The ESP File System – EspFs===
 
===The ESP File System – EspFs===
Part of the Github project known as "Spritetm/libesphttpd" is a module called "espfs"
+
Часть проекта Github, известного как «Spritetm / libesphttpd», представляет собой модуль под названием «espfs», который является «файловой системой ESP». То, что делает этот модуль, позволяет сделать образ из набора файлов на вашем ПК и сохранить это комбинированное изображение во флэш-памяти. Оттуда предоставляется набор API для чтения и доступа к этим файлам и их содержимому. Крайне важно отметить, что данные в этих файлах доступны только для чтения. API не обновляет содержимое файлов. Доступны только те данные, которые изначально записываются в flash.
which is the "ESP File System". What this module does is allow one to make an image
+
 
from a set of files on your PC and store that combined image in flash memory. From
+
В рамках проекта есть утилита под названием «mkespfsimage», которая принимает во вход набор имен файлов и потоков в качестве вывода данных изображения, которые должны быть свернуты. Например:
there, a set of APIs are provided to read and access those files and their content. It is
+
 
vital to note that the data in these files is read-only. There is no API to update the
+
<source lang=bash>
content of the files. Only the data that is initially written to flash is available to be read.
 
As part of the project there is a utility called "mkespfsimage" that takes as input a set of
 
file names and streams as output the image data that should be flashed. For example:
 
 
find | ./mkespfsimage [-c compressor] [-l compression_level] > out.espfs
 
find | ./mkespfsimage [-c compressor] [-l compression_level] > out.espfs
(Note that the project has compression capabilities that I am ignoring at this point).
+
</source>
 +
 
 +
(Обратите внимание, что проект имеет возможности сжатия, которые я игнорирую на данном этапе).
 +
 
 +
 
 +
После того, как данные находятся во флэш-памяти, мы можем затем использовать API-интерфейсы, предоставленные компонентом, для выполнения базового доступа к данным:
 +
* EspFsInitResult espFsInit(void *flashAddress)
 +
* int espFsFlags(EspFsFile *fh)
 +
* EspFsFile *espFsOpen(char *fileName)
 +
* int espFsRead(EspFsFile *fh, char *buff, int len)
 +
* void espFsClose(EspFsFile *fh)
 +
 
 +
Была предпринята попытка портировать код для использования технологий ESP32 и можно найти [https://github.com/nkolban/esp32-snippets/tree/master/filesystems/espfs здесь].
 +
 
 +
Это добавляет новую функцию:
 +
* int espFsAccess(EspFsFile *fh, void **buf, size_t *len)
 +
 
 +
Эта функция возвращает указатель на весь контент файла, который хранится в buf.
 +
 
 +
Длина файла сохраняется в len, а также возвращается из функции в целом.
  
 +
Доступ к данным осуществляется непосредственно из flash без каких-либо копий ОЗУ.
  
Once the data is in flash, we can then use the APIs supplied by the component to
+
Кроме этого, необходимо выделить память:
perform the underlying data access.
 
  
They are:
+
* EspFsInitResult espFsInit(void *flashAddress, size_t size)
EspFsInitResult espFsInit(void *flashAddress)
 
• int espFsFlags(EspFsFile *fh)
 
• EspFsFile *espFsOpen(char *fileName)
 
• int espFsRead(EspFsFile *fh, char *buff, int len)
 
• void espFsClose(EspFsFile *fh)
 
An attempt to port the code to utilize ESP32 technologies was undertaken and can be
 
found here:
 
https://github.com/nkolban/esp32-snippets/tree/master/filesystems/espfs
 
  
This adds a new function called:
+
Вот пример приложения:
• int espFsAccess(EspFsFile *fh, void **buf, size_t *len)
+
<source lang=c>
This function returns a pointer to the whole content of the file which is stored in buf.
 
The length of the file is stored in len and also returned from the function as a whole.
 
The data is accessed directly from flash without any RAM copies.
 
In addition, the function called:
 
• EspFsInitResult espFsInit(void *flashAddress, size_t size)
 
was augmented to include the size of the flash storage to map.
 
Here is an example application:
 
 
ESP_LOGD(tag, "Flash address is 0x%x", (int)flashAddress);
 
ESP_LOGD(tag, "Flash address is 0x%x", (int)flashAddress);
 
if (espFsInit(flashAddress, 64*1024) != ESPFS_INIT_RESULT_OK) {
 
if (espFsInit(flashAddress, 64*1024) != ESPFS_INIT_RESULT_OK) {
ESP_LOGD(tag, "Failed to initialize espfs");
+
  ESP_LOGD(tag, "Failed to initialize espfs");
return;
+
    return;
 
}
 
}
 
EspFsFile *fh = espFsOpen("files/test3.txt");
 
EspFsFile *fh = espFsOpen("files/test3.txt");
 
if (fh != NULL) {
 
if (fh != NULL) {
int sizeRead = 0;
+
  int sizeRead = 0;
char buff[5*1024];
+
  char buff[5*1024];
sizeRead = espFsRead(fh, buff, sizeof(buff));
+
  sizeRead = espFsRead(fh, buff, sizeof(buff));
ESP_LOGD(tag, "Result: %.*s", sizeRead, buff);
+
  ESP_LOGD(tag, "Result: %.*s", sizeRead, buff);
size_t fileSize;
+
  size_t fileSize;
char *data;
+
  char *data;
sizeRead = espFsAccess(fh, (void **)&data, &fileSize);
+
  sizeRead = espFsAccess(fh, (void **)&data, &fileSize);
ESP_LOGD(tag, "Result from access: %.*s", fileSize, data);
+
  ESP_LOGD(tag, "Result from access: %.*s", fileSize, data);
espFsClose(fh);
+
  espFsClose(fh);
 
}
 
}
SD, MMC and SDIO interfacing
+
</source>
Secure Digital (SD) is a standard for removable media. These devices are also known
+
 
as "flash cards" or "SD cards". The idea is that an SD card contains data that can be
+
===SD, MMC and SDIO interfacing===
both read and written. The SD cards store the data as raw memory and it is common to
+
Secure Digital (SD) является стандартом для съемных носителей. Эти устройства также известны как «флеш-карты» или «SD-карты». Идея состоит в том, что SD-карта содержит данные, которые могут считываться и записываться. Карты SD хранят данные как необработанную память, и обычно создается файловая система, которая живет поверх данных. Обычно используются форматы файловой системы FAT16 и FAT32. Карты SD имеют различные физические размеры и с различными возможностями и скоростью.
create a file system that lives on top of the data. The FAT16 and FAT32 file system
+
 
formats are commonly used. SD cards come in a variety of physical dimensions and
+
Карты бывают трех размеров, известные как «SD», «miniSD» и «microSD», от самых больших до самых маленьких.
with a variety of capacities and speeds. For the physical dimensions there are three
+
 
distinct types known as "SD", "miniSD" and "microSD" ranging from largest to smallest.
+
В зависимости от емкости карты делятся на три типа:
For capacity, there are again three distinct types known as "SD", "SDHC" and "SDXC".
+
* SD - до 2GB (FAT12 / FAT16)
SD SDHC SDXC
+
* SDHC - до 32Gb (FAT32)
Capacity x <= 2GB 2GB <= x <=32GB 32GB <= x <= 2TB
+
* SDXC - до 2Tb (extFAT) - не поддерживается
File system FAT12, FAT16 FAT32 exFAT
+
 
For our story, we will ignore SDXC.
+
Дополнительной характеристикой SD карты является скорость. Карты делятся на классы:
An additional characteristic of SD cards is their rated speed. The common speeds are:
+
* Class 2 2MB/s
Class 2 2MB/s
+
* Class 4 4MB/s
Class 4 4MB/s
+
* Class 6 6MB/s
Class 6 6MB/s
+
* Class 10 10MB/s
Class 10 10MB/s
+
 
The SD specification is large and comprehensive. If we were to try and implement the
+
Спецификация SD является большой и всеобъемлющей. Если бы мы сами попытались реализовать спецификацию SD, мы бы рассмотрели целый ряд головоломок. Как таковой, распространено использование ранее существовавших реализаций спецификации, и, к счастью, ESP-IDF предоставляет нам именно это.
SD specification ourselves we would be delving down into a whole host of puzzles. As
+
 
such, it is common to leverage pre-existing implementations of the specification and,
+
Существует также отличное примерное приложение, представленное в каталоге examples / storage / sd_card ESP-IDF.
thankfully, the ESP-IDF provides us with exactly that.
+
 
There is also an excellent example application provide in the examples/storage/sd_card
+
Карта SD может использоваться для хранения данных, но не может использоваться для хранения кода команды для выполнения. Таким образом, SD-карта не должна рассматриваться как альтернатива флэш-памяти, доступной через SPI для хранения кода. SD-карту следует использовать для хранения данных приложения, которые могут быть прочитаны или записаны при запуске приложений.
directory of the ESP-IDF.
+
 
The SD card can be used to hold data but can not be used to hold instruction code for
 
execution. As such, the SD card shouldn't be considered as an alternative to the flash
 
memory accessible via SPI for code storage. The SD card should be used to store
 
application data that can be read by or written by running applications.
 
 
See also:
 
See also:
Page 404
+
* Wikipedia: Multi Media Card
Wikipedia: Multi Media Card
+
* Wikipedia: Secure Digita l
Wikipedia: Secure Digita l
+
* SD Association
SD Association
+
 
Charting data
+
 
Consider some of the sensors
+
[[Категория:ESP32]]

Текущая версия на 15:03, 1 июля 2017

Понятие хранения в программировании хранения включает в себя методы хранения данных для последующего использования. ESP32 имеет ОЗУ, но когда ESP32 выключен, содержимое ОЗУ теряется. Таким образом, нам нужен механизм, чтобы сделать это хранилище более постоянным. ESP32 обычно имеет доступ к флэш-памяти, которая электрически подключается через специальную шину SPI. Обычно размер флеш-памяти составляет 4 Мбайт. Мы можем получить доступ к флэш-памяти через SPI Flash API.

Partition table

Архитектура ESP32 представляет собой концепцию, называемую таблицей разделов, которая в основном представляет собой «карту» или «Макет» того, что содержится во флэш-памяти. Таблица разделов находится в 0x8000 во флэш-памяти и имеет длину 0xC00 байт, что обеспечивает пространство для около 95 отдельных таблиц записей. Каждая запись в таблице имеет структуру записи, которая логически содержит:

  • type – The type of the partition. One of:
    • data
    • app
  • subtype – The sub-type of the partition. One of:
    • nvs – Used for non volatile storage.
    • phy
    • factory
    • coredump – Used to hold core dumps.
    • ota
    • fat – Used for the FAT file system.
  • address – The offset address (flash) of the start of the partition.
  • size – The size of the partition in bytes.
  • label – An optional null terminated string (max 16 characters + NULL)
  • encrypted – Is the partition encrypted.

Таблица разделов доступна для наших приложений только для чтения и может получена с помощью API ESP-IDF. Таблица записывается во флэш-память при прошивке.

Размер смещения является необязательным. Пустые смещения будут размещены смежно после предыдущих данных. Смещения выравниваются по 64 КБ.

Инструмент под названием «gen_esp32part.py» доступен как часть инструментария для построения двоичных представлений таблицы. Мы можем построить двоичную таблицу из файла значений, разделенных запятыми, используя: $ Gen_esp32part.py -verify input_partitions.csv binary_partitions.bin

Мы можем преобразовать двоичный файл обратно в CSV, используя:

$ Gen_esp32part.py --verify binary_partitions.bin input_partitions.csv

И мы можем перечислить содержимое двоичного файла, используя: $ Gen_esp32part.py binary_partitions.bin

Таблица разделов, используемая вашим приложением, определяется командой make menuconfig в разделе Partition Table

See also: • Partition API • esp_vfs_fat_spiflash_mount • esp_vfs_fat_register

Non Volatile Storage

Энергонезависимое хранилище - это память, которая может быть записана так, чтобы после выключения или перезапуска, те же данные могут быть прочитаны из него снова без потерь. В рамках этих данных мы можем хранить конфигурационные и эксплуатационные значения для наших приложений. Например, мы можем сохранить сетевой SSID и пароль таким образом, чтобы когда устройство перезапускается, он знает, к какой сети подключиться, и пароль для представления.

Хранилище разделено на именованные области. Для данной именованной области мы можем сохранить и прочитать пару имя / значение в хранилище. Существуют функции getter / setter для большинства типов данных, включая целые числа с знаком и без знака, строки и двоичные данные.

Именованная область открывается для доступа вызовом nvs_open (). Имя области передается как параметр. Нам возвращен логический «дескриптор», который мы впоследствии можем использовать для ссылки на эту область хранения. Как только мы получим дескриптор, мы можем записать и прочитать элементы именованных данных. Элементы данных ссылаются на имя ключа эффективно превращая область хранения в хэш-карту. Если мы изменим данные, выполнив функцию set, это не приведет к тому, что данные будут записаны в энергонезависимое хранилище. Вместо этого хранилище обновляется, когда мы вызываем nvs_commit (). Это зависит от внутренней реализации того, когда выполняется фактическое обновление, и это может произойти до nvs_commit (). Контракт заключается в том, что, когда мы возвращаемся из nvs_commit (), мы уверены, что все обновления обработаны. Когда мы выполнили все наши наборы и получили, мы должны вызвать nvs_close (), чтобы объявить, что мы больше не будем работать с хранилищем в это время, чтобы время выполнения могло очистить любые ресурсы, которые он мог открыть.

Детали алгоритмов, используемых для управления NVS, раскрываются в документации. Цель NVS на высоком уровне - хранить простые строки и целые числа и другие флаги, а не быть богатой структурой «файловой системы». В настоящее время дефрагментация не выполняется в хранилище.

See also:

Virtual File System

Виртуальная файловая система (VFS) - это архитектура, предоставляемая ESP-IDF, которая дает нам возможность сохранять и загружать данные из наших приложений с использованием ввода-вывода файловой системы.

VFS не привязан к какой-либо одной конкретной технологии, а вместо этого является архитектурной абстракцией, используемой для обеспечения интерфейса ввода-вывода для множества различных реализаций.

Ключом к VFS является тип данных, называемый esp_vfs_t. Эта структура содержит следующее:

  • fd_offset –
  • flags – Operational flags. Use ESP_VFS_FLAG_DEFAULT.
  • close/close_p – Close a previously opened file.
  • closedir/closedir_p – Close a previously opened directory.
  • fstat/fstat_p – Get stats/details of a file.
  • link/link_p – Create a new link to a file.
  • lseek/lseek_p – Change the data pointer within a file.
  • mkdir/mkdir_p – Create a new directory entry.
  • open/open_p – Open a named file.
  • opendir/opendir_p – Open a directory for reading.
  • read/read_p – Read the contents of a file.
  • readdir/readdir_p – Read a record from a directory.
  • rename/rename_p – Rename a file.
  • rmdir/rmdir_p – Delete a directory entry.
  • seekdir/seekdir_p – Set the position of the next readdir().
  • stat/stat_p – Get stats/details of a file.
  • telldir/telldir_p – Return the current direction stream.
  • unlink/unlink_p – Remove a file.
  • write/write_p – Write into a file.

После заполнения структуры нам необходимо зарегистрировать нашу новую виртуальную файловую систему с вызовом esp_vfs_register ().

Нам нужно знать, что предполагаемый вызывающий файл ввода-вывода ожидает среду, похожую на POSIX.

See also: • esp_vfs_register • Virtual filesystem componen t

VFS Implementations

Поскольку VFS предоставляет архитектурную модель, нам необходимо рассмотреть ее фактические реализации. По состоянию на 2016-11 реализаций пока нет. Первыми ожидаемыми реализациями будут файловые системы, хранящиеся во флэш-памяти. Они будут обеспечивать постоянное хранение данных через API файлов. Первыми кандидатами на реализацию являются FAT и/или SPIFFS.

Мы также можем создавать собственные специализированные реализации. Одной из интересных идей - позволить ESP32 быть сетевым клиентом внешних файловых систем. Например для:

  • NFS
  • SSH
  • FTP
  • TFTP
  • HTTP servers
  • Google Drive
  • Other cloud based systems

Может показаться странным иметь доступ к данным сетевого устройства через файловый механизм только для того, чтобы он затем обрабатывал запросы в качестве другого сетевого вызова ... однако могут быть преимущества. ESP32 может кэшировать полученные данные либо в ОЗУ, либо в локальной флэш-памяти и выполнять только внешние сетевые запросы, если запрашиваемые данные недоступны в другом месте.

При работе с файловыми вводами-выводами мы можем использовать механизмы файлов потоков, импортированные через «stdio.h», или использовать ввод / вывод файлов нижнего уровня, импортированных через «fcntl.h».

See also:

  • VFS mapping to SPIFFS

FATFS File System

Файловая система FatFs представляет собой реализацию файловой системы FAT / exFAT, как показано в более ранних операционных системах ПК, таких как MS-DOS и ранние версии Windows (до FAT32 и NTFS).

Реализация является открытым исходным кодом и поставляется «предварительно перенесенной» в ESP32 как часть дистрибутива ESP-IDF. Отображение ESP-IDF для FATFS сопоставляет файловую систему с функциями posix IO. Это означает, что нам не нужно изучать какие-либо специальные API-интерфейсы для чтения и записи файлов. Мы можем использовать функции open (), close (), read (), write () и другие методы, открытые через виртуальную файловую систему.

Прежде чем мы сможем использовать эти API, нам нужно выполнить предварительную настройку.

  1. Вызовите esp_vfs_fat_register
  2. Вызовите ff_diskio_register
  3. Вызовите f_mount

Отменить регистрацию

  1. Закройте все открытые файлы
  2. Вызвать f_mount с помощью NULL
  3. Вызовите ff_diskio_register с помощью NULL
  4. Вызовите esp_vfs_fat_unregister

По умолчанию имена файлов ограничены старым форматом 8.3 (короткие имена), однако, если мы выберем, мы можем включить длительное управление именами файлов в настройках make menuconfig.

См. Также:

  • FatFS – Generic FAT File System Module
  • Virtual File System
  • FatFs file system

Spiffs File System

Файловая система SPI (SPIFFS) - это механизм файловой системы, предназначенный для встроенных устройств. Чтобы настроить SPIFF, нам нужно определить некоторые числа. Во-первых, это размер физической страницы. Далее следует размер физического блока. Затем мы определяем размер логического блока. Это будет некоторый целочисленный множитель размера физического блока.

Вся файловая система SPIFFS должна быть кратной размеру логического блока. Далее следует размер логической страницы, который является некоторым множителем размера логического блока.

Общий размер ESP32 составляет 64 КБ для размера логического блока и 256 для размера логической страницы.

Чтобы было ясно, 1 блок - это n x страниц.

Когда выполняется вызов API SPIFFS, нулевой или положительный ответ указывает на успех, а значение <0 указывает на ошибку. Характер ошибки можно получить через вызов SPIFFS_errno (). Реализация SPIFFS не обеспечивает прямой доступ к флэш-памяти. Вместо этого функциональная область, называемая уровнем абстракции оборудования («hal»), предоставляет эту услугу. Для интеграции SPIFFS необходимо создать три функции, которые имеют следующие заголовки:

s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst)
s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src)
s32_t (*spiffs_erase)(u32_t addr, u32_t size)

В случае успешного выполнения, код возврата SPIFFS_OK (0). На ESP32 они будут сопоставляться с API-интерфейсами SPI.

Чтобы использовать файловую систему SPIFFS, мы должны выполнить вызов SPIFFS_mount (). В результате создается структура конфигурации, которая сообщает SPIFFS, сколько флэш-памяти доступно и множество других свойств. Кроме того, некоторые рабочие хранилища должны быть выделены для различных внутренних операций. Эти размеры могут быть настроены. Ниже приведен пример конфигурации для установки файловых систем:

#define LOG_PAGE_SIZE 256

static uint8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
static uint8_t spiffs_fds[32*sizeof(uint32_t)];
static uint8_t spiffs_cache_buf[(LOG_PAGE_SIZE+32)*4];

spiffs fs;
spiffs_config cfg;
cfg.phys_size = 512*1024; // use 512K
cfg.phys_addr = 2*1024*1024 - cfg.phys_size; // start spiffs at 2MB - 512K
cfg.phys_erase_block = 65536; // according to datasheet
cfg.log_block_size = 65536; // let us not complicate things
cfg.log_page_size = LOG_PAGE_SIZE; // as we said

cfg.hal_read_f = esp32_spi_flash_read;
cfg.hal_write_f = esp32_spi_flash_write;
cfg.hal_erase_f = esp32_spi_flash_erase;
int res = SPIFFS_mount(&fs, &cfg, spiffs_work_buf, spiffs_fds, sizeof(spiffs_fds), spiffs_cache_buf, sizeof(spiffs_cache_buf), 0);

После того, как мы установили файловую систему, мы можем открыть файл, записать в него контент и закрыть его. Например:

char *fileName = "/f1/my_file";
spiffs_file fd = SPIFFS_open(&fs, fileName,
SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12);
SPIFFS_close(&fs, fd);

Аналогично, если мы хотим прочитать данные из файла, мы можем выполнить следующее:

char buf[12];
spiffs_file fd = SPIFFS_open(&fs, fileName, SPIFFS_RDWR, 0);
SPIFFS_read(&fs, fd, (u8_t *)buf, 12);
SPIFFS_close(&fs, fd);

Использование файловой системы SPIFFS может быть иерархической по своей природе, так что она содержит как каталоги, так и файлы, но, похоже, на самом деле это не так. Существует только один каталог с именем root. Корневой каталог - «/». Чтобы определить членов каталога, мы можем открыть каталог для чтения с помощью API SPIFFS_opendir (), и, когда мы закончим, закройте операцию чтения с помощью вызова API SPIFFS_closedir (). Мы можем пройти через записи каталога с вызовами SPIFFS_readdir ().

Например:

spiffs_DIR spiffsDir;
SPIFFS_opendir(&fs, "/", &spiffsDir);
struct spiffs_dirent spiffsDirEnt;
while(SPIFFS_readdir(&spiffsDir, &spiffsDirEnt) != 0) {
   printf("Got a directory entry: %s\n", spiffsDirEnt.name);
}
SPIFFS_closedir(&spiffsDir);

Чтобы это стало ясно, в Linux, если мы создали «/a/b/c.txt», это обычно создало бы файл c.txt в каталоге с именем «b» в каталоге с именем «a». В SPIFFS это фактически создает один файл с именем «/a/b/c.txt», где символы «/» являются просто частью имени файла. Когда мы выполняем SPIFFS_opendir (), на самом деле нет структуры каталогов, а всего лишь один плоский список ВСЕХ файлов, которые могут иметь или не иметь «слэши» в их именах. Чтобы создать файл, мы можем использовать API SPIFFS_open (), предоставив флаг SPIFFS_CREAT.

See also:

  • SPIFFs API
  • Github: pellepl/spiffs
  • Github: igrr/mkspiffs – The mkspiffs tool.
  • SPI Flash
  • Virtual File System mapping to SPIFFS

Building SPIFFs for the ESP32

Под заголовком «"let's build on each other» была проделана отличная работа портирования SPIFF в ESP32 командой LUA (Jaume Olivé Petrus). Исходный код можно найти на github. Они упаковали его как компонент ESP-IDF.

mkspiffs tool

В дополнение к фантастической библиотеке SPIFF существует также инструмент под названием «mkspiffs», который может принимать структуру каталогов в вашей файловой системе и создавать из него образ SPIFF, который затем может быть загружен во флэш-память для предоставления предварительно загруженных данных.

Можно скачать репозиторий Git для mkspiffs и скомпилировать его. Я не обнаружил проблем и скомпилировал их с первого раза.

Пример:

mkspiffs { -c <packdir> | -u <destdir>|-l|-i} \
-b <number> -p <number> -s <number>

One of:

  • -c <directory to pack>
  • -u <dest to unpack into>
  • -l – list content
  • -i – visualize content

and

  • -b <number> – Block size in bytes (for example 65536)
  • -p <number> – Page size in bytes (for example 256)
  • -s <number> – fs image size in bytes.

В результате получим файл образа:

0 idid___________ era_cnt: 0

1 _______________ era_cnt: 0

2 _______________ era_cnt: 0

3 _______________ era_cnt: 0

4 _______________ era_cnt: 0

5 _______________ era_cnt: 0

6 _______________ era_cnt: 0

7 _______________ era_cnt: 0

8 _______________ era_cnt: 0

9 _______________ era_cnt: 0

10 _______________ era_cnt: 0

11 _______________ era_cnt: 0

12 _______________ era_cnt: 0

13 _______________ era_cnt: 0

14 _______________ era_cnt: 0

15 _______________ era_cnt: 0

era_cnt_max: 1

last_errno: 0

blocks: 16

free_blocks: 15

page_alloc: 4

page_delet: 0

used: 1004 of 52961

total: 52961

used: 1004

Когда у нас есть файл образа, чтобы его загрузить выполняем:

esptool.py --chip esp32 --port "/dev/ttyUSB0" --baud 115200 write_flash -z
--flash_mode "dio" --flash_freq "40m" <address> <file>

See also: • Github: igrr/mkspiffs – The mkspiffs tool.

The ESP File System – EspFs

Часть проекта Github, известного как «Spritetm / libesphttpd», представляет собой модуль под названием «espfs», который является «файловой системой ESP». То, что делает этот модуль, позволяет сделать образ из набора файлов на вашем ПК и сохранить это комбинированное изображение во флэш-памяти. Оттуда предоставляется набор API для чтения и доступа к этим файлам и их содержимому. Крайне важно отметить, что данные в этих файлах доступны только для чтения. API не обновляет содержимое файлов. Доступны только те данные, которые изначально записываются в flash.

В рамках проекта есть утилита под названием «mkespfsimage», которая принимает во вход набор имен файлов и потоков в качестве вывода данных изображения, которые должны быть свернуты. Например:

find | ./mkespfsimage [-c compressor] [-l compression_level] > out.espfs

(Обратите внимание, что проект имеет возможности сжатия, которые я игнорирую на данном этапе).


После того, как данные находятся во флэш-памяти, мы можем затем использовать API-интерфейсы, предоставленные компонентом, для выполнения базового доступа к данным:

  • EspFsInitResult espFsInit(void *flashAddress)
  • int espFsFlags(EspFsFile *fh)
  • EspFsFile *espFsOpen(char *fileName)
  • int espFsRead(EspFsFile *fh, char *buff, int len)
  • void espFsClose(EspFsFile *fh)

Была предпринята попытка портировать код для использования технологий ESP32 и можно найти здесь.

Это добавляет новую функцию:

  • int espFsAccess(EspFsFile *fh, void **buf, size_t *len)

Эта функция возвращает указатель на весь контент файла, который хранится в buf.

Длина файла сохраняется в len, а также возвращается из функции в целом.

Доступ к данным осуществляется непосредственно из flash без каких-либо копий ОЗУ.

Кроме этого, необходимо выделить память:

  • EspFsInitResult espFsInit(void *flashAddress, size_t size)

Вот пример приложения:

ESP_LOGD(tag, "Flash address is 0x%x", (int)flashAddress);
if (espFsInit(flashAddress, 64*1024) != ESPFS_INIT_RESULT_OK) {
   ESP_LOGD(tag, "Failed to initialize espfs");
    return;
}
EspFsFile *fh = espFsOpen("files/test3.txt");
if (fh != NULL) {
   int sizeRead = 0;
   char buff[5*1024];
   sizeRead = espFsRead(fh, buff, sizeof(buff));
   ESP_LOGD(tag, "Result: %.*s", sizeRead, buff);
   size_t fileSize;
   char *data;
   sizeRead = espFsAccess(fh, (void **)&data, &fileSize);
   ESP_LOGD(tag, "Result from access: %.*s", fileSize, data);
   espFsClose(fh);
}

SD, MMC and SDIO interfacing

Secure Digital (SD) является стандартом для съемных носителей. Эти устройства также известны как «флеш-карты» или «SD-карты». Идея состоит в том, что SD-карта содержит данные, которые могут считываться и записываться. Карты SD хранят данные как необработанную память, и обычно создается файловая система, которая живет поверх данных. Обычно используются форматы файловой системы FAT16 и FAT32. Карты SD имеют различные физические размеры и с различными возможностями и скоростью.

Карты бывают трех размеров, известные как «SD», «miniSD» и «microSD», от самых больших до самых маленьких.

В зависимости от емкости карты делятся на три типа:

  • SD - до 2GB (FAT12 / FAT16)
  • SDHC - до 32Gb (FAT32)
  • SDXC - до 2Tb (extFAT) - не поддерживается

Дополнительной характеристикой SD карты является скорость. Карты делятся на классы:

  • Class 2 2MB/s
  • Class 4 4MB/s
  • Class 6 6MB/s
  • Class 10 10MB/s

Спецификация SD является большой и всеобъемлющей. Если бы мы сами попытались реализовать спецификацию SD, мы бы рассмотрели целый ряд головоломок. Как таковой, распространено использование ранее существовавших реализаций спецификации, и, к счастью, ESP-IDF предоставляет нам именно это.

Существует также отличное примерное приложение, представленное в каталоге examples / storage / sd_card ESP-IDF.

Карта SD может использоваться для хранения данных, но не может использоваться для хранения кода команды для выполнения. Таким образом, SD-карта не должна рассматриваться как альтернатива флэш-памяти, доступной через SPI для хранения кода. SD-карту следует использовать для хранения данных приложения, которые могут быть прочитаны или записаны при запуске приложений.

See also:

  • Wikipedia: Multi Media Card
  • Wikipedia: Secure Digita l
  • SD Association