РадиоЛоцман - Все об электронике

Использование SD-карт в малых встраиваемых системах. Часть 2

Журнал РАДИОЛОЦМАН, декабрь 2013

Михаил Русских

Часть 1.

Вебинар «Новинки и решения Traco для промышленных и отраслевых приложений» (28.10.2021)

Рассматривается библиотека FatFs, позволяющая работать с файловой системой FAT на SD-карте

Для того чтобы записанные на SD-карту данные можно было прочесть на компьютере, они должны быть упорядочены в соответствии со структурой файловой системы FAT (File Allocation Table или таблица размещения файлов). Для облегчения труда разработчиков малых встраиваемых систем при реализации таблицы FAT программистом под псевдонимом ChaN была написана библиотека FatFs [1], которая быстро приобрела популярность благодаря тому, что ее функциональность позволяет выполнять действия, характерные для серьезных операционных систем при работе с файлами и папками. На данный момент доступна версия R0.10, которая вышла в середине октября 2013 года.

Эта библиотека написана на ANSI C и состоит из нескольких файлов. Она представляет собой связующее программное обеспечение (middleware) между приложением и аппаратным интерфейсным модулем (Рисунок 3). Это значит, что библиотека не зависит от аппаратной части и может быть использована с любым микроконтроллером. Портирование, то есть написание кода, связывающего аппаратную часть с FatFs, должен выполнить сам разработчик встраиваемой системы.
 

Использование SD-карт в малых встраиваемых системах
Рисунок 3. Место библиотеки FatFs в программной структуре малой встраиваемой системы.

В библиотеку входят следующие файлы:

  • ff.c и ff.h – являются основой FatFs, поскольку определяют функции, необходимые для работы с файловой системой.
  • diskio.c и diskio.h – отвечают за низкоуровневый интерфейс, эти файлы должны быть изменены разработчиком в соответствии с используемым способом связи с носителем.
  • integer.h – в этом файле можно задать используемые в библиотеке ключевые слова, определяющие тип данных, например, typedef int INT. Следует учитывать возможности этого файла при переходе с 8 разрядной системы на 32 разрядную и наоборот.
  • ffconf.h – здесь определяются настройки библиотеки, например, #define _FS_READONLY 0 разрешает чтение и запись на носитель, при выборе 1 запись была бы запрещена.

На Рисунке 4 показана взаимосвязь файлов библиотеки FatFs с приложением и отвечающими за работу модуля SDIO файлами, описанными в предыдущей части.

Использование SD-карт в малых встраиваемых системах
Рисунок 4. Взаимосвязь файлов.

Для того чтобы модуль SDIO понимал команды FatFs, нужно определить содержимое функций файла diskio.c. Первым делом организуется функция disk_initialize(drv). Она инициализирует физический диск и подготавливает его к чтению и записи данных. Аргумент drv определяет номер диска. В этой функции обязательно должна вызываться функция SD_Init(), которая непосредственно принимает на себя обязанности по инициализации SD-карты. Также следует учитывать, что функция disk_initialize не должна вызываться из приложения, поскольку она является служебной функцией в составе файла ff.c. Разработчик FatFs предупреждает, что в противном случае файловая структура носителя может быть испорчена. Вместо этого в приложении для монтирования диска нужно вызывать функцию f_mount, содержащую в себе disk_initialize. Функция f_mount будет рассмотрена ниже.

Следующей необходимой для правильной работы библиотеки функцией является disk_status(drv). Она возвращает текущее состояние диска. В ней обязателен вызов функции SD_GetCardInfo, передающей информацию о SD-карте. При получении от SD_GetCardInfo флага SD_OK функция disk_status должна возвращать 0, в противном случае она должна вернуть флаг STA_NOINIT, это будет являться свидетельством того, что диск не был проинициализирован.

