Библиотека FatFS: appnotes, указания по использованию Печать
Добавил(а) microsin   

В этой статье собраны общие рекомендации и указания, как использовать в своих проектах библиотеку FatFS.

  1. Как портировать библиотеку на другие платформы
  2. Ограничения
  3. Использование/расход памяти (Memory Usage)
  4. Сокращение размера модуля библиотеки
  5. Длинное имя файла (Long File Name, LFN)
  6. Unicode API
  7. Re-entrancy (повторный вход в процедуру, реентерабельность)
  8. Двойной доступ к файлу (Duplicated File Access)
  9. Эффективный доступ к файлу
  10. Носители памяти Flash (Flash Memory Media)
  11. Критическая секция кода (Critical Section)
  12. О лицензировании библиотеки FatFs

[Как портировать библиотеку FatFS на другие платформы]

Основные замечания

Для модуля FatFs имеются следующие условия для портирования.

  • ANSI C
    Модуль FatFs является промежуточным микропрограммным средством (middleware), которое написано в соответствии со стандартом ANSI C (C89). Нет никаких зависимостей от конкретной платформы, за исключением наличия компилятора, совместимого с кодом ANSI C.
  • Размерность целочисленных типов (integer types)
    Модуль FatFs подразумевает, что размер типов char/short/long является соответственно 8/16/32 бит, и размер int является 16 или 32 бит. Эти соответствия задаются в заголовочном файле integer.h. Такое условие не является проблемой для большинства компиляторов. Если произошел какой-то конфликт с уже имеющимися типами, Вы должны самостоятельно разрешить его.

Функции, которые могут понадобиться для портирования

Вам необходимо предоставить только низкоуровневые функции ввода/вывода диска (low level disk I/O), необходимые для модуля FatFs, и ничего более. Если рабочий модуль диска для Вашей платформы уже есть, то нужно написать только функции склейки, чтобы подключить их к модулю FatFs. Если такого модуля нет, то нужно портировать любой уже имеющийся дисковый модуль или написать его с нуля. Не всегда нужно реализовывать все функции их списка дискового модуля. Например, функция записи не нужна для конфигурации только для чтения (read-only). Следующая таблица показывает, какие функции нужны в зависимости от выбранных опций конфигурации.

ФункцияКогда нужна:Замечания
disk_initialize
disk_status
disk_read
Всегда Функции ввода/вывода диска (Disk I/O).
Примеры имеются в файле ffsample.zip.
Также в Интернете можно найти множество других реализаций.
disk_write
get_fattime
disk_ioctl (CTRL_SYNC)
_FS_READONLY == 0
disk_ioctl (GET_SECTOR_COUNT)
disk_ioctl (GET_BLOCK_SIZE)
_USE_MKFS == 1
disk_ioctl (GET_SECTOR_SIZE) _MAX_SS > 512
disk_ioctl (CTRL_ERASE_SECTOR) _USE_ERASE == 1
ff_convert
ff_wtoupper
_USE_LFN >= 1 Функции поддержки Unicode.
Доступны в option/cc*.c.
ff_cre_syncobj
ff_del_syncobj
ff_req_grant
ff_rel_grant
_FS_REENTRANT == 1 Функции, зависящие от операционной системы.
Примеры имеются в option/syscall.c.
ff_mem_alloc
ff_mem_free
_USE_LFN == 3

[Ограничения]

  • Поддерживаемые разновидности FAT: FAT12, FAT16 и FAT32.
  • Количество открытых файлов: не ограничено, ограничение может накладываться только количеством доступной памяти.
  • Количество томов: до 10 включительно.
  • Размер файла: зависит от спецификации FAT (до 4G-1 байт)
  • Размер тома: зависит от спецификации FAT (до 2T байт при 512 байт/сектор)
  • Размер кластера: зависит от спецификации FAT (до 64K байт при 512 байт/сектор)
  • Размер сектора: зависит от спецификации FAT (до 4K байт)

[Использование/расход памяти - Memory Usage (R0.09)]

 ARM7
