Программирование Файловые системы Библиотека EFSL Mon, May 01 2017  

Поделиться

нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Библиотека EFSL Печать
Добавил(а) microsin   

Здесь записаны кое-какие сведения по результатам разборок с исходниками EFSL.

Если кто не знает, EFSL - бесплатная библиотека для работы с файловой системой FAT (поддерживается FAT12, FAT16 и FAT32). Расшифровывается аббревиатура как Embedded Filesystems Library (предназначенная для микроконтроллеров библиотека файловой системы).

[Подключение к карте SD/MMC]

MMC_SD02.JPG MMC_SD01.JPG

Примеры вариантов подключения карты SD/MMC к микроконтроллеру ARM7 (AT91SAM7X128, AT91SAM7X256, AT91SAM7X512) приведены в таблице ниже. Можно подключить карту либо к SPI0, либо к SPI1. Например, в макетной плате Olimex SAM7-EX256 используется вариант 1 подключения карты SD/MMC. В бутлоадере, можно выбрать любой вариант в зависимости от макроопределений (см. файл at91lib\board\board.h, макрос SELECT_TO_MMC_SPI1). Для подключения сигнала выборки ~CS существует еще больше вариантов, так как каждый из SPIn имеет по 4 аппаратных выхода выборки.


конт.

сигнал
описание
Вариант 1 подключения
(SPI0, PIOA, периферия A)
Вариант 2 подключения
(SPI1, PIOA, периферия B)
1 ~CS выборка карты (режим DAT3 не используется) PA13 PA21
2 MOSI данные, приходящие на вход карты PA17 PA23
3 GND минус питания карты, сигнальная земля
4 VCC плюс питания карты, от 2.7 до 3.6 вольт, самый лучший вариант 3 вольта
5 SCK такты данных, поступающие на вход карты PA18 PA22
6 GND минус питания карты, сигнальная земля
7 MISO данные, уходящие с выхода карты (DAT0) PA16 PA24
8 не используется (DAT1)
9 не используется (DAT2)

[Особенности внутренней реализации и использования библиотеки EFSL]

1. Итак, EFSL поддерживает FAT12, FAT16 and FAT32. VFAT (расширение FAT, позволяющее оперировать длинными именами) не поддерживается, т. е. все имена записываются и читаются строго в формате 8.3. К сожалению, Windows штатными методами (через свойства тома) не позволяет посмотреть тип файловой системы Вашей флешки, т. е. и FAT12, и FAT16 будут отображаться одинаково как FAT. Отформатировать нужным образом (выбрать FAT12, FAT16 или FAT32) тоже нельзя, нужно использовать специальные программы. При использовании FAT12 и FAT16 есть ограничение на количество файлов в корневом каталоге - например, мне не удалось записать больше 330 файлов.

2. Библиотека EFSL, что попала мне в руки (0.2.7, 2005 год) изначально была не рассчитана на поддержку символов русского языка в именах файлов (кодировка CP866) - функция file.c\file_validateChar старательно вырезала символы русского языка (с кодами больше 127) и заменяла их на букву X. Также и заменялись символы '%'. Я немного доработал код функции file_validateChar, чтобы можно было использовать символы русского языка:

/* ****************************************************************************
* Описание: эта функция принимает символ c, и если это недопустимый символ *
* для имени FAT, то возвращает символ 'X'. если это буква в нижнем регистре, *
* возвращается эквивалент в верхнем регистре. Остальные символы передаются *
* как есть, без изменений. *
* Возвращаемое значение: приведенный "верный" символ *
******************************************************************************/
euint8 file_validateChar(euint8 c)
{
    if( (c < 0x20) || (c > 0x20 && c < 0x30 && c != '-' && c != '%') || (c > 0x39 && c < 0x41)
        || (c > 0x5A && c < 0x61 && c != '_') || (c > 0x7A && c < 0x80 && c != '~') 
        || (c > 0xAF && c < 0xE0) || (c > 0xEF))
        return(0x58);
    if( c >= 0x61 && c < = 0x7A )
        return(c-32);
    return(c);
}