Для чтения секторов имеется функция disk_read, которая в качестве аргументов принимает четыре параметра: drv (номер диска), *buff (указатель на буфер чтения данных), sector (номер начального сектора), count (количество читаемых секторов). В этой функции нужно организовать цикл, в котором функция SD_ReadBlock будет считывать блоки данных в указанном диапазоне (от sector до count). Чтобы прочитать данные, нужно в функции disk_write, принимающей в качестве аргументов те же четыре параметра, что и disk_read, организовать подобный цикл, но уже с функцией SD_WriteBlock, позволяющей считывать информацию с SD-карты. Обе функции (disk_read и disk_write) обязательно должны предусматривать возвращение флага RES_OK в случае успешной операции, либо флага RES_ERROR при возникновении аппаратной ошибки чтения/записи. Также библиотека FatFs предусматривает возврат от этих функций флага RES_PARERR в случае приема неверного параметра и флага RES_NOTRDY, если диск не был инициализирован.

Также для организации дополнительной функциональности, не включающей в себя операции чтения и записи, существует функция disk_ioctl. В качестве аргументов она принимает drv (номер привода), ctrl (команду управления) и *buff (указатель на буфер данных). Функция возвращает те же флаги, что и disk_read или disk_write. Аргумент ctrl может принимать следующие значения: CTRL_SYNC (позволяет завершить операции, ожидающие окончания процесса записи), GET_SECTOR_SIZE (возвращает размер сектора привода в переменную, на которую указывает buff), GET_SECTOR_COUNT (возвращает количество доступных секторов в переменную, на которую указывает buff), GET_BLOCK_SIZE (возвращает размер блока для очистки в переменную, на которую указывает buff), CTRL_ERASE_SECTOR (очищает область памяти, определяемую массивом, первым элементом которого является начальный адрес этой области памяти, а последним элементом – конечный; на сам массив должен указывать buff).

Наконец, в файле diskio.c нужно организовать работу еще двух зависящих от времени функций – disk_timerproc и get_fattime. Первая обеспечивает таймауты для надежного функционирования библиотеки. Ее нужно вызывать каждые 10 мс. Вторая возвращает текущее время выполнения определенной операции. Для ее правильной работы нужно включить и настроить часы реального времени. Если это не нужно, то можно организовать возврат какого-либо определенного значения или нуля. Подробный пример правильной инициализации всех вышеприведенных функций можно найти в [2]. Данная программа предназначена для микроконтроллеров STM32F407xxx/42xxxx/43xxxx и основана на работе модуля SDIO и драйвера stm324xg_eval_sdio_sd.

Теперь перейдем непосредственно к рассмотрению работы библиотеки FatFs в рамках приложения. Как уже было сказано выше, для монтирования и регистрации диска используется функция f_mount с тремя аргументами fatfs, path и opt. Аргумент fatfs является указателем на объект файловой системы, который должен быть зарегистрирован, path указывает на строку, которая в случае единственного привода должна быть пустой, opt определяет опцию инициализации и может принимать два значения: 0 (не монтировать привод, он будет смонтирован позже) и 1 (смонтировать привод сейчас, чтобы проверить его доступность). Функции библиотеки FatFs могут возвращать флаги, перечисленные в Таблице 2. f_mount возвращает FR_OK, FR_INVALID_DRIVE, FR_DISK_ERR, FR_NOT_READY и FR_NO_FILESYSTEM.

