Введение
В этой части мы рассмотрим библиотеку для работы с дисками, имеющими файловую систему 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 раздела
Пример использования
FATFS fs; //объявление объекта FATFS
FRESULT res; //переменная для возвращаемых значений
...
//смонтировать диск
res = pf_mount(&fs);
if (res == FR_OK){
//диск смонтирован, продолжаем работу
...
//демонтируем диск, передав функции нулевой указатель
pf_mount(NULL);
}
else{
//не удалось смонтировать диск
...
}
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 - не смонтирован диск
Пример использования
FATFS fs; //объявление объекта FATFS
FRESULT res; //переменная для возвращаемых значений
...
//монтируем диск
res = pf_mount(&fs);
if (res == FR_OK){
//открываем файл test.txt, лежащий в корне диска
if(pf_open("test.txt") == FR_OK){
...
}
....
}
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 - не смонтирован диск
Пример использования
FATFS fs; //объявление объекта FATFS
FRESULT res; //переменная для возвращаемых значений
BYTE buff[32]; //буфер для чтения файла
WORD br; //счетчик прочитанных байт
...
//монтируем диск и открываем файл без проверки
pf_mount(&fs);
pf_open("test.txt");
//читаем 32 байта из файла
res = pf_read(buff, 32, &br);
if(res == FR_OK){
//если прочитали меньше 32,
// значит достигли конца файла
if (br != 32){
...
}
}
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 - не смонтирован диск
Пример использования
FATFS fs; //объявление объекта FATFS
FRESULT res; //переменная для возвращаемых значений
BYTE buff[32]; //буфер для чтения файла
WORD br; //счетчик прочитанных байт
.....
//монтируем диск и открываем файл без проверки
pf_mount(&fs);
pf_open("test.txt");
//устанавливаем указатель на первый сектор
pf_lseek(0);
do{
//здесь, допустим, заполняем буфер
....
//а здесь записываем его на карту
pf_write(buff, 32, &br);
}while(br == 32);
//финализируем запись
pf_write(0, 0, &br);
FRESULT pf_lseek(DWORD offset) - смещает указатель чтения/записи открытого файла. Эта функцию используется чтобы указать с какого байта выполнять чтение, или с какого сектора диска выполнять запись. Можно выполнять абсолютное смещение указателя, передавая функции число, а можно выполнять смещение относительно текущей позиции, передавая значение указателя fs.fptr и величину смещения (смотри пример). Функция доступна, когда параметр _USE_LSEEK равен 1.
Параметры
DWORD offset - количество байт, на которые нужно сместить указатель.
Возвращаемые значения
FR_OK - успешное завершение функции
FR_DISK_ERR - ошибка диска
FR_NOT_OPENED - файл не был открыт
Пример использования
//смещаем указатель на 1000 байт
pf_lseek(1000);
//смещаем указатель на 2000 байт
// относительно текущей позиции
pf_lseek(fs.fptr + 2000);
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 - не смонтирован диск
Пример использования
//объявление переменных
FATFS fs;
DIR dir;
..
//монтируем диск без проверки
pf_mount(&fs);
//открываем директорию
pf_opendir(&dir, "FOLDER1");
...
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 - не открыта директория
Пример использования
FATFS fs;
FRESULT res;
FILINFO fno;
DIR dir;
....
//монтируем диск без проверки
pf_mount(&fs);
//открываем директорию
pf_opendir(&dir, "FOLDER1");
//чи таем содержимое директории
for(;;){
res = pf_readdir(&dir, &fno);
if ((res != FR_OK) || (fno.fname[0] == 0)){
break;
}
USART_SendStr(fno.fname);
USART_SendStr(" \r");
}
....
Ссылки
Библиотека Petit FatFs
Продолжение следует...
Comments
В статье про воспроизведение wav файла я писал, сколько занимает времени занимает чтение SD карты - единицы миллисекунд. Остальные времена не анализировал.
Долго тупил насчёт пункта 3, наверно нужно было всё же дополнить немного:
"3. Задаем конфигурацию библиотеки Petit FatFs в файле pff.h"
Находим строчки, выставляем 1 напротив нужных функций (чтение, директории, указатель, запись)
#define _USE_READ 1
#define _USE_DIR 1
#define _USE_LSEEK 1
#define _USE_WRITE 1
конкретно не понятно как сделать много строк - постоянно записывает разную информацию только в первую строку, дальше не идет
Например код "31 31 0D 0A 32 32 0D 0A"
откроется в блокноте как:
11
22
и выделяет DRESULT disk_writep {
кто работал с pff мож подскажете что делать?
Компилятор: Atmel Studio 6.2
Камень: mega328p
В чем может быть дело?
причем на SPI микроконтроллер а нет никаких сигналов
RSS feed for comments to this post