ESP8266 Урок 31. FreeRTOS. Файловая система SPIFFS



Продолжаем работу по программированию микроконтроллера ESP8266 с использованием операционной системы реального времени FREEFTOS.

На прошлом уроке мы убедились, что мы вполне можем передавать по протоколу HTTP документы с нашего сервера клиенту. Только мы столкнулись с проблемой их неудобного хранения на нашем сервере, а именно при помощи массива. Хотелось бы как-то хранить их в явном виде — в виде файлов. Помочь нам в этом сможет то, что у контроллера ESP8266 (как впрочем и у ESP32) есть своя файловая система SPIFFS (Serial Peripheral Interface Flash File System). Вернее даже будет сказать, что она есть не у контроллера, а содержится в API SDK. Данная файловая система размещается в свободном пространстве FLASH-памяти, а так как у нас её 4 мегабайта, а для прошивки нам много места не нужно, мы до сих пор вполне умещаемся в 500 килобайтах в начале памяти, то мы вполне можем использовать некоторое пространство для файловой системы. На всякий случай мы для прошивки оставим полностью первый мегабайт, а дальше уже будем размещать файловую систему. 1-2 мегабайта нам вполне хватит для размещения служебных файлов сервера. Также в технической документации мы можем прочитать то, что на файловую систему SPIFFS наложен ряд ограничений, как то невозможность создавать директории, ограниченный размер имени файла и т.д. Но, так как хранить нам придётся немного, мы вполне в рамках данных ограничений уместимся.

Итак, SDK нам предоставляет некоторый функционал по работе с файловой системой SPIFS. Последний комплект даже предоставляет намного больше, но пока мне его, к сожалению, не удалось прикрутить к работе под Windows.

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

Также существует утилита для добавления в образ файловой системы файлов mkspiffs, но к сожалению у меня она корректно работает только для контроллера ESP32. Поэтому будем пока обходиться другими средствами, также мы этой невозможностью будем мотивированы для создания проекта по добавлению файлов через браузер в дальнейшем.

Плату мы будем использовать ту же самую, что и на прошлом уроке

 

 

Проект мы также с именем WIFI_STA_HTTP_SERVER_RTOS возьмём из прошлого урока и на его основе создадим проект с именем SPIFFS_RTOS.

Откроем наш проект в Eclipse, и, так как мы не будем работать ни с дисплеем, ни с сетью, то мы вполне можем себе позволить удалить из проекта файлы i2c_user.c, i2c_user.h, wifi.c и wifi.h.

Удалим из кода во всех файлах подключение заголовочных файлов i2c_user.h и wifi.h к проекту.

В файле main.c из бесконечного цикла функции task1 удалим мониторинг сетевого адреса

 

wifi_get_ip_info(STATION_IF, &ipinfo);

os_printf(«Addr STA: %s\n», inet_ntoa(ipinfo.ip));

 

Также удалим до бесконечного цикла вот этот код

 

struct ip_info ipinfo;

uint32_t ip;

char ip_char[17];

snprintf(ip_char, sizeof(ip_char), «%s», «192.168.0.1»);

ip = ipaddr_addr(ip_char);

memcpy(&ipinfo.ip, &ip, 4);

 

Также в теле функции user_init() удалим инициализацию Wi-Fi-станции

 

init_esp_wifi();

//start_wifi_ap(WIFI_APSSID, WIFI_APPASSWORD);

start_wifi_station(WIFI_CLIENTSSID, WIFI_CLIENTPASSWORD);

 

Теперь у нас проект соберётся.

Для удобной работы с файловой системой создадим под это два файла — user_spiffs.h и user_spiffs.c следующего содержания

 

 

 

Также подключим вновь созданную библиотеку в файле main.h

 

 

В файле user_spiffs.c добавим функцию инициализации, которая ничего не будет принимать во входных параметрах и будет возвращать результат, успешно ли прошла инициализация файловой системы SPIFFS

 

 

Объявим в заголовочном файле на данную функцию прототип и, перейдём в функцию user_init() файла main.c и также сначала объявим целочисленную переменную

 

 

Вызовем нашу функцию инициализации SPIFFS и по результату проверим, успешно ли у нас прошла инициализация, если нет, то в терминальной программе об этом скажем и выйдем из программы

 

 

Вернёмся в файл user_spiffs.c в функцию spiffs_init и объявим ещё одну целочисленную переменную, которая там также в дальнейшем понадобится

 

 

Для первичной инициализации нам потребуется объявление переменной типа конфигурационной структуры

 

 

Далее нам потребуется заполнить поля данной переменной. Для этого мы в файле user_spiffs.h объявим вот такие макросы

 

 

Мы пока будем работать с файловой системой размером чуть меньше одного мегабайта, расположим её с адреса 0x110000, зададим размер страницы 256 байт, размер сектора (как и блока) в 4 килобайта.

Вернёмся в файл user_spiffs.c и, используя наши макросы, проинициализируем поля

 

 

И теперь, воспользовавшись данной переменной типа структуры, вызовем функцию инициализации файловой системы SPIFFS библиотеки SDK

 

 

Если мы после этого попытаемся собрать проект, то у нас этап компиляции пройдёт успешно, а на этапе линковки мы, скорее всего получим вот такую ошибку

 

 

Эта ошибка говорит о неподключенной библиотеке. Так как весь функционал библиотеки SDK для SPIFFS с закрытым кодом, то мы видим пока только заголовки. Поэтому в makefile вот здесь подключим нужную библиотеку

 

@$(LD) -L$(SDK_LIBDIR) $(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) build/app_app.a $(SDK_LIBDIR)/libdriver.a $(SDK_LIBDIR)/libspiffs.a -Wl,--end-group -o build/app.out

 