Таблица 2. Флаги, возвращаемые функциями библиотеки FatFs
FR_OK
Функция завершена успешно
FR_DISK_ERR
Ошибка, возникшая на нижнем уровне
(в функциях disk_read, disk_write или disk_ioctl)
FR_INT_ERR
Ошибка во внутреннем процессе, возникающая, например,
при поврежденной структуре FAT
FR_NOT_READY
Привод не может функционировать из-за ошибки предыдущего
размонтирования или из-за ошибки в функции disk_initialize
FR_NO_FILE
Файл не найден
FR_NO_PATH
Путь не найден
FR_INVALID_NAME
Заданная строка определяет неверный путь
FR_DENIED
Запрашиваемый доступ запрещен
FR_EXIST
Файл или каталог, имеющий то же имя, уже существует
FR_INVALID_OBJECT
Объект (файл или каталог) является недействительным, или
был задан нулевой указатель
FR_WRITE_PROTECTED
Неудачная попытка записи при активном режиме «Только чтение»
FR_INVALID_DRIVE
Неверный номер диска в указанном пути
FR_NOT_ENABLED
Рабочая область логического диска не зарегистрирована с
помощью функции f_mount
FR_NO_FILESYSTEM
На приводе нет рабочей области FAT
FR_MKFS_ABORTED
Работа функции f_mkfs была прервана
FR_TIMEOUT
Выполнение функции отменено по истечении времени,
определяемого блоком управления потоками
FR_LOCKED
Доступ к файлу отклонен из-за одновременной работы
с другим файлом
FR_NOT_ENOUGH_CORE
Недостаточно памяти для выполнения операции
FR_TOO_MANY_OPEN_FILES
Количество открытых файлов достигло максимального значения,
следующий файл не будет открыт
FR_INVALID_PARAMETER
Заданный параметр неверен

Для того чтобы создавать файлы и работать с ними используется функция f_open. Она создает файловый объект, необходимый для доступа к конкретному файлу. Функция принимает три аргумента: *fp (указатель на структуру данных объекта файла), *path (указатель на строку с именем файла) и mode (определяет тип доступа и метод открытия файла). Аргумент mode может быть представлен одним или несколькими флагами: FA_READ (позволяет считывать из файла), FA_WRITE (позволяет записывать в файл), FA_OPEN_EXISTING (открывает уже имеющийся на диске файл), FA_OPEN_ALWAYS (либо открывает существующий файл, либо создает новый), FA_CREATE_NEW (создает новый файл) и FA_CREATE_ALWAYS (создает новый файл, если файл с таким именем существует, то он будет перезаписан). Функция f_open может возвращать все перечисленные в Таблице 2 флаги, кроме FR_INVALID_OBJECT, FR_MKFS_ABORTED и FR_INVALID_PARAMETER. После работы с файлом требуется его закрыть, для этого существует функция f_close. Она принимает только один аргумент *fp и может вернуть FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_OBJECT и FR_TIMEOUT.

Для чтения и записи данных служат функции f_read и f_write, соответственно. Они обе принимают четыре аргумента: *fp, *buff (указатель на буфер, куда будут записаны прочитанные данные, или где содержатся записываемые данные), btr или btw (количество байт для чтения или для записи, соответственно), *br или *bw (указатели на переменную для возврата количества прочитанных или записанных байтов). Эти функции могут возвращать FR_OK, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_OBJECT и FR_TIMEOUT. Следует отметить, что функция f_write недоступна при включенном режиме «только чтение», то есть при _FS_READONLY = 1.

Для полноценной работы с файловой системой нужно уметь выполнять операции не только над файлами, но и над каталогами. Создать новый каталог можно с помощью функции f_mkdir, которая принимает строку (аргумент *path), указывающую имя каталога и полный путь. Если задать f_mkdir("sub1"), то каталог sub1 будет создан в корневом каталоге, если записать f_mkdir("sub1/sub2"), то подкаталог sub2 будет создан в sub1. Здесь также следует учитывать, что строка не должна заканчиваться символом «/». Для того, чтобы получить доступ к каталогу, то есть открыть его, используют функцию f_opendir. Ее аргументами являются указатель на незаполненную структуру объекта директории *dp и указатель *path на определяющую путь строку. Чтобы поменять текущую директорию диска применяют f_chdir с единственным аргументом *path, указывающим на директорию, которая станет текущей.

Для удаления файла или каталога используется функция f_unlink. Она принимает только *path – указатель на строку, которая задает имя удаляемого объекта. При этом удаляемый объект не должен иметь атрибута «Только чтение», удаляемый файл не должен быть открыт, удаляемая директория не должна быть текущей и обязательно должна быть пустой.