3. Для получения списка файлов и папок каталога используют последовательные вызовы функций efs_init, ls_openDir (которой в последнем параметре указывается путь до каталога, список которого надо получить) и ls_getNext (эта функция последовательно получает все имена указанного каталога и атрибут типа объекта - файл, папка или метка тома) - см. примеры из документации по EFSL. Например, чтобы получить список корневого каталога карточки MMC, нужно для функции ls_openDir в качестве пути указать "/", а чтобы прочитать содержимое папки fold01 корневого каталога, нужно указать путь "/fold01/" (путь должен обязательно завершаться слешем!).

Функция ls_getNext выбирает имена друг за другом в неотсортированном порядке (сохранен порядок создания файлов, т. е. появления записей в каталоге).

Навигацию можно начать заново (функция ls_getNext при этом спозиционируется снова в начало списка), если еще раз вызвать ls_openDir (функции, "закрывающей" каталог, нет). Навигацию с помощью функции можно продолжить с произвольной позиции каталога, если её предварительно запомнить в переменной типа DirList, а потом запомненное значение использовать в вызове ls_getNext.

По окончании работы с файловой системой нужно вызвать функцию fs_umount.

4. Чтобы получить количество файлов в папке, нужно последовательно прочитать весь список файлов в папке (функциями ls_openDir и ls_getNext), другого более быстрого метода нет.

5. Чтобы получить дату и время создания файла, необходимо открыть файл функцией file_fopen, и прочитать 16-битные значения из полей (EmbeddedFile)file.DirEntry.WriteDate, (EmbeddedFile)file.DirEntry.WriteTime. Дата закодирована следующим образом:
[15][14][13][12][11][10][ 9][ 8][ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0]
      Y   Y   Y   Y   Y   Y   M   M   M   M   D   D   D   D   D

Время закодировано следующим образом:
[15][14][13][12][11][10][ 9][ 8][ 7][ 6][ 5][ 4][ 3][ 2][ 1][ 0]
  H   H   H   H   H   M   M   M   M   M   M   S   S   S   S   S

При этом секунды кодируются с точностью до пар секунд (в разряды 0..4 пишется число секунд, поделенное на 2).

Для ускорения получения даты и времени (без открытия файла) написал функцию getFileRecord:

/* ***************************************************************************\
 Заполняет поля параметра file -> DirEntry. В случае успеха возвращает 0.
*/
esint8 getFileRecord (File* file, FileSystem *fs, eint8* filename)
{
    FileLocation loc;
    if(fs_findFile(fs,filename,&loc,0)==1)
    {
        dir_getFileStructure(fs,&file -> DirEntry,&loc);
        return 0;
    }
    return -1;
}

Входные параметры этой функции:

File* file - просто указатель на тупо выделенную память под объект EmbeddedFile file. Все результат работы функции (в котором есть информация и по дате/времени) сохраняются в этом объекте.

FileSystem *fs - указатель на файловую систему, которую получаем при инициализации библиотеки EFSL.
eint8* filename - указатель на строку с полным путем к нужному файлу.

Пример работы с функцией:

EmbeddedFileSystem efsl;
...
//инициализируем файловую систему
if (!efs_initialized)
{
    if ( efs_init (&efsl, 0) !=0 )
    {
        //printf ( "Could not open filesystem.\n" );
        ErrMsg();
        return;
    }
    else
    {
        efs_initialized = true;
    }
}
//открываем нужный путь
if (ls_openDir ( &list, &(efsl.myFs), arcpath ) != 0)
{
    //printf ( "Could not open list at %s.\n", arcpath );
    ErrMsg();
    memset (foldname, 0, sizeof(foldname));
    crm = CAT_READ_DIRS;
    return;
}
...
  
DirList list;
...
  
if (0 != ls_getNext (&list))
{
    //обработка ошибки
}
  
EmbeddedFile file;
char name[9];
char ext [4];
char full_path [TXTBUF_SIZE/*1 +8+1+3 +1 +8+1+3 +1*/];
memset(name, 0, sizeof(name));
memset(ext , 0, sizeof(ext ));
strncpy(name,(char*) list->currentEntry.FileName,  8);
strncpy(ext, (char*)&list->currentEntry.FileName[8],3);
trim(name);
trim(ext);
//теперь получим дату и время файла
strcpy(full_path, arcpath);
strcat(full_path, name);
strcat(full_path, ".");
strcat(full_path, ext);
if (0 != getFileRecord(&file,&efsl.myFs,full_path))
{
    //Обработка ошибки:
    printf ( "Can`t get file record %s.%s\n", name, ext );
    ...
}
else
{
    DecodeDate(file.DirEntry.WriteDate);
    DecodeTime(file.DirEntry.WriteTime);
}
  
