Jump to content

    

FatFS и SD-карта. Ускорить чтение файлов с карты

Добрый день.

 

Проблема такая.  Использую SD-карту по SPI (SDIO нет и не будет), перевожу её в High Speed mode, всё успешно: статус-регистры возвращаются как надо.  Тактовая частота карты:  48 МГц. Прикрутил Fat FS ревизия 87030.   Файлы видятся, работает чтение.

 

 Но скорость чтения данных с файлов не радует.   6 файлов общим объёмом 10 МБ  читаются в течение 5,5 секунд.  SD карты 4-го и 10-го класса скоростей на ёмкость 16 ГБ.   Для чтения применяю мульти-секторную команду чтения (Read Begin, Read Data, Read End).   Пробовал закешировать первый мегабайт (начальные сектора карты) - не помогает, видать файлы находятся дальше.   Читаю с помощью fread()

 

Какие есть пути (программные) повышения скорости чтения данных файлов?  Нужно именно быстрое чтение данных, запись вообще не треуется.

 

Edited by __inline__

Share this post


Link to post
Share on other sites

А куда читаются файлы? Может, обработка содержимого файлов тормозит?

Share this post


Link to post
Share on other sites
1 hour ago, __inline__ said:

Какие есть пути (программные) повышения скорости чтения данных файлов?

Кэширование с упреждающим чтением (строками, как процессор заполняет кэш).

Share this post


Link to post
Share on other sites
25 minutes ago, AHTOXA said:

А куда читаются файлы? Может, обработка содержимого файлов тормозит?

Читаются большими блоками в память.

 

17 minutes ago, aaarrr said:

Кэширование с упреждающим чтением (строками, как процессор заполняет кэш).

Применительно к секторам карты ?

Share this post


Link to post
Share on other sites

Есть подозрение, что максимальные скорости доступны только по SDIO.

Share this post


Link to post
Share on other sites
2 minutes ago, jcxz said:

Есть подозрение, что максимальные скорости доступны только по SDIO.

Сравнивал время чтения файлов : в случае дефолтного режима (24 МГц)  и High Speed (48 МГц) - соответственно 7 и 5,5 с.

 

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

Share this post


Link to post
Share on other sites
2 минуты назад, __inline__ сказал:

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

Насколько помню - там есть команды как посекторного чтения так и мультисекторного. Да и вообще разные команды. Какие используете?

PS: А всё - вижу, не прочитал выше...

Share this post


Link to post
Share on other sites
8 минут назад, __inline__ сказал:

Сравнивал время чтения файлов : в случае дефолтного режима (24 МГц)  и High Speed (48 МГц) - соответственно 7 и 5,5 с.

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

при наличие свободной памяти смахните fat таблицу в память и попробуйте объяснить это fatfs, тут хоть немного будет ускорения при доступе к цепочке кластеров..

а вообще по однопроводке сильно быстро не будет, ваши 48МГц перемежаются старт-стопами spi и куча накладных расходов - проверьте сырую скорость считывания по интерфейсу и может проще будет сделать жесткую разбивку, допустим по 10МБ на файл при последовательном хранение с 0 сектора, а файлы обновлять через программную прослойку или через dd в линукс-машине

Share this post


Link to post
Share on other sites
22 минуты назад, Jury093 сказал:

тут хоть немного будет ускорения при доступе к цепочке кластеров..

а вообще по однопроводке сильно быстро не будет, ваши 48МГц перемежаются старт-стопами spi и куча накладных расходов

Тоже хотел это сказать, мне больше 3мб\сек по 1 проводу не удавалось выбить даже из самой скоростной карты...

Share this post


Link to post
Share on other sites
16 минут назад, mantech сказал:

Тоже хотел это сказать, мне больше 3мб\сек по 1 проводу не удавалось выбить даже из самой скоростной карты...

Это можно быстро глянуть осциллом или лог.анализатором. Вангую - там даже при чтении последовательной цепочки секторов будут большие дырки из 0xFF-ок между данными на MISO.

Тогда - только кешировать. На уровне секторов.

Share this post


Link to post
Share on other sites
22 minutes ago, jcxz said:

Это можно быстро глянуть осциллом или лог.анализатором. Вангую - там даже при чтении последовательной цепочки секторов будут большие дырки из 0xFF-ок между данными на MISO.

 

Да, так оно и есть. львиная доля времени уходит на получение ответа готовности карты выдать ОЧЕРЕДНУЮ порцию данных по 512 байт.  Хоть и мультисекторная команда.

Код:

 

DRESULT MMC_disk_read(BYTE* buff,DWORD sector,UINT count)
{
 SDCARD_ReadBegin(sector);
 for(u32 i=0;i<count;i++)SDCARD_ReadData(&buff[i<<9]);
 SDCARD_ReadEnd();

 return RES_OK; //all OK
}

s8 SDCARD_ReadBegin(u32 blockNum) {
    SDCARD_Select();

      SDCARD_WaitNotBusy();

    /* CMD18 (READ_MULTIPLE_BLOCK) command */
    u8 cmd[] = {
        0x40 | 0x12 /* CMD18 */,
        (blockNum >> 24) & 0xFF, /* ARG */
        (blockNum >> 16) & 0xFF,
        (blockNum >> 8) & 0xFF,
        blockNum & 0xFF,
        (0x7F << 1) | 1 /* CRC7 + end bit */
    };
    SPI_TX((u8*)cmd,sizeof(cmd));

    if(SDCARD_ReadR1() != 0x00) {
        SDCARD_Unselect();
        return -2;
    }

    SDCARD_Unselect();
    return 0;
}