32bit
ARM7
Thumb
Cortex-M3
Thumb-2
AVRH8/300HPIC24RL78V850ESSH-2ARX62NIA-32
Компилятор GCC GCC GCC GCC CH38 C30 CC78K0R CA850 SHC RXC VC6
_WORD_ACCESS 0 0 0 1 0 0 0 1 0 1 1
text (Full, R/W) 10459 7201 6623 12646 10686 11466 12967 7732 8752 5747 7545
text (Min, R/W) 6503 4745 4297 8306 6986 7440 8745 4938 5576 3746 4923
text (Full, R/O) 4535 3181 2869 5960 4876 5286 6060 3554 3804 2659 3450
text (Min, R/O) 3303 2493 2171 4366 3770 3984 4604 2684 2940 2025 2664
bss D*4 + 2 D*4 + 2 D*4 + 2 D*2 + 2 D*4 + 2 D*2 + 2 D*2 + 2 D*4 + 2 D*4 + 2 D*4 + 2 D*4 + 2
Work area
(_FS_TINY == 0)
V*560 +
F*550
V*560 +
F*550
V*560 +
F*550
V*560 +
F*544
V*560 +
F*550
V*560 +
F*544
V*560 +
F*544
V*560 +
F*544
V*560 +
F*550
V*560 +
F*550
V*560 +
F*550
Work area
(_FS_TINY == 1)
V*560 +
F*36
V*560 +
F*36
V*560 +
F*36
V*560 +
F*32
V*560 +
F*36
V*560 +
F*32
V*560 +
F*32
V*560 +
F*36
V*560 +
F*36
V*560 +
F*36
V*560 +
F*36

В таблице перечислены примеры расхода памяти на некоторых целевых системах при соответствующих указанных условиях. Объем памяти указан в байтах, V обозначает количество смонтированных томов, и F означает количество открытых файлов. Все примеры при компиляции оптимизированы на размер генерируемого кода (optimized in code size). Ниже перечислены опции конфигурации FatFS для этих примеров.

_FS_READONLY     0 (R/W), 1 (R/O)
_FS_MINIMIZE     0 (полный функционал), 3 (минимизированный функционал)
_USE_STRFUNC     0 (запрещены строковые функции)
_USE_MKFS        0 (запрет функции f_mkfs)
_USE_FORWARD     0 (запрет функции f_forward)
_USE_FASTSEEK    0 (запрет возможности быстрого позиционирования fast seek)
_CODE_PAGE       932 (кодовая страница Japanese Shift-JIS)
_USE_LFN         0 (запрещены длинные имена LFN)
_MAX_SS          512 (фиксированный размер сектора)
_FS_RPATH        0 (запрет относительных путей)
_VOLUMES         D (количество используемых логических дисков)
_MULTI_PARTITION 0 (один раздел на драйв - Single partition per drive)
_FS_REENTRANT    0 (запрет реентерабельности - reentrancy)
_FS_SHARE        0 (запрет контроля совместного использования файлов - sharing control)

[Сокращение размера модуля библиотеки]

Следующая таблица показывает, какие функции API будут удалены соответствующими опциями конфигурации - для уменьшения размера кода модуля FatFS.

Функция _FS_MINIMIZE _FS_READONLY _USE_STRFUNC _FS_RPATH _USE_MKFS _USE_FORWARD _MULTI_PARTITION
0 1 2 3 0 1 0   1/2 0 1 2 0 1 0 1 0/1 2
f_mount                                  
f_open                                  
f_close                                  
f_read                                  
f_write           x                      
f_sync           x                      
f_lseek       x                          
f_opendir     x x                          
f_readdir     x x                          
f_stat   x x x                          
f_getfree   x x x   x                      
f_truncate   x x x   x                      
f_unlink   x x x   x                      
f_mkdir   x x x   x                      
f_chmod   x x x   x                      
f_utime   x x x   x                      
f_rename   x x x   x                      
f_chdir                 x                
f_chdrive                 x                
f_getcwd                 x x              
f_mkfs           x           x          
f_fdisk           x           x       x  
f_forward                           x      
f_putc           x x                    
f_puts           x x                    
f_printf           x x                    
f_gets             x                    

[Длинное имя файла (Long File Name, LFN)]