char* DecodeDate (u16 date)
{
    u8 m, d;
    char y[5];
  
    sprintf (y,"%4i", 1980 + ((date >> 9)&0x3F));
    m = (date >> 5)&0x0F;
    d = date & 0x1F;
    sprintf (datestr, "%02i.%02i.%s", d, m, &y[2]);
    datestr[8] = 0;
    return datestr;
}
  
char* DecodeTime (u16 time)
{
    u8 h, m, s;
    h = (time >> 11)&0x1F;
    m = (time >> 5) &0x3F;
    s = (time      &0x1F) * 2;
    sprintf (timestr, "%02i:%02i:%02i", h, m, s);
    timestr[8] = 0;
    return timestr;
}

6. Конфигурация кэша arm7_efsl_0_2_7\inc\config.h - #define IOMAN_NUMBUFFER 6, размер кэша 512*3 = 3 кБайта. Попробовал выключить (указать #define IOMAN_NUMBUFFER 0) - чтобы проверить, как кэш влияет на скорость чтения каталога - но компилятор начал ругаться. Если указать #define IOMAN_NUMBUFFER 1, видимого замедления чтения каталога не происходит.

7. С помощью светодиода выяснил, что больше всего времени при прокрутке каталога (вычитывании данных по файлу) занимает подпрограмма dir.c\dir_findinCluster. Она вызывается переменное количество раз для одного файла, причем чем дальше по каталогу, тем бОльшее количество. Из-за этого навигация по каталогу при уходе от начала вглубь сильно замедляется.

8. Функция ls_openDir требует, чтобы в имени открываемой папки в конце присутствовал завершающий слеш.

9. В библиотеке EFSL нет функции удаления папки. Есть только функция rmfile, которая удаляет файлы. Эта функция папки удалять не может (как пустые, так и заполненные). Оказалось все довольно просто - можно взять за основу rmfile, и переделать её так, что она будет удалять и папки. В начале этой функции есть поиск файла вызовом fs_findFile. При удалении файла ожидается, что функция fs_findFile вернет 1. При удалении директории нужно ждать, что функция fs_findFile вернет 2. Вот функция rmdir для удаления папки:

/* ****************************************************************************
* esint16 rmdir (FileSystem *fs, euint8* dir)
* Description: функция удаляет папку по имени, путем освобождения её цепочки
* кластеров, и удаления его записи из директории.
* Return value: 0 если О.К., -1 при ошибке типа файл не найден.
*/
esint16 rmdir (FileSystem *fs, euint8* dir)
{
    FileLocation loc;
    ClusterChain cache;
    euint8* buf;
    euint32 firstCluster=0;
    if((fs_findFile(fs, (eint8*)dir, &loc,0))==2)
    {
        buf=part_getSect(fs->part,loc.Sector,IOM_MODE_READWRITE);
        firstCluster = ex_getb16(buf,loc.Offset*32+20);
        firstCluster << = 16;
        firstCluster += ex_getb16(buf,loc.Offset*32+26);
        /* Bugfix:
 * Очищая всю структуру, Вы отмечаете конец каталога.
 * Если не этот случай, то файлы дальше не могут быть больше открыты
 * реализациями, которые соответствуют стандарту. */
        /*memClr(buf+(loc.Offset*32),32);*/
        *(buf+(loc.Offset*32)+0) = 0xE5; /* Пометить файл удаленным */
        part_relSect(fs -> part,buf);
        cache.DiscCluster = cache.LastCluster = cache.Linear = cache.LogicCluster = 0;
        cache.FirstCluster = firstCluster;
        fat_unlinkClusterChain(fs,&cache);
        return(0);
    }
    return(-1);
}

Эту функцию нужно использовать с осторожностью, так как она может "удалить" непустую папку - нет проверки на то, что удаляемая папка содержит файлы. При этом на диске образуются пропавшие кластеры (они относятся к тем файлам, которые были в этой папке). Поэтому перед вызовом rmdir нужно проверить, есть ли в удаляемой папке файлы, и если есть, то либо отказаться от удаления папки, либо предварительно удалить все файлы из папки, а потом вызвать rmdir.