При работе с файлами и папками иногда возникает необходимость в их переименовании. Для этого имеется функция f_rename. Ее аргументами являются указатели *old_name и *new_name. Первый указывает на строку, которая содержит текущее имя объекта, а второй на строку с новым именем объекта. Помимо обычного переименования функция позволяет переносить объект в другую директорию. Например, запись f_rename("oldname.txt", "dir1/newname.txt") переименует файл oldname.txt в newname.txt и переместит его в каталог dir1.

Библиотека FatFs позволяет не только работать с файлами и каталогами, но и выполнять действия на более фундаментальном уровне, то есть делить физический диск на разделы и создавать на диске файловую систему FAT. Первое можно осуществить с помощью функции f_fdisk, принимающей аргументы pdrv (определяет номер физического диска, который будет разбит на разделы), part[] (таблица карты разделов, имеющая 4 элемента) и work (определяет размер рабочей области для функции; минимальный размер указывается в переменной _MAX_SS). Разбивка на разделы выполняется в соответствии с форматом FDISK, допускающим создание максимум 4 разделов. Соотношение объемов разделов определяется вторым аргументом функции, который можно задать, например, как DWORD plist[] = {50, 50, 0, 0}, что будет означать разбиение диска на два логических раздела с одинаковым объемом. Для дальнейшего форматирования диска в соответствии с FAT используют функцию f_mkfs, принимающую аргументы *path (указатель на логический номер диска, который должен быть отформатирован), sfd (правило разбиения на разделы) и au (задает размер единицы данных в байтах). Аргумент sfd может принимать два значения: 0 или 1. В первом случае предусматривается правило разбиения FDISK, во втором – SFD. При работе с твердотельными накопителями, в том числе и с SD-картами, следует выбирать по умолчанию 0. Правило SFD подходит для работы с гибкими дисками, поскольку не предусматривает разделы диска, при этом FAT начинается с первого сектора физического диска. С помощью аргумента au можно принудительно задать размер кластера, это число должно быть 2n. Именно оно определяет тип используемой файловой системы: FAT12, FAT16 или FAT32.

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

Список источников

  1.  elm-chan.org/fsw/ff/ff10.zip
  2.  skydrive.live.com

Перевод: Mikhail R по заказу РадиоЛоцман

Изготовление 1-4 слойных печатных плат за $2

