Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: FATfs и SD-карта
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Artem
Доброго времени суток! Микроконтроллер STM32 работает с SD картой по SPI. Прицеплена FATfs. Необходимо открыть файл для записи, если файла нет, то создать его и в него записать строку. Но вот в чём проблема, если в файле уже есть хоть один символ, то запись проходит успешно, а если файл только что создали, т.е. его размер равен 0 , то запись не происходит, f_write возвращает FR_INT_ERR. Не могу понять в чём проблема... Помогите кто чем может.. Заранее спасибо.
Вот код:
CODE
void proba ()
{
volatile FRESULT res; // FatFs function common result code
UINT br, bw; // File read/write count
uint8_t str_cnt = 0;

// Register a work area for logical drive 0
f_mount(0, &fs);

// Открываем файл
res = f_open(&fdst, "test_cpy.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
if(res)
{
res = res;
}


buffer[0] = 'A';
buffer[1] = 'B';
buffer[2] = 'C';
buffer[3] = 'D';
buffer[4] = 'E';

for(str_cnt = 0; str_cnt < 10; str_cnt++)
{
res = f_lseek(&fdst, fdst.fsize);
br = 5;
res = f_write(&fdst, buffer, br, &bw);
if(res)
{
res = res;
}

f_puts ("Proba \r\n", &fdst);
f_sync (&fdst);
}

f_close(&fdst);

// Unregister a work area before discard it
f_mount(0, NULL);
}


Добавлю:
Файл не пишется размером больше 4033 байт.


Сделал вот так:
CODE
void proba ()
{
volatile FRESULT res; // FatFs function common result code
UINT br, bw; // File read/write count
uint8_t str_cnt = 0;

// Register a work area for logical drive 0
f_mount(0, &fs);

// Открываем файл
res = f_open(&fdst, "test_cpy.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
if(res)
{
res = res;
}


buffer[0] = 'A';
buffer[1] = 'B';
buffer[2] = 'C';
buffer[3] = 'D';
buffer[4] = 'E';

for(str_cnt = 0; str_cnt < 10; str_cnt++)
{
res = f_lseek(&fdst, fdst.fsize);
br = 5;
res = f_write(&fdst, buffer, br, &bw);
if(res)
{
res = res;
}

f_puts ("Proba \r\n", &fdst);
f_sync (&fdst);
}

//---------------------------------------------------------------------------------
// Вот этот блок добавил

for(str_cnt = 0; str_cnt < 10; str_cnt++)
{
res = f_lseek(&data_file, ((&data_file)->fsize));

f_puts ("Proba\r\n", &fdst);

f_sync (&data_file);
}
//---------------------------------------------------------------------------------

f_close(&fdst);

// Unregister a work area before discard it
f_mount(0, NULL);
}

и стало писаться с в только что созданный файл, и размер файла не ограничен.
Ничего не понимаю, в чём дело? Что за танцы с бубном?
*rust*
Цитата
Файл не пишется размером больше 4033 байт.


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


Вот пример использования FATfs от ATMEL надеюсь он Вам поможет.
CODE
#include <stdio.h>
#include <string.h>
#include <board.h>
#include <utility/trace.h>
#include <utility/assert.h>
#include <utility/math.h>
#include <memories/MEDSdcard.h>

#include "fatfs_config.h"
#if _FATFS_TINY != 1
#include <fatfs/src/ff.h>
#else
#include <fatfs/src/tff.h>
#endif
#include <fatfs/src/ff_util.h>

//------------------------------------------------------------------------------
// Local constants
//------------------------------------------------------------------------------

/// Maximum number of LUNs which can be defined.
/// (Logical drive = physical drive = medium number)
#define MAX_LUNS 1

/// Available medias.
Media medias[MAX_LUNS];

//------------------------------------------------------------------------------
// Local variables
//------------------------------------------------------------------------------

#define ID_DRV DRV_MMC

#if _FATFS_TINY == 0
#define STR_ROOT_DIRECTORY "0:"
#else
#define STR_ROOT_DIRECTORY ""
#endif

#if defined(at91cap9stk)
#define MCI_ID 1 //no connector for MCIO/SPI0
#else
#define MCI_ID 0
#endif

const char* FileName = STR_ROOT_DIRECTORY "Basic.bin";

#if 0
//Bigger than this value will cause SD HC error now.
//#define DATA_SIZE (7*1024 + 512)
#define DATA_SIZE (9*1024)
//unsigned char data[DATA_SIZE];
unsigned char * data = (unsigned char*)0x60000400;
#else
#define DATA_SIZE 2064 // size of the file to write/read
// !!!minimum size 512 for erase operation !!!

unsigned char data[DATA_SIZE];
#endif

//------------------------------------------------------------------------------
// Local functions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
/// Do file system tests
/// \return test result, 1: success.
//------------------------------------------------------------------------------
static unsigned char RunFsTest(void)
{
unsigned int i;
unsigned int ByteToRead;
unsigned int ByteRead;
#if _FATFS_TINY == 0
unsigned int ByteWritten;
char key;
#endif

FRESULT res;
DIR dirs;
FATFS fs; // File system object
FIL FileObject;

// Init Disk
printf("-I- Please connect a SD card ...\n\r");
while(!MEDSdcard_Detect(&medias[ID_DRV], MCI_ID));
printf("-I- SD card connection detected\n\r");

printf("-I- Init media Sdcard\n\r");
if (!MEDSdcard_Initialize(&medias[ID_DRV], MCI_ID)) {
printf("-E- SD Init fail\n\r");
return 0;
}
numMedias = 1;

// Mount disk
printf("-I- Mount disk %d\n\r", ID_DRV);
memset(&fs, 0, sizeof(FATFS)); // Clear file system object
res = f_mount(ID_DRV, &fs);
if( res != FR_OK ) {
printf("-E- f_mount pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}

// Test if the disk is formated
res = f_opendir (&dirs,STR_ROOT_DIRECTORY);
if(res == FR_OK ){

// erase sdcard to re-format it ?
printf("-I- The disk is already formated.\n\r");

// Display the file tree
printf("-I- Display files contained on the SDcard :\n\r");
FF_ScanDir(STR_ROOT_DIRECTORY);

#if _FATFS_TINY == 0
printf("-I- Do you want to erase the sdcard to re-format disk ? (y/n)!\n\r");

key = DBGU_GetChar();
if( (key == 'y') || (key == 'Y'))
{
for(i=0;i<100;i++) {
MEDSdcard_EraseBlock(&medias[ID_DRV], i);
}
printf("-I- Erase the first 100 blocks complete !\n\r");
res = FR_NO_FILESYSTEM;
}
#endif
}

if( res == FR_NO_FILESYSTEM ) {

#if _FATFS_TINY == 0
//printf("-I- Press 'y' to start format:\n\r");
//if (DBGU_GetChar() != 'y') return 0;
// Format disk
printf("-I- Format disk %d\n\r", ID_DRV);
printf("-I- Please wait a moment during formating...\n\r");
res = f_mkfs(ID_DRV, // Drv
0, // FDISK partition
512); // AllocSize
printf("-I- Format disk finished !\n\r");
if( res != FR_OK ) {
printf("-E- f_mkfs pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}
#else
printf("-I- Please run Full version FAT FS test first\n\r");
return 0;
#endif
}

#if _FATFS_TINY == 0
// Create a new file
printf("-I- Create a file : \"%s\"\n\r", FileName);
res = f_open(&FileObject, FileName, FA_CREATE_ALWAYS|FA_WRITE);
if( res != FR_OK ) {
printf("-E- f_open create pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}

// Write a checkerboard pattern in the buffer
for (i=0; i < sizeof(data); i++) {
if ((i & 1) == 0) {
data[i] = (i & 0x55);
}
else {
data[i] = (i & 0xAA);
}
}
printf("-I- Write file\n\r");
res = f_write(&FileObject, data, DATA_SIZE, &ByteWritten);
printf("-I- ByteWritten=%d\n\r", (int)ByteWritten);
if( res != FR_OK ) {
printf("-E- f_write pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}
else {
printf("-I- f_write ok: ByteWritten=%d\n\r", (int)ByteWritten);
}

// Close the file
printf("-I- Close file\n\r");
res = f_close(&FileObject);
if( res != FR_OK ) {
printf("-E- f_close pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}
#endif

// Open the file
printf("-I- Open the same file : \"%s\"\n\r", FileName);
res = f_open(&FileObject, FileName, FA_OPEN_EXISTING|FA_READ);
if( res != FR_OK ) {
printf("-E- f_open read pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}
ASSERT( FileObject.fsize == DATA_SIZE, "File size value not expected!\n\r");

// Read file
printf("-I- Read file\n\r");
memset(data, 0, DATA_SIZE);
ByteToRead = FileObject.fsize;
res = f_read(&FileObject, data, ByteToRead, &ByteRead);
if(res != FR_OK) {
printf("-E- f_read pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}

// Close the file
printf("-I- Close file\n\r");
res = f_close(&FileObject);
if( res != FR_OK ) {
printf("-E- f_close pb: 0x%X (%s)\n\r", res, FF_GetStrResult(res));
return 0;
}

// compare read data with the expected data
for (i=0; i < sizeof(data); i++) {
ASSERT((((i & 1) == 0) && (data[i] == (i & 0x55)))
|| (data[i] == (i & 0xAA)),
"Invalid data at data[%u] (expected 0x%02X, read 0x%02X)\n\r",
i, ((i & 1) == 0) ? (i & 0x55) : (i & 0xAA), data[i]);
}
printf("-I- File data Ok !\n\r");

return 1;
}

//------------------------------------------------------------------------------
// Global functions
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
/// main
/// FatFs Full version
//------------------------------------------------------------------------------
int main( void )
{
TRACE_CONFIGURE(DBGU_STANDARD, 115200, BOARD_MCK);
printf("-- Basic FatFS Full Version with SDCard Project %s --\n\r",
SOFTPACK_VERSION);
printf("-- %s\n\r", BOARD_NAME);
printf("-- Compiled: %s %s --\n\r", __DATE__, __TIME__);

while(1) {
if (RunFsTest()) {
printf("-I- Test passed !\n\r");
}
else {
printf("-F- Test Failed !\n\r");
}
SD_Stop(MEDSdcard_GetDriver(MCI_ID),
MEDSdcard_GetDriver(MCI_ID)->pSdDriver);

printf("\n\r** any key to start test again **\n\r");
DBGU_GetChar();
}

return 0;
}
Artem
Сделал вот так:
CODE


static FATFS fs; // Work area (file system object) for logical drives
static FIL fdst, data_file; // file objects

void proba ()
{
volatile FRESULT res; // FatFs function common result code
UINT br, bw; // File read/write count
uint8_t str_cnt = 0;

// Register a work area for logical drive 0
f_mount(0, &fs);

// Открываем файл
res = f_open(&data_file, "test_cpy.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
if(res)
{
res = res;
}


buffer[0] = 'A';
buffer[1] = 'B';
buffer[2] = 'C';
buffer[3] = 'D';
buffer[4] = 'E';

for(str_cnt = 0; str_cnt < 10; str_cnt++)
{
res = f_lseek(&data_file, data_file.fsize);
br = 5;
res = f_write(&data_file, buffer, br, &bw);
if(res)
{
res = res;
}

f_puts ("Proba \r\n", &data_file);
f_sync (&data_file);
}

//---------------------------------------------------------------------------------
// Вот этот блок добавил

fdst = fdst;
//---------------------------------------------------------------------------------

f_close(&data_file);

// Unregister a work area before discard it
f_mount(0, NULL);
}


Вот только не понятно, почему если оставить неиспользуемый fdst , то всё работает, если его закомментировать, то опять с начала файла не пишет, и размер файла не больше 4033 байт. (забыл сказать , компилятор IAR ARM, FreeRTOS) размер стека увеличивал, не помогает...
что такое может быть?
sergeeff
Учитывая, что сам FatFS пользуют, неверное, миллионы программистов и она работает, проблема, скорее всего, в той части, которую вы сами к этой библиотеке "прикрутили" - функции физического чтения/записи сектора. Ва бы их внимательно проверили и отладили до FatFS.


Во-вторых, может вы можете свой тест запустить не под FreeDOS? Тогда тоже многое может проясниться.
Artem
Так вот если файл не нулевого размера, эти функции работают же. Файл пишется. Поэтому на них вроде и не думаю. Понятно, что ошибка где то у меня, не понятно только где..
sergeeff
На мой взгляд, должно быть что-то типа:


CODE
void proba ()
{
volatile FRESULT res; // FatFs function common result code
UINT br, bw; // File read/write count
uint8_t str_cnt = 0;
static FATFS fs; // Work area (file system object) for logical drives
static FIL fdst, data_file; // file objects

// Register a work area for logical drive 0
f_mount(0, &fs);

res = f_open(&data_file, "test_cpy.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
if(res != FR_OK)
{
printf("ERR : %d\n", res);
f_close(&data_file);
return;
}


buffer[0] = 'A';
buffer[1] = 'B';
buffer[2] = 'C';
buffer[3] = 'D';
buffer[4] = 'E';

if(data_file.fsize)
res = f_lseek(&data_file, data_file.fsize); // goto to the end of file only,
// if file exist

if(res != FR_OK)
{
printf("ERR : %d\n", res);
f_close(&data_file);
return;
}

for(str_cnt = 0; str_cnt < 10; str_cnt++)
{
res = f_write(&data_file, buffer, 5, &bw);
if(res != FR_OK)
{
printf("ERR : %d\n", res);
f_close(&data_file);
return;
}

f_puts("Proba \r\n", &data_file);
}


f_close(&data_file);

// Unregister a work area before discard it
f_mount(0, NULL);
}
Artem
Спасибо, Ваш пример работает. Переработал свой код по образу и подобию, тоже заработало. Спасибо!
dimasusl
Цитата(Artem @ May 6 2011, 09:38) *
Спасибо, Ваш пример работает. Переработал свой код по образу и подобию, тоже заработало. Спасибо!

Artem, добрый день. У меня аналогичный набор (stm32+fatfs+freertos) и абсолютно та же проблема. При этом я ранее реализовывал эту связку на более старшем проце, только там был SDIO, а не SPI как здесь. Вроде делаю все как у вас заработало - у меня эффект ноль. Можете скинуть ваши исходники относительно Fatfs (ff.c diskio.c и т.п.) на мыло dimasusl@gmail.com?

Цитата(dimasusl @ Jun 23 2011, 16:00) *
Artem, добрый день. У меня аналогичный набор (stm32+fatfs+freertos) и абсолютно та же проблема. При этом я ранее реализовывал эту связку на более старшем проце, только там был SDIO, а не SPI как здесь. Вроде делаю все как у вас заработало - у меня эффект ноль. Можете скинуть ваши исходники относительно Fatfs (ff.c diskio.c и т.п.) на мыло dimasusl@gmail.com?

Блин, занятное дело...

Был код
Код
res = f_mount(0, &fs);
res = f_open(&fsrc, "spi1.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE );
if (fsrc.fsize) res = f_lseek(&fsrc, fsrc.fsize);
res = f_write(&fsrc, usb_buffer, sizeof(usb_buffer), &br);
res = f_close(&fsrc);
res = f_mount(0, NULL);

Файл создавался, но данные в него не писались (если сделать ненулевой размер файла то все Ок).
Подсмотрел тут что еще юзаете для своих целей f_puts(...)
Код
res = f_mount(0, &fs);
res = f_open(&fsrc, "spi1.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE );
if (fsrc.fsize) res = f_lseek(&fsrc, fsrc.fsize);
res = f_puts("",&fsrc); // Пустая строка, чтобы не "ломать" формат файла
res = f_write(&fsrc, usb_buffer, sizeof(usb_buffer), &br);
res = f_close(&fsrc);
res = f_mount(0, NULL);

и стало все Ок и при нулевом размере файла. Откуда ноги растут так и не ясно

Artem
Добрый день. У меня проблема была с файлом sdc_diskio.c (низкоуровневые функции работы с SD). А если ещё точнее, то проблема была с функцией Receive_DataBlock. Получалось, что я при чтении вылезал за область памяти прёмного буфера, и при этом портил структуру fs. После устранения, проблемы исчезли.

PS. Письмо отправил
dimasusl
Цитата(Artem @ Jun 24 2011, 09:02) *
Добрый день. У меня проблема была с файлом sdc_diskio.c (низкоуровневые функции работы с SD). А если ещё точнее, то проблема была с функцией Receive_DataBlock. Получалось, что я при чтении вылезал за область памяти прёмного буфера, и при этом портил структуру fs. После устранения, проблемы исчезли.

PS. Письмо отправил


Ответил на мыло, но напишу и тут, вдруг кому будет полезно

Код
static
BOOL Receive_DataBlock(
    BYTE *buff,            /* Data buffer to store received data */
    UINT btr            /* Byte count (must be multiple of 4) */
)
{
    BYTE token;
    MMC_SELECT(); // !!!!!!!!!! ДОБАВИЛ ЭТО !!!!!!!!!!!!!!!!
    Timer1 = 10;
    do {                            /* Wait for data packet in timeout of 100ms */
        token = SPI_ReadWrite_Byte(0xff);
    } while ((token == 0xFF) && Timer1);
    if(token != 0xFE) return FALSE;    /* If not valid data token, retutn with error */

    btr--;  //!!!!!!!!!! И ДОБАВИЛ ЭТО !!!!!!!!!!
    do {                            /* Receive the data block into buffer */
        *buff++ = SPI_ReadWrite_Byte(0xff);
    } while (btr--);
    SPI_ReadWrite_Byte(0xff);        /* Discard CRC */
    SPI_ReadWrite_Byte(0xff);

    return TRUE;                    /* Return with success */
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.