Работа с SD картой. MMC. FAT fs файловая система
Введение
В этой части мы рассмотрим библиотеку для работы с дисками, имеющими файловую систему FAT. Это всем известная библиотека Elm Chan`a - Petit FatFs. Она представляет собой облегченную версия библиотеки FatFs и предназначена для микроконтроллеров с небольшим объемом оперативной памяти. Конечно, функционал Petit FatFs сильно ограничен, но имеет смысл начать знакомство с нее, потому что в ней проще разобраться.
В этой части изложена информация справочного характера, которую я почерпнул из документации на библиотеку, а в следующей части будет уже практический материал.
Состав библиотеки
Библиотека Petit FatFs состоит из 5 файлов. Изначально она не заточена под какой-т о конкретный носитель памяти с файловой системой FAT и может использоваться с любым из них. Для этого к библиотеке нужно добавить реализацию трех низкоуровневых функций для работы с диском - функцию инициализации, записи и чтения.
integer.h - здесь объявлены целочисленные типы данных, используемые в библиотеке
diskio.h - описаны прототипы низкоуровневых функций для работы с диском и статусные коды, возвращаемые функциями.
diskio.c - файл реализации низкоуровневых функций для работы с диском. Изначально содержит "пустышки".
pff.h - здесь задается конфигурация библиотеки, объявлены типы данных и прототипы функций для взаимодействия с файловой системой диска
pff.c - файл реализации функций для взаимодействия с файловой системой диска
Низкоуровневая работа с SD картой
Как вы понимаете из описания выше, для работы с SD картой библиотеку Petit FatFs нужно "допиливать". А именно, писать реализацию низкоуровневых функций в файле diskio.c. На сайте автора есть архив с примерами использования библиотеки Petit FatFs с различными дисками и микроконтроллерами. Есть там и пример использования SD карт с AVR. В принципе, можно не разбираться с низкоуровневой работой с SD картой, а взять уже готовый код, что я и сделаю в следующий части.
Подключение библиотеки и настройка
1. Копируем файлы библиотеки Petit FatFs в папку проекта
2. Подключаем сишные файлы (diskio.c, pff.c)к проекту внутри среды разработки
3. Задаем конфигурацию библиотеки Petit FatFs в файле pff.h
4. Включаем (инклюдим) заголовочные файлы библиотеки (integer.h, pff.h и diskio.h) в сишный файл, где будут использоваться ее функции.
5. Реализуем низкоуровневые функции для работы с диском или подставляем вместо diskio.c какой-нибудь "готовый" файл, например из примеров Elm Chan`a.
Ну а дальше используем функции библиотеки.
Функции библиотеки Petit FatFs
FRESULT pf_mount (FATFS* fs) - смонтировать/демонтировать диск. Эта функция должна вызываться перед началом работы с диском. Она получает данные о структуре файловой системы диска и позволяет продолжить работу с его содержимым. Также функция демонтирует или виртуально отключает диск, если ее вызывать с нулевым указателем. Когда диск демонтирован, все остальные функции библиотеки возвращают FR_NOT_ENABLED (диск не смонтирован). Функция pf_mount() доступна всегда.
Параметры
FATFS *fs - указатель на объект типа FATFS. Это объект библиотеки, в котором описана структура файловой системы. На него можно взглянуть в файле pff.h. Ну а по сути, это просто переменная определенного типа, которая должна быть предварительно объявлена.
Возвращаемые значения
FR_OK - успешное завершение функции
FR_NOT_READY - не удалось инициализировать диск
FR_DISK_ERR - ошибка диска
FR_NO_FILESYSTEM - на диске нет правильного FAT раздела
Пример использования
FRESULT pf_open (const char* path) - открывает существующий файл. Функция должна вызываться перед тем, как выполняется любая работа с файлом - чтение, запись, изменение указателя. С открытым файлом можно работать до тех пор, пока не будет открыт другой файл. Функция pf_open() доступна всегда.
Параметры
const char *path - указатель на строку, показывающую путь к файлу. Строка должна заканчиваться нулевым символом. Путь нужно указывать полностью, разделяя подкаталоги символом слэша.
"test.txt" - путь к файлу test.txt, лежащему в корне диска
"Folder/code.txt" - путь к файлу сode.txt, лежащему в папке Folder
Возвращаемые значения
FR_OK - успешное завершение функции
FR_NO_FILE - не удалось найти файл
FR_NO_PATH - не удалось найти путь
FR_DISK_ERR - ошибка диска
FR_NOT_ENABLED - не смонтирован диск
Пример использования
FRESULT pf_read(void* buff, WORD btr, WORD* br) - прочитать данные из файла. Функция читает заданное количество байт из открытого файла и записывает их в буфер пользователя. Также она подсчитывает количество прочитанных байт. Если заданное количество байт и прочитанное не совпадают, значит при чтении был достигнут конец файла. Функция доступна когда параметр _USE_READ равен 1.
Параметры
void* buff - указатель на буфер, в котором будут сохраняться прочитанные данные. Если передать нулевой указатель, то прочитанные данные будут перенаправлены в другой поток, некую функцию, которую нужно описывать самостоятельно.
WORD btr - количество байт, которые нужно прочитать.
WORD* br - указатель на переменную, в которой функция pf_open сохранит количество прочитанных байтов.
Возвращаемые значения
FR_OK - успешное завершение функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - файл не был открыт
FR_NOT_ENABLED - не смонтирован диск
Пример использования
FRESULT pf_write(const void* buff, WORD btw, WORD* bw) - эта функция записывает данные в предварительно открытый файл. Она доступна только тогда, когда параметр _USE_WRITE равен 1. Из-за того, что библиотека Petit FatFs рассчитана на микроконтроллеры с маленьким объемом памяти, функцию записи имеет ряд ограничений:
- нельзя создать новый файл,
- нельзя увеличить размер файла,
- нельзя обновить временную метку файла,
- файловый атрибут "только для чтения" не может запретить запись,
- операцию записи можно запустить/остановить только на границе сектора диска.
Последний пункт, пожалуй, требует пояснения. SD карта разбита на сектора по 512 байт. Функция pf_write может выполнять запись только с начала какого-либо сектора. При этом, если записывается меньше 512 байт, остаток заполняется нулями. Например, мы порциями записываем 612 байтов полезной информации - первый сектор будет заполнен полностью, а во втором будет 100 байтов полезной информации и 412 нулевых байтов.
Функция pf_lseek(..), о которой рассказано ниже, позволяет перемещать указатель чтения/записи данных. При использовании функции записи указатель нужно устанавливать на начало сектора. Если установить указатель в середину, то он будет округлен к нижней границе сектора и запись все равно будет выполняться с его начала.
Таким образом, операция записи выполняется в следующей последовательности:
1. Устанавливаем указатель записи на какой-нибудь сектор.
2. Вызываем функцию записи.
3. Если записаны не все данные и конец файла не достигнут повторяем 2-й шаг.
4. Финализируем запись, вызвав функцию записи с нулевым указателем.
Параметры
const void* buff - указатель на буфер содержащий данные для записи. Нулевое значение завершает текущую операцию записи.
WORD btw - количество байт, которые нужно записать в файл.
WORD* bw - указатель на 16-и разрядную переменную, в которой сохранится количество байт, которые удалось записать. По значению этой переменной можно определять, когда достигнут конец файла.
Возвращаемые значения
FR_OK - успешное завершение функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - файл не был открыт
FR_NOT_ENABLED - не смонтирован диск
Пример использования
FRESULT pf_lseek(DWORD offset) - смещает указатель чтения/записи открытого файла. Эта функцию используется чтобы указать с какого байта выполнять чтение, или с какого сектора диска выполнять запись. Можно выполнять абсолютное смещение указателя, передавая функции число, а можно выполнять смещение относительно текущей позиции, передавая значение указателя fs.fptr и величину смещения (смотри пример). Функция доступна, когда параметр _USE_LSEEK равен 1.
Параметры
DWORD offset - количество байт, на которые нужно сместить указатель.
Возвращаемые значения
FR_OK - успешное завершение функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - файл не был открыт
Пример использования
FRESULT pf_opendir(DIR* dp, const char * path) - эта функцию открывает существующую директорию и инициализирует переменную типа DIR. В дальнейшем эта переменная может использоваться для получения списка файлов открытой директории. Функцию доступна, когда параметр _USE_DIR равен 1.
Параметры
DIR *dp - указатель на переменную типа DIR. Она должна быть предварительно объявлена.
const char* path - указатель на строку-путь к директории. Строка должна заканчиваться нулевым символом. Путь нужно указывать полностью, разделяя подкаталоги символом слэша. Написание пути к директории подчиняется тем же правилам, что и написание пути к файлу (смотри функцию pf_open).
Возвращаемые значения
FR_OK - успешное завершение функции
FR_NO_PATH - не удалось найти путь
FR_NOT_READY - не удалось инициализировать диск
FR_DISK_ERR - ошибка диска
FR_NOT_ENABLED - не смонтирован диск
Пример использования
FRESULT pf_readdir(DIR* dp, FILINFO* fno) - эта функцию позволяет прочитать содержимое директории. Для этого ее нужно вызывать несколько раз, пока функция не возвратит нулевую строку в одном из членов переменной fno - fno.fname[]. Функция доступна, когда параметр _USE_DIR равен 1. Читаемая директория должна быть предварительно открыта с помощью функции pf_opendir(..).
Параметры
DIR *dp - указатель на переменную типа DIR. Переменная должна быть предварительно объявлена.
FILINFO *fno - указатель на переменную типа FILINFO. Переменная должна быть предварительно объявлена.
Возвращаемые значения
FR_OK - успешное завершение функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - не открыта директория
Пример использования
Ссылки
Продолжение следует...
Обратная связь
Интересуют вопросы реализации алгоритмов, программирования, выбора электроники и прочая информация, постараюсь осветить в отдельных статьях
пишите мне на netdm@mail.ru
Добавить комментарий