Запись вебинара «Микросхемы для защиты цепей питания: ограничители всплесков напряжения и тока, контроллеры горячей замены, идеальные диоды»
Для комментирования материалов с сайта и получения полного доступа к нашему форуму Вам необходимо зарегистрироваться.
Имя
Фрагменты обсуждения:Полный вариант обсуждения »
  • Очень хорошая статья по FAT на SD картах. FatFs (C)ChaN сегодня является стандартом де-факто не только в любительских разработках встраиваемых микросистем, о чём говорит вполне серьёзный Appnote UM1721 от ST под названием [URL="http://www.st.com/st-web-ui/static/active/jp/resource/technical/document/user_manual/DM00105259.pdf"]"Developing Applications on STM32Cube with FatFs"[/URL]. Единственный недостаток FatFs, на мой взгляд – это плохо документированный и сложно читаемый код. Но разобраться самостоятельно с FAT весьма трудозатратно и намного более сложно, чем использовать ChaN’s модуль. Стоит дополнить список литературы несколькими ссылками с удачными имплементациями FatFs. Эти примеры разработок могут быть полезными для быстрого старта с FAT и не только: 1. Блог Uwe Becker с десятками примеров для STM32F4 (в основном) и Atmega: [URL]http://mikrocontroller.bplaced.net/wordpress[/URL]. Кроме материалов по SDIO, DMA, ADC, DAC, SPI, PWM, I2C, CAN и множеству, множеству других тем, реализации FAT на базе FatFs версии R0.09b посвящены статьи с библиотеками для STM32F4 под номерами: 13 = FATFS-SDIO 20 = FATFS_Picture 87 = Dual_FATFS 89 = FATFS-SPI на странице [URL]http://mikrocontroller.bplaced.net/wordpress/?page_id=744[/URL]. Также доступны материалы с библиотеками для Atmega 09 = FAT16 31 = FASTFAT на странице [URL]http://mikrocontroller.bplaced.net/wordpress/?page_id=746[/URL]. В общем, этот блог стоит изучить в любом случае, т.к. обширный список представленных материалов охватывает почти всю периферию STM32F4. Добавлю также, что порой портировать код Uwe на нижние МК, в частности STM32F1, несколько затруднительно. 2. На сайте технического университета в городе Кайзерслаутерн (Technische Universitat Kaiserslautern) есть страничка с разработками под ARM (AT91SAM7 и LPC) by Martin Thomas: [URL]http://siwawi.bauing.uni-kl.de/avr_projects/arm_projects/index.html[/URL]. Тут можно найти адаптированные для разных МК библиотеки FatFs (C)ChaN c низкоуровневыми функциями доступа к SD картам, в частности тут [URL]http://siwawi.bauing.uni-kl.de/avr_projects/arm_projects/arm_memcards/index.html[/URL]. Там же представлены полезные ссылки на другие материалы в сети с тегом FAT, например реализация на LPC2xxx низкоуровневых функций работы с SPI by Mike Anton для не менее известной библиотеки EFSL. По ссылкам на странице [URL]http://siwawi.bauing.uni-kl.de/avr_projects[/URL] представлены прочие разработки автора(ов). 3. Не менее известный код для stm32f10x, реализующий низкоуровневые функции работы с SPI для FatFs, написан by Domen Puncer и находится здесь [url]http://cba.si/stuff/fatfs_diskio_sdcard_spi.c[/url]. 4. Собственно одна из альтернатив FatFs – это EFSL [URL]http://sourceforge.net/projects/efsl[/URL], но многие говорили о багах в этой библиотеке. Видимо, на текущий момент внесены исправления. О чём свидетельствует существование не менее серьёзного Appnote от NXP для Cortex-M3 AN10916, [URL="http://www.nxp.com/documents/software/AN10916.zip"]"FAT library EFSL and FatFs port on NXP LPC1700"[/URL]. 5. Ещё одна альтернатива – это FAT32 by Henk Kelder, [url]http://trac.netlabs.org/fat32[/url]. 6. А также стоит упоминания DOSFS by Lewin A.R.W. Edwards. Код доступен на его сайте [URL]http://www.zws.com/products/dosfs/index.html[/URL]. 7. И конечно FATLib by Ivan Shan, появившаяся как студенческий проект в University of British Columbia. Код в исходном варианте (2005 год) доступен для загрузки на сайте журнала Circuit Cellar [URL]ftp://ftp.circuitcellar.com/pub/Circuit_Cellar/2005/176/Sham176.zip[/URL], а обзорную статью можно прочитать здесь [URL]http://www.slideshare.net/Flashdomain/portable-fat-library-for-mcu-applications[/URL]. Кстати, судя по объёму кода и количеству разработок на сайте [url]www.elm-chan.org[/url], этот человек или одержимый гений, или под псевдонимом (C)ChaN скрывается группа разработчиков. Что не уменьшает степени уважения к "ним" со стороны мирового embedded сообщества. Ещё раз спасибо Михаилу за полезный материал на РадиоЛоцмане. Всем удачного форматирования.
  • Спасибо за разьяснение, но мой мозг уже не воспринимает такую информацию (дальше бейсика не продвинулся , О ЧЕМ ОЧЕНЬ СОЖАЛЕЮ). Вопрос можно ли тупо вместо микроSD подключить миниSD согласно приведенной в таблице распиновке???? Жалко ложат без дела на 500Мв, а с 8 Гв используются только250Мв!!!