s8 SDCARD_ReadEnd(void) {
    SDCARD_Select();

    /* CMD12 (STOP_TRANSMISSION) */
    {
        static const u8 cmd[] = { 0x40 | 0x0C /* CMD12 */, 0x00, 0x00, 0x00, 0x00 /* ARG */, (0x7F << 1) | 1 };
        SPI_TX((u8*)cmd,sizeof(cmd));
    }


   SPI(0xFF);

    if(SDCARD_ReadR1() != 0x00) {
        SDCARD_Unselect();
        return -2;
    }
    
    SDCARD_Unselect();
    return 0;
}

static inline s8 SDCARD_ReadData(u8* buff)
{
 SDCARD_Select();

 if(SDCARD_WaitDataToken(DATA_TOKEN_CMD18)<0)
 {
  SDCARD_Unselect();
  return -1;
 }

 SDCARD_ReadBytes(buff,512);

 SPI(0xFF);
 SPI(0xFF);

 SDCARD_Unselect();

 return 0;
}

static inline void SDCARD_ReadBytes(u8* buff, u32 buff_size)
{
 while(buff_size>0)
 {
  *buff++=SPI(0xFF);
  buff_size--;
 }
}

 

Как видно, между полезными данными куча служебной лабуды...

 

Интересную тему нашёл: https://electronix.ru/forum/index.php?app=forums&module=forums&controller=topic&id=78105&page=1

 

То что описал уважаемый aarrrr - замечательно,  в моём случае такой подход к кешированию поможет?   Оперативной памяти под кеш могу до 8 МБ занять.     Файлы читаю разом - крупным блоком сразу:  открыл - считал - закрыл.   Далее следующий файл...   Файлов много (больше 10, меньше 100), есть папки с уровнем вложенности до 3,  размер файлов 100 кБ - 20 МБ

 

36 minutes ago, mantech said:

Тоже хотел это сказать, мне больше 3мб\сек по 1 проводу не удавалось выбить даже из самой скоростной карты...

 

3 мега-бита в секунду?  Тогда 10 МБ должно открыться за 3,5 с,   а не за 5,5 как в моём случае ))

 

59 minutes ago, Jury093 said:

при наличие свободной памяти смахните fat таблицу в память и попробуйте объяснить это fatfs, тут хоть немного будет ускорения при доступе к цепочке кластеров..

а вообще по однопроводке сильно быстро не будет, ваши 48МГц перемежаются старт-стопами spi и куча накладных расходов - проверьте сырую скорость считывания по интерфейсу и может проще будет сделать жесткую разбивку, допустим по 10МБ на файл при последовательном хранение с 0 сектора, а файлы обновлять через программную прослойку или через dd в линукс-машине

 

Есть ли способ быстро узнать стартовый сектор и размер таблицы FAT? Используется FAT32 с LFN

Edited by __inline__

Share this post


Link to post
Share on other sites
2 часа назад, __inline__ сказал:

Есть ли способ быстро узнать стартовый сектор и размер таблицы FAT? Используется FAT32 с LFN

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

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

ЗЫ я в fat32 заглядывал лет 10 назад, когда к atmega прикручивал fat16 и целился подключить hdd. т.ч. больше знаний нет

Share this post


Link to post
Share on other sites
4 часа назад, __inline__ сказал:

3 мега-бита в секунду?

2-3.5 мегабайта в сек, по среднему, где-то 2.5, на файлах поменьше, полтора мегабайта - это максимум, карта - трансенд, на всяких смартбаях еле до полутора дотягивало.

4 часа назад, __inline__ сказал:

То что описал уважаемый aarrrr - замечательно,  в моём случае такой подход к кешированию поможет?

Кеширование файлов не поможет, ФС - возможно. Кеш файлов использовал только для распаковки картинок, т.к. в том же GIF требуется постоянное обращение за несколькими десятками байт - вот там кэш на 16-30Кбайт очень помог - скорость стала на порядок выше, с анимацией - еще больше, но если читать большие линейные куски - выигрыша нет совсем. Кэш заметно помогает при записи, но там своих проблем тоже не мало..

4 часа назад, __inline__ сказал:

Да, так оно и есть. львиная доля времени уходит на получение ответа готовности карты выдать ОЧЕРЕДНУЮ порцию данных по 512 байт. 

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

ЗЫ, да и по 512 байт уже давно никто не читает, 4К - сейчас это минимум..

Edited by mantech

Share this post


Link to post
Share on other sites
7 hours ago, mantech said:

ЗЫ, да и по 512 байт уже давно никто не читает, 4К - сейчас это минимум..

Не могли бы вы осветить этот момент подробнее? Пробовал читать больше чем по 512 байт:  по 1024 и по 4096 - файловая система работает некорректно с такими длинами чтений.

Интересует  SDCARD_ReadData(u8* buff)

Там после каждых 512 байт надо делать опрос SDCARD_WaitDataToken(DATA_TOKEN_CMD18)<0)  , иначе неправильно работает.

 

Прорабатываю вариант без LFN, имена директорий и файлов в формате 8.3

Share this post


Link to post
Share on other sites
1 hour ago, __inline__ said:

Прорабатываю вариант без LFN, имена директорий и файлов в формате 8.3

Прироста в скорости переход с LFN на 8.3 не дал. Флажок в ffconf LFN выставлен в 0.

 

Тут пишут, что мультиблочное чтение всёравно должно идти порциями по 512 байт и нужно ждать дата-токена и считывать 2 байта CRC.   Разом не считаешь без дата-токена - нужно ждать. А это плохо.

https://www.avrfreaks.net/forum/writeread-multiple-blocks-sd-card-0

 

Read multiple blocks is same as above except:

Send READ_MULTIPLE_BLOCK command to card with address, number of blocks etc
Repeat for number of blocks
{
 Poll card for 0xFE (data token)
 Receive the 512 bytes.
 receive 2 CRC bytes
}

+ READ END CMD

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now