Модуль FatFs теперь поддерживает длинные имена файлов и папок (LFN), начиная с ревизии 0.07. Два различных имени файла, SFN (Short File Name, короткое имя файла) и LFN (Long File Name, длинное имя файла) - являются прозрачными для вызовов файловых функций, за исключением функции f_readdir. Для разрешения возможности LFN нужно установить опцию _USE_LFN в значение 1, 2 или 3, и добавить в проект функции преобразования Unicode - ff_convert() и ff_wtoupper(). Включенная возможность поддержки LFN требует некоторой дополнительной памяти для рабочего буфера. Размер буфера можно сконфигурировать опцией _MAX_LFN - в соответствии с имеющимся количеством доступной памяти. Размер длинного имени может достигать до 255 символов, при этом _MAX_LFN должна быть установлена в значение 255 (полнофункциональная поддержка LFN). Если размер рабочего буфера недостаточен для предоставленного имени файла, то файловая функция завершится с кодом ошибки FR_INVALID_NAME. Когда опция LFN включена вместе с опцией реентерабельности (re-entrant feature), то опция _USE_LFN должна быть установлена в 2 или 3. В этом случае файловая функция выделяет рабочий буфер в стеке или в куче heap. Рабочий буфер занимает (_MAX_LFN + 1) * 2 байт.

Конфигурация LFN для ARM7
Кодовая страница (Code page)Размер программы
SBCS +3.7K
932(Shift-JIS) +62K
936(GBK) +177K
949(Korean) +139K
950(Big5) +111K

Когда включена опция LFN, размер кода модуля увеличится в зависимости от выбранной кодовой страницы. Таблица справа показывает на некоторых кодовых страницах (кодировках имен), сколько байт кода нужно дополнительно, когда возможность LFN включена. Жители Восточной Азии имеют десятки тысяч символов. К сожалению, это требует огромной таблицы для двунаправленного преобразования OEM-Unicode, и размер модуля значительно увеличится, что отображено в таблице. Как следствие, FatFs с включенной возможностью LFN, с DBCS не может быть реализована на большинстве 8-битных микроконтроллеров. Это одна из причин, по которой автор библиотеки длительное время не был заинтересован в реализации LFN. 

