Кто любит RISC в жизни, заходим, не стесняемся.
Сб фев 23, 2019 22:01:36
Пытаюсь подключить 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, как правильно, в этом случае, её подключать?
Последний раз редактировалось
DENIS451 Вс фев 24, 2019 12:49:55, всего редактировалось 1 раз.
Вс фев 24, 2019 04:11:39
DENIS451 писал(а):Что не так?
Праздник, наверное ...
Хотя, переводчики не дремлют :
ошибка: нет соответствующей функции для вызова 'spi_SD_Read_Block'
Сами не пробовали перевести ?
Вс фев 24, 2019 10:18:49
Перевести отдельные слова я могу.
Уточнение, если поставить такую заглушку:
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 */
Вс фев 24, 2019 10:29:00
Чудеса...
У Вас ошибка, судя по содержимому её теста, связана не с указателем, а с невозможностью компилятору найти реализацию функции spi_SD_Read_Block.
Вс фев 24, 2019 21:19:17
С буфером вопрос решился - я что то думал что unsigned char и просто char в данном случае одно и тоже, а это не так.
Остальные вопросы в силе, (скоро новые возникнут).
Добавлено after 6 hours 45 minutes 21 second:
Новые вопросы:
Есть некоторые успехи, в этой тестовой функции:
Спойлер
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, если они создаются динамически, можно ли их заставить создаваться в стеке без потери функциональности
библиотеки?
Вт фев 26, 2019 00:55:41
Вот весь проект:
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, на проблему это не повлияло.
Добавлено after 8 hours 17 minutes 12 seconds:Нашёл ошибку, в функции чтения и записи секторов (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/ вам тут ничего не кажется подозрительным?
Добавлено after 5 hours 9 minutes 30 seconds:Новый вопрос, при каком минимальном количестве оперативной памяти в микроконтроллере у вас нормально работал FatFs не урезанный
(с поддержкой длинных имён и юникодом c русской кодовой страницей)?
Вт фев 26, 2019 17:11:43
Было переполнение стэка, он был задан 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" может быть много, они что при прерываниях тоже в стек лезут?
Вт фев 26, 2019 17:44:00
структуры у вас лезут не сами куда-то, а вы их помещаете либо в области глобальных переменных, либо в "куче", либо в области локальных переменных - а вот это ничто иное, как стек. если у вас структура определена внутри функции, как локальная, она попадет в стек - и это естественно.
FatFS от Чена в минимально-приемлемой конфигурации (чтение одного и запись другого файла) вполне неплохо обходится чуть более, чем килобайтом памяти. кстати, у него на сайте о требоаниях к ОЗУ все расписано весьма подробно и детально по всем возможностям...