• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Решено SPIFFS - задержки при чтении

JohnSmith

New member
Здравствуйте.
Пытаюсь сделать на NodeMCU проигрыватель небольшого количества коротких WAV-файлов в формате 44кHz 16bit 2ch через I2S, расположенных на SPIFFS. Столкнулся с проблемой, что при циклическом чтении файла в буфер (256 байт или больше), иногда возникают задержки до 50мс, не приемлемые для непрерывного воспроизведения файлов с таким качеством.

Если включить вывод отладочной информации в файле spiffs_config.h, то создается впечатление что задержки совпадают с множественным вызовом функций работы с кэшем spiffs_cache_page_allocate и spiffs_cache_page_free. Я пробовал отключить кэш:
Код:
#define SPIFFS_CACHE 0
Но код при этом не компилируется, так как отключается тело функции, которая вызывается из файла spiffs_api.h:
Код:
size_t cacheBufSize = SPIFFS_buffer_bytes_for_cache(&_fs, _maxOpenFds);
cacheBufSizeв случае с включенном кэшем равно 1400, и если кэш отключить и прописать статично 1400 либо 0 или другое значение - то после компиляции и прошивки ESP уходит в BSOD.

Также я заметил, что на задержки влияют размер файла, заполненность SPIFFS, режим Flash Size 4M (1M SPIFFS), или 4M (3M SPIFFS).

Помимо прочего, есть опасения, что попалась битая микросхема флэш.
Я буду очень признателен, если мне кто-нибудь подскажет, что является причиной этих задержек и есть ли способ от них избавиться. Возможно ли как-нибудь отключить использование кэш и проверить флэш-память на бэды.
Спасибо.
Код:
#include <FS.h>

#define BUFFER_LEN 256
static uint8_t buffer[BUFFER_LEN];

void readFile(const char *fileName)
{
    File f;
    unsigned long time1, time2;

    f = SPIFFS.open(fileName, "r");
    unsigned long readedBytesCount = 1, readedBytesCountTotal = 0;

    while (readedBytesCount > 0)
    {
        time1 = micros();
        readedBytesCount = f.read((uint8_t *)buffer, BUFFER_LEN);
        time2 = micros();

        if (time2 - time1 > 1000)
            Serial.printf("Readed: %lu bytes, last %d bytes reading time: %luus\r\n", readedBytesCountTotal + readedBytesCount, BUFFER_LEN, time2 - time1);

        readedBytesCountTotal += readedBytesCount;
    }
    Serial.printf("File readed: %lu bytes\r\n", readedBytesCountTotal);
    f.close();
}

void setup()
{
    Serial.begin(115200);
    if (!SPIFFS.begin())
    {
        Serial.println("SPIFFS.begin() failed");
        return;
    }
}

void loop()
{
    readFile("/ST1.wav");
    delay(500);
}
Код:
Reading file: /ST1.wav
Readed: 26368 bytes, last 256 bytes reading time: 2631us
Readed: 57600 bytes, last 256 bytes reading time: 1441us
Readed: 88832 bytes, last 256 bytes reading time: 1178us
Readed: 119808 bytes, last 256 bytes reading time: 1172us
Readed: 151040 bytes, last 256 bytes reading time: 1029us
Readed: 182016 bytes, last 256 bytes reading time: 1644us
Readed: 213248 bytes, last 256 bytes reading time: 1577us
File readed: 264646 bytes

Reading file: /ST2.wav
Readed: 26368 bytes, last 256 bytes reading time: 1392us
Readed: 57600 bytes, last 256 bytes reading time: 1063us
Readed: 88832 bytes, last 256 bytes reading time: 1708us
Readed: 119808 bytes, last 256 bytes reading time: 1457us
Readed: 151040 bytes, last 256 bytes reading time: 1200us
Readed: 182016 bytes, last 256 bytes reading time: 1187us
Readed: 213248 bytes, last 256 bytes reading time: 1065us
Readed: 244224 bytes, last 256 bytes reading time: 1331us
File readed: 264646 bytes

Reading file: /ST3.wav
Readed: 26368 bytes, last 256 bytes reading time: 1427us
Readed: 57600 bytes, last 256 bytes reading time: 1596us
Readed: 88832 bytes, last 256 bytes reading time: 1047us
Readed: 119808 bytes, last 256 bytes reading time: 1057us
Readed: 151040 bytes, last 256 bytes reading time: 1742us
Readed: 182016 bytes, last 256 bytes reading time: 1447us
Readed: 213248 bytes, last 256 bytes reading time: 1334us
File readed: 264646 bytes