10. При всех операциях записи (удаление файлов, добавление каталогов и т. п.) на карточку напрямую ничего не пишется - все идет через кэш, которым управляет подсистема ввода-вывода второго уровня - IOMan, или iomanager. Таким образом, если Вы удалите какой-нибудь файл функцией rmfile, затем вытащите карточку, не размонтировав файловую систему (вызовом fs_umount(&efsl.myFs)), то удаленный файл все равно на карточке останется. Для принудительной синхронизации кэша и носителя (без размонтирования) удобно пользоваться функцией ioman_flushAll(&efsl.myIOman). Подробнее про IOMan читайте в статье EFSL: I/O Manager (менеджер ввода/вывода)

11. Нашел и исправил несколько ошибок ui.c\short listFiles(FileSystem *fs, char *dirname). Эта функция подсчитывает количество файлов в папке dir. Одна из ошибок была в том, что эта функция не могла посчитать файлы, у которых первая буква в имени была русская. Это поправить было довольно легко. Другая ошибка была в том, что не инициализировались поля локальной переменной File dir, из-за чего не отрабатывал вызов функции file_fread(&dir,offset,512,buf) в условии цикла while. Не инициализировалось поле dir.FileStatus - поправил, добавив вызов file_setAttr(&dir, FILE_STATUS_OPEN, 1), а также поле FileSize, и из-за этого file_fread не могла прочитать файл директории. Тупо исправил ошибку, проинициализировав dir.FileSize значением -1 (потому что не смог разобраться, как узнать размер файла директории). Вот подправленная функция listFiles:

short listFiles(FileSystem *fs, char *dirname)
{
    unsigned long startCluster;
    unsigned char fileEntryCount;
    unsigned short counter=0;
    unsigned long offset=0;
    FileRecord fileEntry;
    FileLocation loc;
    unsigned char buf[512];
    File dir;
    unsigned short i;
    /* Проверка - поиск идет в корневом каталоге, или нет */
    if(dirname[0]=='/' && dirname[1]=='\0')
    {
        if( (fs -> type == FAT12) || (fs -> type == FAT16) )
        {
            for(i=0; i < = (fs -> volumeId.RootEntryCount/16); i++)
            {
                loc.Sector=fs -> FirstSectorRootDir + i;
                part_readBuf(fs -> part,loc.Sector,buf);
                /* I STOPPED HERE*/
                /* FIXME */
            }
        }
    }
    else /* Обычная директория */
    {
        /* Проверка - указывает ли путь на директорию */
        if(fs_findFile(fs,dirname,&loc,0)!=2)
        {
            //FUNC_OUT((TXT("")));
            return(-1);
        }
        /* Узнаем начальный кластер каталога директории */
        part_readBuf(fs -> part, loc.Sector, buf);
        fileEntry = *(((FileRecord*)buf) + loc.Offset);
        startCluster = (((unsigned long)fileEntry.FirstClusterHigh) << 16)
            + fileEntry.FirstClusterLow;
        /* Инициализация директории */
        dir.fs=fs;
        dir.Cache.LogicCluster=-1;
        dir.Cache.FirstCluster=startCluster;
        dir.DirEntry.Attribute=ATTR_DIRECTORY;
        file_setAttr(&dir, FILE_STATUS_OPEN, 1);
        dir.FileSize = (euint32)(-1);
        while((file_fread(&dir,offset,512,buf)))
        {
            DBG((TXT("Read 512 bytes from dir with offset %li.\n"),offset));
            for(fileEntryCount=0; fileEntryCount < 16; fileEntryCount++)
            {
                fileEntry = *(((FileRecord*)buf) + fileEntryCount);
                if( !( (fileEntry.Attribute & 0x0F) == 0x0F ) )
                {
                    if (fileEntry.FileName[0] == 0xE5)
                        continue;
                    if
                    (
                     (fileEntry.FileName[0] > = 'A' && fileEntry.FileName[0] < = 'Z')
                     ||
                     (fileEntry.FileName[0] > = '0' && fileEntry.FileName[0] < = '9')
                     ||
                     (fileEntry.FileName[0] > = 'a' && fileEntry.FileName[0] < = 'z')
                     ||
                     (fileEntry.FileName[0] > = 0x80)
                    )
                    {
                        DBG((TXT("Filename: %s\n"),fileEntry.FileName));
                        counter++;
                    }
                }
            }
            offset+=512;
        }
    }
    FUNC_OUT((TXT("")));
    file_setAttr(&dir, FILE_STATUS_OPEN, 0);
    return(counter);
}