Внимание! Когда включена опция LFN (разрешены длинные имена, в файле ff.h задано #define _USE_LFN 1), поля lfname и lfsize в структуре FILINFO должны быть предварительно инициализированы до вызова функций, использующих переменную типа FILINFO (например, переменную FILINFO использует функция f_stat). Поле lfname является указателем на буфер, в котором будет сохранена строка с длинным именем файла. Поле lfsize содержит размер для этого буфера строки, указанный в единицах TCHAR. Этот указатель должен указывать на валидный буфер в RAM, иначе все функции, которые используют переменную FILINFO (например f_stat) могут привести к непрогнозированному поведению программы (обычно Data Abort или зависание). Кроме того, для доступа к файлам даже при включенных длинных именах нужно использовать короткое имя файла (поле fname), так как если имя файла по размеру меньше 8.3, то длинное имя будет пустым (0 == strlen(lfname)). Для дополнительной информации см. также описание функции f_readdir. Пример кода, где есть инициализация полей lfname и lfsize, дан в описании функции f_stat.

Имейте в виду, что возможность LFN на файловой системе FAT запатентована корпорацией Microsoft. Не так обстоит дело с FAT32. Когда в коммерческих продуктах разрешена опция LFN, может потребоваться лицензия от Microsoft - в зависимости от места применения.

[Unicode API]

API библиотеки FatFS поддерживает по умолчанию кодировку ANSI/OEM, однако FatFS можно также переключить в поддержку кодировки Unicode. Для более подробной информации см. описание системы именования файлов FatFS.

[Re-entrancy (повторный вход в процедуру, реентерабельность)]

Операции с файлами на разных томах всегда являются реентерабельными и могут работать одновременно. Файловые операции на одном и том же томе по умолчанию не реентерабельные, однако это можно сконфигурировать для потокозащищенного режима (thread-safe) опцией _FS_REENTRANT. Для этого случая нужны также зависящие от операционной системы функции управления объектом синхронизации - ff_cre_syncobj, ff_del_syncobj, ff_req_grant и ff_rel_grant, которые должны быть добавлены в проект.

Когда файловая функция вызвана на томе, который используется любой другой задачей, файловая функция будет приостановлена (suspended) до того момента, пока другая задача не освободит файловую функцию. Если время ожидания превысит период, заданный опцией _TIMEOUT, то файловая функция оборвет выполнение с ошибкой FR_TIMEOUT. Возможность отслеживания таймаута может не поддерживаться на некоторых RTOS (Real Time OS, операционная система реального времени).

Для функций f_mount и f_mkfs есть исключение. Эти функции не реентерабельные на одном и том же томе. Когда используются эти функции, то все остальные задачи должны закрыть соответствующие файлы на томе и избегать доступа к этому тому.

Имейте в виду, что эта секция описывает реентерабельность модуля FatFs самого по себе, однако низкоуровневые дисковые функции слоя ввода/вывода (low level disk I/O) должны быть также реентерабельными.

[Двойной доступ к файлу (Duplicated File Access)]

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

Управление совместным доступом может быть доступно, когда опция _FS_SHARE установлена в 1 или бОльшее значение. Это значение указывает количество файлов, которые могут быть обработано одновременно. Когда совместный доступ разрешен, то любая попытка нарушения совместного доступа при открытии (open), переименовании (rename) или удалении (remove) приведет к завершению файловой функции с ошибкой FR_LOCKED. Если количество открытых файлов превысит _FS_SHARE, то функция f_open function завершится с ошибкой FR_TOO_MANY_OPEN_FILES.

[Эффективный доступ к файлу]

Для получения хорошей производительности чтения/записи файлов на малых встраиваемых системах разработчик firmware должен представлять себе, как происходит этот процесс в модуле FatFs. Данные файла на диске передаются внутри  f_read в следующей последовательности (см. рисунки 1..3).

Рис. 1. Чтение сектора в случае отсутствия выравнивания (короткое) - Sector miss-aligned read (short)
FatFS-appnotes-f1

Рис. 2. Чтение сектора в случае отсутствия выравнивания (длинное) - Sector miss-aligned read (long)
FatFS-appnotes-f2

Рис. 3. Чтение сектора при выравнивании - Sector aligned read
FatFS-appnotes-f3

Файловый буфер ввода/вывода (file I/O buffer) означает буфер сектора для чтения/записи блока данных на секторе. Буфер сектора может быть либо отдельным для каждого файлового объекта (file object, т. е. файл), или общий используемый буфер сектора, привязанный к объекту файловой системы (file system object). Опция конфигурации _FS_TINY определяет, какой буфер сектора используется для передачи данных файла. Когда выбран маленький буфер - tiny buffer (1), затраты памяти уменьшаются до 512 байт на каждый файловый объект. В этом случае модуль FatFs использует только буфер сектора объекта файловой системы для передачи данных и доступа к каталогу FAT/директориям. Недостаток конфигурации tiny buffer следующая: данные FAT кэшируются в буфере сектора, и они должны быть потеряны при передаче данных файла и должны быть перезагружены на каждой границе кластера. Однако такое решение может подойти для большинства приложений с точки зрения незначительного снижения производительности при значительном экономии расхода памяти.

Рис. 1 показывает блок данных сектора передается через буфер I/O. На длинных передачах, как показано на рис. 2, промежуточные передаваемые данные (соответствующие одному или нескольким секторам) попадают напрямую в буфер приложения. Рис. 3 показывает случай, когда передаваемые данные выровнены на границу сектора. В этом случае, буфер I/O файла не используется. На прямой передаче максимальное количество секторов будет прочитано функцией disk_read за один раз, однако если мультисекторная передача не пересекает границу кластера, даже если кластеры идут непрерывно друг за другом.

Поэтому если взять на вооружение выровненный по секторам доступ на чтение/запись, которое позволяет избежать буферизированную передачу данных, то быстродействие чтения/записи возрастет. Помимо этого эффекта, кэшированные данные FAT не будут сбрасываться (flush) при передачи данных файла в конфигурации tiny, так что может быть достигнута та же производительность, как и в не tiny конфигурации, причем с малыми затратами памяти.

[Носители памяти Flash (Flash Memory Media)]

Чтобы добиться максимальной производительности записи на физическом носителе flash,  таких как SDC и CFC, эти носители должны управляться в соответствии с их характеристиками.

Использование многосекторной записи (Multiple-Sector Write)

Рис. 6. Сравнение методов записи - многосекторная и односекторная (Multiple/Single Sector Write)
FatFS-appnotes-f6

Пропускная способность носителей памяти flash ухудшается при одиночной записи сектора (single sector write) и увеличивается пропорционально количеству секторов на одну транзакцию записи. Этот эффект сильнее проявляется на шине с высокой тактовой частотой и скорость часто возрастает больше чем в 10 раз. Количество транзакций записи также влияет на время жизни носителя памяти (life time). Таким образом, программа приложения должна осуществлять запись блоками как можно бОльшего размера - чем блок больше, тем лучше. Идеальный размер блока равен размеру кластера, или степени числа 2 байт, и байтовое смещение должно быть выровнено по границе блока. Само собой, все слои между программой приложения и физическим носителем должны поддерживать возможность многосекторной записи, однако в большинстве случае open-source драйверы диска не уделяют этому достаточное внимание. Не разделяйте запрос на многосекторную запись на одиночные записи секторов, иначе получите плохую скорость записи. Обратите внимание, что модуль FatFs и сопутствующий пример драйверов диска поддерживают многосекторные чтение/запись.

Принудительная очистка памяти (Forcing Memory Erase)

Когда происходит удаление файла с помощью функции f_remove, то кластеры, в которых были записаны данные удаленного файла, помечаются как свободные (free) в каталоге FAT. Однако секторы данных, содержащие в себе данные файла, не прикладываются к любому процессу, так что данные остаются занятыми на носителе данных как live blocks. Если данные будут принудительно стерты (erased) при удалении файла, то количество свободных блоков на носителе увеличится. Эту операцию очистки можно опустить до момента следующей записи, тогда в этот момент при записи сработает внутренняя операция очистки блока. Если установить принудительную очистку при удалеAs the result the write performance might be improved. To enable this feature, set _USE_ERASE to 1. Note that this is a feature with expectation of internal process of the flash memory media. It may not always effective and f_remove function will take a time on removing a large file.

[Критическая секция кода (Critical Section)]

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

Рис. 4. Длинная критическая секция Рис.5. Минимизированная критическая секция
FatFS-appnotes-f4 FatFS-appnotes-f5

Прерывание в красной области может вызвать перекрестную ссылку (cross link); в результате изменяемый объект может быть потерян. Возможен один или более вариантов, перечисленных ниже, когда прерывание возникает в желтой области.

  • Перезаписанные данные файла будут испорчены.
  • Файл, в который добавлялись данные, вернется в начальное состояние.
  • Новый создаваемый файл исчезнет.
  • Новый создаваемый файл, или перезаписываемый файл потеряет свое содержимое.
  • Эффективность диска снизится, так как на нем появятся потерянные секторы.

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

[О лицензировании библиотеки FatFs]

Это копия лицензии FatFs, которая включена в исходные коды библиотеки.

/*----------------------------------------------------------------------------/
/  FatFs - FAT file system module  R0.09                     (C)ChaN, 2011
/-----------------------------------------------------------------------------/
/ FatFs module is a generic FAT file system module for small embedded systems.
/ This is a free software that opened for education, research and commercial
/ developments under license policy of following trems.
/
/  Copyright (C) 2011, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-----------------------------------------------------------------------------/

Перевод лицензии: "FatFs - модуль файловой системы FAT, версия R0.09 (C)ChaN, 2011. Модуль FatFs является программным модулем обычной файловой системы FAT, предназначенным для малых встраиваемых систем на микроконтроллерах. Это свободное программное обеспечение, которое открыто для обучения, исследования и коммерческих разработок при условии соблюдения следующих правил. Все права на библиотеку FatFs принадлежат ChaN. На эту библиотеку НЕ ДАЕТСЯ НИКАКИХ ГАРАНТИЙ. Нет ограничений на использование. Вы можете использовать и распространять код библиотеки для персональных, некоммерческих или коммерческих продуктов ПОД ВАШЕЙ СОБСТВЕННОЙ ОТВЕТСТВЕННОСТЬЮ. Распространяемый исходный код библиотеки должен содержать в себе указанные выше лицензионные замечания.". Таким образом, лицензия FatFs является одной из разновидностей лицензии BSD, однако есть одно большое отличие. Поскольку FatFs предназначена для встраиваемых проектов, то условия распространения в двоичной форме (такой как встраиваемый код, HEX-файл или двоичная библиотека) не определены с целью увеличения удобства использования. Документация дистрибутивов может как включать в себя FatFs и её лицензионный документ, так и не включать его. Разумеется, лицензия FatFs совместима с проектами, выпущенными под защитой лицензии GNU GPL. Когда библиотека распространяется с любой модификацией, лицензия может быть также изменена на GNU GPL или лицензию BSD-стиля.

[Ссылки]

1. FatFs Module Application Note site:elm-chan.org - указания по применению библиотеки FatFs (оригинал статьи на английском языке).
2Библиотека FatFS: модуль файловой системы FAT.
3. Библиотека EFSL (другая реализация файловой системы FAT).