Jump to content

    
Sign in to follow this  
__inline__

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

Recommended Posts

Добрый день.

 

Проблема такая.  Использую 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
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
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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this