Вот теперь всё нормально соберётся.

Далее нам нужно примонтировать нашу файловую систему, чтобы мы затем спокойно могли к ней обращаться.

Для этого сначала в файле user_spiffs.c добавим функцию выше функции spiffs_init

 

 

Добавим на данную функцию прототип в заголовочном файле.

 

 

В теле данной функции объявим переменную другой структуры

 

 

Используя те же макросы, а также имена функций обратного вызова файловых операций, которые мы напишем позже, в функции инициализации spiffs_init файла user_spiffs.c инициализируем поля нашей переменной

 

 

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

Для начала объявим несколько глобальных переменных

 

 

Следующая функция будет при операции стирания выводить в терминал при ошибке соответствующие сообщения, стирать нужный сектор и возвращать результат данной операции

 

 

Далее объявим макрос, который будет нам нужен ниже

 

 

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

 

 

Следующие две функции простые — одна для чтения другая для записи, и они при этом вызывают предыдущую функцию с разницей в флаге записи

 

 

Следующая функция будет вызываться при стирании информации

 

 

Следующая — при чтении

 

 

 

Следующая — при записи

 

 

Вернёмся в функцию mount_fs и обнулим следующие массивы

 

 

Вызовем функцию монтирования файловой системы и запишем результат в переменную

 

 

В последнем параметре вызове функции монтирования находится указатель на функцию обратного вызова проверки согласованности.

Добавим данную функцию в наш код

 

 

Функция эта ничего не возвращает, лишь только отправляет информацию в терминальную программу при различных операциях и ошибках.

В функции spiffs_init вызовем нашу функцию, проверим результат и в случае ошибки выведем соответствующее сообщение в терминал

 

 

Теперь перейдём в файл main.c и попробуем как-то воспользоваться нашей файловой системой. Подключим глобальную переменную, предоставляющую доступ к нашей файловой системе

 

 

Вначале нам желательно будет отформатировать наш виртуальный раздел. Хотя практика показала, что это необязательно, но мы хотя бы проверим, что у нас работает функционал. В документации написано, что, прежде чем форматировать систему, нужно её примонтировать и затем отмонтировать. Так как она у нас уже примонтирована, то мы должны её только отмонтировать. Для этого в функции user_init() вызовем следующую функцию

 

 

Объявим целочисленную локальную переменную

 

 

Теперь попробуем отформатировать нашу систему и проверить результат

 

 

Дальше мы должны её примонтировать обратно

 

 

Попробуем создать файл. Для этого мы воспользуемся массивом файла из проекта прошлого занятия. Объявим его и проинициализируем

 

 

Вернёмся в user_init и попытаемся создать файл

 

 

Объявим локальную переменную для дискриптора файла

 

 

Откроем файл на чтение и запись

 

 

Попытаемся записать в него данные массива

 

 

Закроем файл

 

 

Теперь нам как-то надо узнать, что файл у нас появился. Для начала узнаем информацию вообще о файловой системе — каков её размер и сколько его уже занято.

В функции task1 объявим две переменных

 

 

В бесконечном цикле узнаем наши размеры

 

 

Соберём проект, прошьём контроллер и посмотрим, что у нас вышло.

На этапе инициализации мы видим только служебные сообщения, никаких сообщений об ошибках мы не видим

 

 

Значит весь этап инициализации и создания файла прошел успешно. А вот информация в бесконечном цикле

 

 

Отлично!

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

 

 

Думаю, здесь всё понятно. Мы объявляем переменную структуры DIR для доступа к директории, затем объявляем ещё одну подобную переменную, только для одной файловой записи в каталоге, затем переменную-указатель на неё, читаем каталог, пробегаемся по списку, выводя информацию о каждой записи.

Прежде чем это пробовать, в функции user_init() закомментируем форматирование, повторное монтирование, а также создание файла и запись в него, чтобы у нас каждый раз всё заново не пересоздавалось, так как содержимое файловой системы не затирается при повторной прошивке кода и никуда у нас ничего не денется

 

 

Соберём код, прошьём контроллер и посмотрим, что у нас выведется

 

 

У нас есть один файл, у него есть имя, идентификатор, а также он имеет определённый размер. Отлично!

Теперь давайте в user_init() просто прочитаем содержимое нашего файла, для чего мы уже откроем файл только на чтение. Для начала объявим небольшой буфер

 

 

Теперь после закомментированного кода проделаем наши операции

 

 

Испытаем наш код, собрав проект и прошив контроллер

 

 

Содержимое нашего файла полностью вывелось в терминальную программу.

Итак, на данном уроке мы научились пользоваться файловой системой SPIFFS. Пусть мы её освоили только немного, это лишь один урок. Но, тем не менее, мы теперь умеем её создать, отформатировать, создавать и читать файлы, а также выводить информацию о размере, свободном месте, а также список файлов с именами, идентификаторами и их размерами. Согласитесь, для одного урока это немало. Причём это не в IDE Arduino, а с использованием чистого SDK.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование МК ESP8266 Следующий урок

 

Исходный код

 

 

Модуль ESP NodeMCU можно купить здесь: Модуль ESP NodeMCU

Различные модули ЕSP8266 можно приобрести здесь Модули ЕSP8266

Дисплей LCD 20×4 можно приобрести здесь Дисплей LCD 20×4

Дисплей LCD 16×2

Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

ESP8266 FreeRTOS. Файловая система SPIFFS

2 комментария на “ESP8266 Урок 31. FreeRTOS. Файловая система SPIFFS
  1. megger380:

    Спасибо! Очень интересно! А где видео?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*