12. При проверке корректности удаления файлов и папок из библиотеки EFSL выяснилась интересная фича. Когда я в папке удаляю файлы с русскими именами (они короткие 8.3), то место освобождается не полностью. chkdsk g: пишет, что нашел "поврежденный длинный элемент папки" - сколько было удалено файлов, столько и "поврежденных длинных элементов". Когда я удаляю после этого папку, откуда удалил все файлы, то chkdsk пишет, что ошибок нет. Когда я таким образом удаляю с диска все папки, то ошибок тоже нет, и флешка восстанавливает полностью свободное место (оно равно по объему величине сразу после форматирования). Если я тупо удаляю папку, не удаляя предварительно из неё файлы, то свободное место на диске теряется на потерянные кластеры.

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

13. Исправил следующие ошибки: ioman.c -> ioman_flushSector

Было:

if(!(ioman_writeSector(ioman, ioman -> sector[bufplace],buf)))
{
    ioman_setError(ioman,IOMAN_ERR_WRITEFAIL);
    return(-1);
}

Поправил:

if(-1 == ioman_writeSector(ioman, ioman -> sector[bufplace], buf))
{
    ioman_setError(ioman, IOMAN_ERR_WRITEFAIL);
    return(-1);
}
sc.c -> sd_writeSector

Было:

return(0);

Поправил:

return(1);

Так сделал потому, что ioman_writeSector проверяет результат if_writeBuf, и он должен быть >0.

14. Поддержка даты и времени файлов.

Для того, чтобы создании и модификации файлов корректно указывалось время, нужно сделать две вещи:
- в файле arm7_efsl_0_2_7\inc\config.h раскомментировать строку #define DATE_TIME_SUPPORT
- определить код для функций efsl_getYear, efsl_getMonth, efsl_getDay, efsl_getHour, efsl_getMinute, efsl_getSecond, fs_makeDate, fs_makeTime.

Вот пример объявления таких функций (файл time.h):

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : types.h *
* Description : Headerfile for types.c *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/
#ifndef __TIME_H_
#define __TIME_H_
/*****************************************************************************/
#include "types.h"
/*****************************************************************************/
#ifdef DATE_TIME_SUPPORT
  #define time_getYear(void) efsl_getYear()
  #define time_getMonth(void) efsl_getMonth()
  #define time_getDay(void) efsl_getDay()
  #define time_getHour(void) efsl_getHour()
  #define time_getMinute(void) efsl_getMinute()
  #define time_getSecond(void) efsl_getSecond()
  #define time_getDate(void) fs_makeDate()
  #define time_getTime(void) fs_makeTime()
#else
  #define time_getYear(void) 0x0;
  #define time_getMonth(void) 0x0;
  #define time_getDay(void) 0x0;
  #define time_getHour(void) 0x0;
  #define time_getMinute(void) 0x0;
  #define time_getSecond(void) 0x0;
  #define time_getDate(void) 0x0;
  #define time_getTime(void) 0x0;
#endif
#ifdef DATE_TIME_SUPPORT
euint16 efsl_getYear(void);
euint8 efsl_getMonth(void);
euint8 efsl_getDay(void);
euint8 efsl_getHour(void);
euint8 efsl_getMinute(void);
euint8 efsl_getSecond(void);
#endif
euint8 fs_hasTimeSupport(void);
#endif

Вот пример определения таких функций (файл time.c):

/*****************************************************************************\
* efs - General purpose Embedded Filesystem library *
* --------------------- ----------------------------------- *
* *
* Filename : time.c *
* Description : This file contains functions for time support *
* *
* (c)2006 Lennart Yseboodt *
* (c)2006 Michael De Nil *
\*****************************************************************************/
  
/*****************************************************************************/
#include "time.h"
#include "arm7_efsl_0_2_7\inc\fs.h"
/*****************************************************************************/
  
#include "include/settings.h"
#include "include/vars.h"
  
euint16 efsl_getYear(void)
{
    //return(2005);
    return(2000 + 10*(currTime.Year >> 4) + (currTime.Year & 0x0F));
}
  
euint8 efsl_getMonth(void)
{
    //return(5);
    return (10*(currTime.Month >> 4) + (currTime.Month & 0x0F));
}
  
