Перейти к содержанию
    

Помогите подключить FatFs к STM32F105RBT6 + SDHC

Пытаюсь подключить FatFs (http://elm-chan.org/fsw/ff/00index_e.html)  к STM32F105RBT6 + карта  SDHC (поддержка старых SD не требуется), проект в Keil 5.26,

отладка в оперативной памяти (из 64кб - 40кб под прошивку 24кб оставшаяся оперативная память)

Создал проект с тремя основными функциями - инициализация SDHC (предполагается работа только с одной картой), чтение N секторов в буфер начиная со стартового адреса,

запись N секторов из буфера начиная со стартового адреса, проверял на буферах размером до 8 секторов, всё надежно работает.

Пытаюсь подключить библиотеку, нужно написать функцию disk_read:

Спойлер

DRESULT disk_read (
    BYTE pdrv,        /* Physical drive nmuber to identify the drive */
    BYTE *buff,        /* Data buffer to store read data */
    DWORD sector,    /* Start sector in LBA */
    UINT count        /* Number of sectors to read */
)
{
//////////////////////////////////////////////////////////////////////////
if(0 == spi_SD_Read_Block(buff, sector, uint8_t (count))) {return RES_OK;}
else {return RES_ERROR;}
//////////////////////////////////////////////////////////////////////////    
}

 

получаю ошибку:

Цитата

fatfs/diskio.cpp(159): error: no matching function for call to 'spi_SD_Read_Block'

моя функция:

Спойлер

unsigned char spi_SD_Read_Block (char* bf, uint32_t SD_adr, uint8_t adr_count) //чтение секторов из SD карты
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
unsigned char result;
long int cnt = 0;
//*******************************************************************************************************************
for(uint8_t i=0; i < adr_count; i++)
  {    
    SD_adr = SD_adr+i;        
    unsigned char SD_adr_0 = SD_adr;            //разбивка адреса uint32_t на 4 байта
    unsigned char SD_adr_1 = SD_adr >> 8;
    unsigned char SD_adr_2 = SD_adr >> 16;
    unsigned char SD_adr_3 = SD_adr >> 24;
    //-----------------------------------------------------------------------------------------------------------------        
    first_ACMD17 = spi_WaitReady();
    if(first_ACMD17 == waiting) {return 1;} //превышено время ожидания
    spi_SD_cmd (0x51, SD_adr_3, SD_adr_2, SD_adr_1, SD_adr_0, 0x95);        //CMD17 даташит стр 50 и 96
    cnt=0;
    do     
        {
        result=spi_SendRecvByte(0xFF);
        cnt++;
        }
        while ((result!=0x00) && (cnt < waiting));
    after_ACMD17 = cnt;  
    if (cnt == waiting) return 2; //превышено время ожидания        
    spi_SendRecvByte(0xFF);
    cnt=0;
    do     //Ждем начала блока
        {
        result=spi_SendRecvByte(0xFF);
        cnt++;
        }
        while ((result!=0xFE) && (cnt < waiting));
    first_read = cnt;
    if (cnt == waiting) return 3;
    for (cnt=0;cnt<512;cnt++)    bf[cnt+(512*i)]=spi_SendRecvByte(0xFF); //получаем байты блока из шины в буфер
    spi_SendRecvByte(0xFF);                    //Получаем контрольную сумму
    spi_SendRecvByte(0xFF);
  }    
return 0;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

Что не так?

Второй вопрос: я саму библиотеку правильно скачал http://elm-chan.org/fsw/ff/arc/ff13c.zip  ?

 

Третий вопрос: мой проект написан на C++ а библиотека FatFs на C, как правильно, в этом случае, её подключать?

 

Изменено пользователем Donker
добавил вопрос

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уточнение, если поставить такую заглушку:

Цитата

char buffer[10];    
    
    
if(0 == spi_SD_Read_Block(buffer, sector, uint8_t (count))) {return RES_OK;}
else {return RES_ERROR;}

код компилируется, т.е. компилятору не нравиться передача указателя на буфер, но почему?!

BYTE это обычный unsigned char, после подключения FatFs я могу в своём коде поменять unsigned char или uint8_t на BYTE и ничего не изменится.

 

Цитата

typedef unsigned char    BYTE;    /* char must be 8-bit */

 

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Donker сказал:

BYTE это обычный unsigned char, после подключения FatFs я могу в своём коде поменять unsigned char или uint8_t на BYTE и ничего не изменится.

Разница в том, что функцию объявили с char *, а вызываете с BYTE *. Соответственно - компилятор не может найти функцию с подходящей вашему вызову декларацией.

И что мешает применить явное приведение типа при вызове: spi_SD_Read_Block((char *)buff,...  ?

Ведь count Вы зачем-то приводите, хотя как раз там это делать бессмысленно и вредно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

jcxz

спасибо, я что то думал что unsigned char  и просто char в данном случае одно и тоже.

 

Остальные вопросы в силе, (скоро новые возникнут).

Изменено пользователем Donker
Остальные вопросы в силе...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Новые вопросы:

 

Есть некоторые успехи, в этой тестовой функции:
 

Спойлер

void ff_test(void)
{
//////////////////////////////////////////////////////////////////////////////////////////////    
FATFS fs;
FRESULT res;
sprintf(lines[0],"Ready!"); //UART_Printf("Ready!\r\n");

// mount the default drive
res = f_mount(&fs, "", 0);    
sprintf(lines[0],"f_mount, res: %d", res);     lcd_refr();        
if(res != FR_OK)
  {
    //UART_Printf("f_mount() failed, res = %d\r\n", res);
  return;
  }
//UART_Printf("f_mount() done!\r\n");
//---------------------------------------------------------------------------------------------
uint32_t freeClust;
FATFS* fs_ptr = &fs;
// Warning! This fills fs.n_fatent and fs.csize!
res = f_getfree("", &freeClust, &fs_ptr);
sprintf(lines[1],"f_getfree, res: %d", res);     lcd_refr();            
if(res != FR_OK)
  {
    ///UART_Printf("f_getfree() failed, res = %d\r\n", res);
    return;
  }
///UART_Printf("f_getfree() done!\r\n");
uint32_t totalBlocks = (fs.n_fatent - 2) * fs.csize;
uint32_t freeBlocks = freeClust * fs.csize;
//UART_Printf("Total blocks: %lu (%lu Mb)\r\n", totalBlocks, totalBlocks / 2000);
//UART_Printf("Free blocks: %lu (%lu Mb)\r\n", freeBlocks, freeBlocks / 2000);
sprintf(lines[2],"Total blocks: %d Mb", (totalBlocks / 2048));     
sprintf(lines[3],"Free blocks: %d Mb", (freeBlocks / 2048));     lcd_refr();    
//---------------------------------------------------------------------------------------------
DIR dir;
res = f_opendir(&dir, "/");
sprintf(lines[4],"f_opendir, res: %d", res);     lcd_refr();            
if(res != FR_OK)
  {
    ///UART_Printf("f_opendir() failed, res = %d\r\n", res);
    return;
  }
FILINFO fileInfo;
uint32_t totalFiles = 0;
uint32_t totalDirs = 0;
//UART_Printf("--------\r\nRoot directory:\r\n");
uint8_t st=0;    
for(;;)
    {
    res = f_readdir(&dir, &fileInfo);
    if((res != FR_OK) || (fileInfo.fname[0] == '\0')) {break;}
  if(fileInfo.fattrib & AM_DIR)
      {
        //UART_Printf("  DIR  %s\r\n", fileInfo.fname);
        sprintf(lines[5+st],"DIR %s", fileInfo.fname);
        st++;
        totalDirs++;
    }
        else
          {
            //UART_Printf("  FILE %s\r\n", fileInfo.fname);
            sprintf(lines[5+st],"FILE %s", fileInfo.fname);
            st++;    
            totalFiles++;
      }
  }
    
//UART_Printf("(total: %lu dirs, %lu files)\r\n--------\r\n",totalDirs, totalFiles);
sprintf(lines[15],"total: %d dr, %d fl",totalDirs, totalFiles);        
lcd_refr();        
//---------------------------------------------------------------------------------------------
res = f_closedir(&dir);
sprintf(lines[16],"f_closedir, res: %d", res);     lcd_refr();
if(res != FR_OK)
  {
    //UART_Printf("f_closedir() failed, res = %d\r\n", res);
    return;
  }
//---------------------------------------------------------------------------------------------
//UART_Printf("Writing to log.txt...\r\n");
char writeBuff[128];
snprintf(writeBuff, sizeof(writeBuff), "Total blocks: %d (%d Mb); Free blocks: %d (%d Mb)\r\n", totalBlocks, totalBlocks / 2048, freeBlocks, freeBlocks / 2048);
FIL logFile;
res = f_open(&logFile, "log.txt", FA_OPEN_APPEND | FA_WRITE);
sprintf(lines[17],"f_open, res: %d", res);     lcd_refr();    
if(res != FR_OK)
  {
    //UART_Printf("f_open() failed, res = %d\r\n", res);
    return;
  }
unsigned int bytesToWrite = strlen(writeBuff);
unsigned int bytesWritten;
res = f_write(&logFile, writeBuff, bytesToWrite, &bytesWritten);
sprintf(lines[18],"f_write, res: %d", res);     lcd_refr();    
if(res != FR_OK)
    {
    //UART_Printf("f_write() failed, res = %d\r\n", res);
    return;
  }
if(bytesWritten < bytesToWrite)
  {
  //UART_Printf("WARNING! Disk is full.\r\n");
  }
//_delay_ms(1);    
res = f_close(&logFile);
sprintf(lines[18],"f_close, res: %d", res);     lcd_refr();    
if(res != FR_OK)
    {
    //UART_Printf("f_close() failed, res = %d\r\n", res);
    return;
  }
//---------------------------------------------------------------------------------------------
    //UART_Printf("Reading file...\r\n");
    FIL msgFile;
    res = f_open(&msgFile, "log.txt", FA_READ);
    if(res != FR_OK) {
        //UART_Printf("f_open() failed, res = %d\r\n", res);
        return;
    }

    char readBuff[128];
    unsigned int bytesRead;
    res = f_read(&msgFile, readBuff, sizeof(readBuff)-1, &bytesRead);
    if(res != FR_OK) {
        //UART_Printf("f_read() failed, res = %d\r\n", res);
        return;
    }

    readBuff[bytesRead] = '\0';
    //UART_Printf("```\r\n%s\r\n```\r\n", readBuff);

    res = f_close(&msgFile);
    if(res != FR_OK) {
        //UART_Printf("f_close() failed, res = %d\r\n", res);
        return;
    }

    // Unmount
    res = f_mount(NULL, "", 0);
    if(res != FR_OK) {
        //UART_Printf("Unmount failed, res = %d\r\n", res);
        return;
    }

    //UART_Printf("Done!\r\n");
}


 

все функции до  f_close нормально работают (как минимум возвращают 0, а не код ошибки, и делают ожидаемые вещи),
а вот  f_close возвращает 1, почему такое может быть?

 

Нужно ли настраивать таймер на 10ms и вызывать в нём disk_timerproc (я вообще не нашёл такой функции в FatFs)?

 

Каким образом и где FatFs создаёт буферы для чтения и записи сектров, указатели которых передаются в функции
disk_write и disk_read, если они создаются динамически, можно ли их заставить создаваться в стеке без потери функциональности
библиотеки?

Изменено пользователем Donker

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот весь проект:
https://yadi.sk/d/w98_y4E7kJN6Eg


Уточнение, перераспределение памяти для отладки в RAM - 44кб под
прошивку  20кб оставшаяся оперативная память память.

Сейчас появилась такая  проблема, в fileWork.cpp в функции ff_test
есть строка:

res = f_open(&logFile, "log.txt", FA_OPEN_APPEND | FA_WRITE);
 
если выходить из функции до неё, то всо нормально, выполнение этой строки, в какой то момент(не пойму что я сделал), начало приводить к зависанию МК, до этого проблема была только с f_close (код ошибки 1), и ведь строки в log.txt успешно добавлялись!

Карта подключена к J10 (схема в проекте), к J2 подключен экран 20x4,
lines[NumLines][20] массив для хранения строк отладочного экрана строки
крутятся энкодером, пробовал подавать питание на J1 убирая перемычку J4, на проблему это не повлияло.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нашёл ошибку, в функции чтения и записи секторов (spi_SD_Write_Block и spi_SD_Read_Block) они корректно работали
только при чтении одного сектора, иначе адрес котцался, так правильно:

    uint32_t SD_adr_tmp = SD_adr+i;        
    unsigned char SD_adr_0 = SD_adr_tmp;            //разбивка адреса uint32_t на 4 байта
    unsigned char SD_adr_1 = SD_adr_tmp >> 8;
    unsigned char SD_adr_2 = SD_adr_tmp >> 16;
    unsigned char SD_adr_3 = SD_adr_tmp >> 24;

но исправление на вышеописанную проблему никак не повлияло.

Кстати, я беру некоторый код отсюда: https://eax.me/stm32-fatfs/ вам тут ничего не кажется подозрительным?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Новый вопрос, при каком минимальном количестве оперативной памяти в микроконтроллере у вас нормально работал FatFs не урезанный
(с поддержкой длинных имён и юникодом c русской кодовой страницей)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 часов назад, Donker сказал:

Новый вопрос, при каком минимальном количестве оперативной памяти в микроконтроллере у вас нормально работал FatFs не урезанный
(с поддержкой длинных имён и юникодом c русской кодовой страницей)?

Вы это сами можете посмотреть, в своём .map-файле. Не задавая вопросов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Было переполнение стэка, он был задан 1кб (размер по умолчанию), поставил 4кб, глюк исчез.

Это только у меня такая проблема, всем остальным хватает 1кб для FatFs на STM32 ?!  

При каких обстоятельствах мне ждать от FatFs переполнения уже 4кб?

Я нашёл где прячется этот самый массив на 512 байт минимум (см. win BYTE win[FF_MAX_SS];):

typedef struct {
    BYTE    fs_type;        /* Filesystem type (0:not mounted) */
    BYTE    pdrv;            /* Associated physical drive */
    BYTE    n_fats;            /* Number of FATs (1 or 2) */
    BYTE    wflag;            /* win[] flag (b0:dirty) */
    BYTE    fsi_flag;        /* FSINFO flags (b7:disabled, b0:dirty) */
    WORD    id;                /* Volume mount ID */
    WORD    n_rootdir;        /* Number of root directory entries (FAT12/16) */
    WORD    csize;            /* Cluster size [sectors] */
#if FF_MAX_SS != FF_MIN_SS
    WORD    ssize;            /* Sector size (512, 1024, 2048 or 4096) */
#endif
#if FF_USE_LFN
    WCHAR*    lfnbuf;            /* LFN working buffer */
#endif
#if FF_FS_EXFAT
    BYTE*    dirbuf;            /* Directory entry block scratchpad buffer for exFAT */
#endif
#if FF_FS_REENTRANT
    FF_SYNC_t    sobj;        /* Identifier of sync object */
#endif
#if !FF_FS_READONLY
    DWORD    last_clst;        /* Last allocated cluster */
    DWORD    free_clst;        /* Number of free clusters */
#endif
#if FF_FS_RPATH
    DWORD    cdir;            /* Current directory start cluster (0:root) */
#if FF_FS_EXFAT
    DWORD    cdc_scl;        /* Containing directory start cluster (invalid when cdir is 0) */
    DWORD    cdc_size;        /* b31-b8:Size of containing directory, b7-b0: Chain status */
    DWORD    cdc_ofs;        /* Offset in the containing directory (invalid when cdir is 0) */
#endif
#endif
    DWORD    n_fatent;        /* Number of FAT entries (number of clusters + 2) */
    DWORD    fsize;            /* Size of an FAT [sectors] */
    DWORD    volbase;        /* Volume base sector */
    DWORD    fatbase;        /* FAT base sector */
    DWORD    dirbase;        /* Root directory base sector/cluster */
    DWORD    database;        /* Data base sector */
#if FF_FS_EXFAT
    DWORD    bitbase;        /* Allocation bitmap base sector */
#endif
    DWORD    winsect;        /* Current sector appearing in the win[] */
    BYTE    win[FF_MAX_SS];    /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;

причём структурных переменных "FATFS" может быть много, они что при прерываниях тоже в стек лезут?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

46 минут назад, Donker сказал:

причём структурных переменных "FATFS" может быть много, они что при прерываниях тоже в стек лезут?

FatFS ничего не знает про прерывания. Не его это дело. Так как он - middleware.

И вообще - использование стека зависит от компилятора, ключей его компиляции, архитектуры МК, использования инструкций FPU, .... и много от чего ещё. Создатели middleware не обязаны знать особенности архитектуры всех целевых платформ на которых будет запускаться их ПО. Их должны знать Вы - тот кто портирует FatFS к себе на своё железо/компилятор.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...