Reading file: /ST4.wav
Readed: 26368 bytes, last 256 bytes reading time: 1391us
Readed: 57600 bytes, last 256 bytes reading time: 1040us
Readed: 88832 bytes, last 256 bytes reading time: 1728us
Readed: 119808 bytes, last 256 bytes reading time: 1472us
Readed: 182016 bytes, last 256 bytes reading time: 1309us
Readed: 213248 bytes, last 256 bytes reading time: 1593us
File readed: 264646 bytes

Reading file: /ST5.wav
Readed: 57600 bytes, last 256 bytes reading time: 1733us
Readed: 88832 bytes, last 256 bytes reading time: 1060us
Readed: 119808 bytes, last 256 bytes reading time: 1735us
Readed: 151040 bytes, last 256 bytes reading time: 1048us
Readed: 182016 bytes, last 256 bytes reading time: 1083us
Readed: 213248 bytes, last 256 bytes reading time: 1449us
File readed: 264646 bytes

Reading file: /ST6.wav
Readed: 26368 bytes, last 256 bytes reading time: 1141us
Readed: 57600 bytes, last 256 bytes reading time: 1731us
Readed: 88832 bytes, last 256 bytes reading time: 1212us
Readed: 151040 bytes, last 256 bytes reading time: 7437us
Readed: 182016 bytes, last 256 bytes reading time: 5333us
Readed: 213248 bytes, last 256 bytes reading time: 5589us
Readed: 244224 bytes, last 256 bytes reading time: 3511us
File readed: 264646 bytes

Reading file: /ST7.wav
Readed: 26368 bytes, last 256 bytes reading time: 5801us
Readed: 57600 bytes, last 256 bytes reading time: 5601us
Readed: 88832 bytes, last 256 bytes reading time: 4966us
Readed: 119808 bytes, last 256 bytes reading time: 5627us
Readed: 151040 bytes, last 256 bytes reading time: 5766us
Readed: 182016 bytes, last 256 bytes reading time: 5061us
Readed: 213248 bytes, last 256 bytes reading time: 4623us
Readed: 244224 bytes, last 256 bytes reading time: 2891us
File readed: 264646 bytes

Reading file: /ST8.wav
Readed: 26368 bytes, last 256 bytes reading time: 4216us
Readed: 57600 bytes, last 256 bytes reading time: 4262us
Readed: 88832 bytes, last 256 bytes reading time: 4639us
Readed: 119808 bytes, last 256 bytes reading time: 4635us
Readed: 151040 bytes, last 256 bytes reading time: 1848us
Readed: 182016 bytes, last 256 bytes reading time: 3467us
Readed: 182272 bytes, last 256 bytes reading time: 51903us
Readed: 182528 bytes, last 256 bytes reading time: 51931us
Readed: 182784 bytes, last 256 bytes reading time: 51900us
Readed: 183040 bytes, last 256 bytes reading time: 51932us
...
...
 

Вложения

  • 100.8 KB Просмотры: 5

JohnSmith

New member
Проблема решилась, дело оказалось не в микросхеме. Вместо SPIFFS, решил читать через spi_flash_read(). Чтение 3 Мб теперь занимает 0.4с то есть скорость чтения составляет 7.5 Мб/с.

Если сравнивать с предыдущими результатами, то чтение максимум, что влезло в формате SPIFFS = 2.54 Мб занимает 44 секунды, то есть скорость 58 Кб/с, что немного странно.
 
Последнее редактирование:

qwedhinet