euint8 efsl_getDay(void)
{
    //return(11);
    return (10*(currTime.Day>>4) + (currTime.Day&0x0F));
}
euint8 efsl_getHour(void)
{
    //return(13);
    return (10*(currTime.Hour >> 4) + (currTime.Hour & 0x0F));
}
  
euint8 efsl_getMinute(void)
{
    //return(14);
    return (10*(currTime.Minute>>4) + (currTime.Minute&0x0F));
}
  
euint8 efsl_getSecond(void)
{
    //return(40);
    return (10*(currTime.Second>>4) + (currTime.Second&0x0F));
}
  
euint16 fs_makeDate(void)
{
#ifndef DATE_TIME_SUPPORT
    return(0);
#else
    euint8 m,d;
    euint16 y;
    
    y = time_getYear()-1980;
    m = time_getMonth();
    d = time_getDay();
    
    return(
        (y > 127? 127 << 9: (y & 0x3F) << 9)  |
        ((m == 0 || m > 12)? 1: (m & 0xF) << 5) |
        ((d == 0 || d > 31)? 1: (d & 0x1F))
    );
#endif
}
/*****************************************************************************/
euint16 fs_makeTime(void)
{
#ifndef DATE_TIME_SUPPORT
    return(0);
#else
    euint8 s,m,h;
    
    s = time_getSecond();
    m = time_getMinute();
    h = time_getHour();
    
    return(
        (h > 23? 0: (h & 0x1F) << 11) |
        (m > 59? 0: (m & 0x3F) << 5) |
        (s > 59? 0: (s-s%2)/2)
    );
#endif
}
/*****************************************************************************/
euint8 fs_hasTimeSupport(void)
{
#ifdef DATE_TIME_SUPPORT
    return(1);
#else
    return(0);
#endif
}
/*****************************************************************************/

15. Быстро позиционировать позицию чтения по файлу можно при помощи функции file.c -> file_setpos. Второй способ - можно просто поменять значение свойства file.FilePtr (переменная file имеет тип File или EmbeddedFile). То же самое, кстати, делает и функция file_setpos, поэтому лучше применять именно её.

16. Некоторые карты SD, которые мне попадались, требуют двойной инициализации после подачи питания на карту (после того, как она подключена к считывающему устройству с EFSL). На фото показаны две совершенно идентичные карты SD Kingston 1 Gb.

SD-CARDS-IMAG0179.jpg

Карта, что на фото слева, требует двойной инициализации физического интерфейса карты, иначе запуск инициализации файловой системы завершится с ошибкой. Та карта, что справа, работает как обычно, с одиночной инициализацией. Вот исправления (выделено красным), которые нужно внести в процедуру if_initInterface (файл at91_spi.c):

esint8 if_initInterface(hwInterface* file, eint8* opts)
{
    euint32 sc;
    
    if_spiInit(file);
    if_spiInit(file);    //добавочный вызов инициализации интерфейса
    
    if(sd_Init(file) < 0)    
    {
        //printf("Card failed to init, breaking up...\n\r");
        return(-1);
    }
    
    if(sd_State(file) < 0)
    {
        //printf("Card didn't return the ready state, breaking up...\n\r");
        return(-2);
    }
    
    /* file -> sectorCount = 4; */ /* FIXME ASAP!! */
    /* mthomas: - somehow done - see below */
    sd_getDriveSize(file, &sc);
    file -> sectorCount = sc/512;
    if( (sc%512) != 0) 
        file -> sectorCount --;
    //DBG((TXT("Card Capacity is %u Bytes (%i Sectors)\n\r"), sc, file -> sectorCount));
    
    if_spiSetSpeed(SPI_SCBR_MIN);
    //if_spiSetSpeed(100); /* debug - slower */
    
    return(0);
}

С такой правкой нормально работают все известные мне карты SD/MMC.

[Ссылки]

1. Сайт EFSL.
2. IAR EW ARM: работа с файловой системой FAT на карточках SD/MMC.
3. IAR EW ARM: как сделать USB Mass Storage Device на основе MMC/SD.
4. EFSL: I/O Manager (менеджер ввода/вывода).
5. Другая популярная реализации файловой системы для микроконтроллеров - Petit FAT File System Module. См. также FatFs Generic FAT File System Module.

 

Добавить комментарий


Защитный код
Обновить

Top of Page