New member
Здравствуйте!
Вы могли бы поделиться подробнее как с этой библиотекой работать, плата тоже Node и тоже проблема со скоростью.
А с этой библиотекой ни прошить не получилось да и толком понять какими методами пользоваться тоже(
Может примеры скетчей покажите, как вы на практике ее применили. C этой памятью еще же сама esp работает, получается надо адреса точно прописывать?
Заранее спасибо!
 
Последнее редактирование:

JohnSmith

New member
Приветствую. Не совсем понял, вы имеете в виду библиотеку spiffs? Просто я ведь написал что отказался от ее использования. Хотя через нее заливать файлы на флэшку удобно, так же как и выполнять операции с файлами, единственный минус - скорость работы получается не высокая. Так как в моем проекте скорость была критически важной, то пришлось отказаться от файловой системы и читать с флэшки нужные области памяти. Просто не очень понял что вам нужно, опишите подробнее вашу проблему или лучше создайте отдельную тему.
 

qwedhinet

New member
Спасибо за ответ!
Уж очень хочется использовать память этого зверя на адекватной скорости =)
Веб страничка общим весом 100Кб грузится 17 секунд.
Вы файлы тоже заливаете библиотекой SPIFlash? С чего, то есть как выглядит подключение источника к esp?
Подскажите, пожалуйста, какой пин (FLASH_SS) указываете при работе с памятью esp? Очень интересно разобраться с этой библиотекой, а информации почти нет.
Возможно считать файл записанный с помощью SPIFFS, точнее как узнать адрес его начала? И будет ли в этом смысл?
Вы пришли к какому нибудь мнению насчет того почему SPIFFS так медленно работает? На Вашем примере почти в 100 раз...
Еще раз заранее спасибо!
 

JohnSmith

New member
Похоже у нас с вами задачи сильно различаются и есть вероятность, что мой подход вам не подойдет. Вы уверены, что у вас проблемы из-за SPIFFS? Потому что 100 кб за 17 секунд это прям как-то совсем медленно.

В моем варианте в памяти должно находиться всего два-четыре файла и критически важна высокая скорость, поэтому пришлось отказаться от SPIFFS. При этом нужно самому организовать структуру этих файлов - как вы их запишете, так они и будут лежать. Например, самый простой вариант:
Код:
0x00000000 : [название файла №1 - 24 байта] [смещение файла №1 - 4 байта] [размер файла №1 - 4 байта]
0x00000020 : [название файла №1 - 24 байта] [смещение файла №2 - 4 байта] [размер файла №2 - 4 байта]
...
[смещение файла №1] : [Даннные файла №1]
[смещение файла №2] : [Даннные файла №2]
...
То есть скомпоновать таким образом один файл, назовем его data.bin - я делал это на питоне. Если указать в ардуине Tools - Flash Size : 4M (3M SPIFFS), то размер файла этого с данными (data.bin) должен быть 3125248 байт, чтобы записать нашими данными сразу всю свободную область микросхемы spi flash. То есть конец добиваем нулями до размера 3125248, если хотим, чтобы не было остатков от предыдущих прошивок в конце, но это не обязательно.

Затем эту область с данными я прошивал командой:
esptool.exe -cd nodemcu -cb 921600 -cp COM3 -ca 0x100000 -cf data.bin
esptool обычно лежит здесь "%AppData%\..\Local\Arduino15\packages\esp8266\tools\esptool\0.4.9\esptool.exe"

Функция spi_flash_read() как оказалось, подвешивала МК, вместо нее читал через:
ESP.flashRead(uint32_t offset, uint32_t *data, size_t size) - она работает также быстро, но проблем с зависанием нет. Читать надо начиная с того же адреса, куда прошивали - 0x100000. В моем случае, я читал по 64 байта в стек и отправлял их через DMA в I2S и дальше на внешний ЦАП для вывода звука. Для записи чего-то с МК в spi flash можно пользоваться
ESP.flashWrite(uint32_t offset, uint32_t *data, size_t size)
Удачи!
 
Последнее редактирование:

pvvx

Активный участник сообщества
примере почти в 100 раз...
Бывает и более, особенно при дефрагментированной структуре диска на SPIFFS. Особенно на функции открытия файла - до пару секунд. Это норма для SPIFFS, т.к. он создан для работы в малой памяти древних MCU за счет понижения скорости.
Веб страничка общим весом 100Кб грузится 17 секунд.
Страница грузиться медленно, по причине неправильного метода отправки. У вас на каждый TCP блок в 1.5 кило уходит 200 ms задержки приемного стека TCP на приемном устройстве до подтверждения доставки.
Передавать надо сразу по 2 блока TCP, тогда задержки подтверждения у приемника не будет.
https://support.microsoft.com/en-us...ing-small-data-segments-over-tcp-with-winsock
Данные проблемы неоднократно обсуждались на форуме, по тому ответ краткий - поищите и найдете более развернутые...
 

qwedhinet

New member
Еще раз спасибо!
Много вопросов прояснили, не так все просто.
Надо переварить, нужно ли оно мне.
Действительно, стоит повнимательнее к альтернативам присмотреться.
 
Сверху Снизу