[TUT] [C] Getting SD/MMC card working painlessly with FatFS

Go To Last Post
354 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would suggest not. This thread is about getting FatFs to work on an AVR. Only post things here that might help future users of FatFs achieve that goal. If you have a general question about filing functions and especially about PC filing then post that elsewhere. If it is about AVR then post it in the AVR Forum. If it is a general question then put it either in "General Electronics" or "Off Topic".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually i wanted to let you know that i have created a program which can Create a file, overwrite a file, add more data to a file and lastly read the file.

I am getting this error when i post the code:

Quote:
Bad Request

Your browser sent a request that this server could not understand.

This is the code if you are interested. It is working perfectly except that if u enter any alphabet instead of number as choice to perform operations, the program goes mad.
Now i wanted to know is this much basic understanding enough to move back to avr and the fatfs?

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to replace any % sign with % then you can post the code like this (BTW I used indent on it as your layout was atrocious and unreadable):

#include
#include
#include
#include
#include

int
main ()
{
  char fname[50];
  char data[200];
  char readstring[200];
  int ch;

menu1:
  while (ch != 5)
    {
      printf ("\n Press 1 to create a file ");
      printf ("\n Press 2 to overwrite a file ");
      printf ("\n Press 3 to append a file ");
      printf ("\n Press 4 to read a file ");
      printf ("\n Press 5 to exit program ");
      scanf ("%d", &ch);



      if (ch == 1)
	{
	  system ("cls");
	  printf ("\nPlease enter the name of file you want to create: ");
	  getchar ();
	  scanf ("%[^\n]", fname);
	  system ("cls");
	  printf ("The file <" "%s" "> has been created. \n", fname);


	  FILE *pFile;
	  pFile = fopen (fname, "w");

	  if (pFile != NULL)
	    {
	      fputs ("Your file has been made!", pFile);
	      fclose (pFile);
	    }
	  printf ("\nDone! \n ");
	  system ("PAUSE");
	  system ("cls");
	  goto menu1;

	}
/////////////////////////////////////////////////////
      if (ch == 2)
	{
	  system ("cls");
	  printf ("\nCaution: All the prevous data will be lost. ");
	  printf ("\nPlease enter the name of file you want to overwrite: ");
	  getchar ();
	  scanf ("%[^\n]", fname);
	  system ("cls");


	  FILE *pFile;
	  pFile = fopen (fname, "r");

	  if (pFile != NULL)
	    {
	      printf ("\nPlease enter the new next: ");
	      getchar ();
	      scanf ("%[^\n]", data);
	      pFile = fopen (fname, "w");
	      fputs (data, pFile);
	      fclose (pFile);

	      printf ("\nDone!\n ");
	      system ("PAUSE");
	      system ("cls");
	      goto menu1;
	    }
	  else
	    printf ("\nFile not found!\n ");
	  system ("PAUSE");
	  system ("cls");
	  goto menu1;
	}
////////////////////////////////////////////////////

      if (ch == 3)
	{
	  system ("cls");
	  printf ("\nPlease enter the name of file you want to append: ");
	  getchar ();
	  scanf ("%[^\n]", fname);
	  system ("cls");



	  FILE *pFile;
	  pFile = fopen (fname, "r");

	  if (pFile != NULL)
	    {
	      printf ("\nPlease enter the text you want to add: ");
	      getchar ();
	      scanf ("%[^\n]", data);
	      pFile = fopen (fname, "a");
	      fputs ("\n", pFile);
	      fputs (data, pFile);
	      fclose (pFile);

	      printf ("\nText has been added. \n");
	      system ("PAUSE");
	      system ("cls");
	      goto menu1;
	    }
	  else
	    fclose (pFile);
	  printf ("\nFile not found!\n");
	  system ("PAUSE");
	  system ("cls");
	  goto menu1;
	}
/////////////////////////////////////////////////
      if (ch == 4)
	{
	  system ("cls");
	  printf ("\nPlease enter the name of file you want to open: ");
	  getchar ();
	  scanf ("%[^\n]", fname);

	  FILE *pFile;
	  pFile = fopen (fname, "r");

	  if (pFile != NULL)
	    {
	      system ("cls");
	      do
		{
		  fgets (readstring, 200, pFile);
		  puts (readstring);
		}
	      while (!feof (pFile));
	      printf ("\n<<Reached end of file>>\n");
	      fclose (pFile);
	      system ("PAUSE");
	      system ("cls");
	      goto menu1;
	    }
	  else
	    printf ("\nFile not found! \n ");
	  system ("PAUSE");
	  system ("cls");
	  goto menu1;
	}
    }
}

(you sure about using "goto" ??)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Now i wanted to know is this much basic understanding enough to move back to avr and the fatfs?

Yes, you can see exactly the same concepts there that you will use in FatFs. In FATFS "FILE" is effectively "FIL" and most of the functions start "f_" rather than just "f". Also the parameters are a little different but in effect achieve the same things. The key thing you learnt is that you create files with fopen/f_open and the same is later used to reopen files you already created. You write with fputc, fputs, fwrite and FatFs has f_putc, f_puts and f_write. You read with fgetc, fgets, fread and FatFs has f_gets and f_read but strangely no f_getc (though Chan does the equivalent with f_read(fp, s, 1, &rc); inside f_gets so you could either implement a function or just #define an equivalent for f_getc). In DOS you close the file with fclose, in FatFs it is f_close. If you want to move to a particular place in a file in DOS it is fseek while FatFs uses f_lseek.

On the whole this means you can throw together a quick DOS filing program on the PC to test out an idea (like how do you sort the lines in a file say) then you can implement it in almost identical FatFs functions on the AVR and be pretty sure the same logic is going to work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry i posted it without cleaning up the code...

Quote:

(you sure about using "goto" ??)

err no, why?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

Now i wanted to know is this much basic understanding enough to move back to avr and the fatfs?

Yes, you can see exactly the same concepts there that you will use in FatFs. In FATFS "FILE" is effectively "FIL" and most of the functions start "f_" rather than just "f". Also the parameters are a little different but in effect achieve the same things. The key thing you learnt is that you create files with fopen/f_open and the same is later used to reopen files you already created. You write with fputc, fputs, fwrite and FatFs has f_putc, f_puts and f_write. You read with fgetc, fgets, fread and FatFs has f_gets and f_read but strangely no f_getc (though Chan does the equivalent with f_read(fp, s, 1, &rc); inside f_gets so you could either implement a function or just #define an equivalent for f_getc). In DOS you close the file with fclose, in FatFs it is f_close. If you want to move to a particular place in a file in DOS it is fseek while FatFs uses f_lseek.

On the whole this means you can throw together a quick DOS filing program on the PC to test out an idea (like how do you sort the lines in a file say) then you can implement it in almost identical FatFs functions on the AVR and be pretty sure the same logic is going to work.

I certainly have some understanding now, in fact now i know what line is doing what in the code you gave. (reads poem.txt) Btw what is the FRESULT ? and why it turns blue...

So i guess now its basically trying out different commands of the library but i have still a confusion. Like in the code i made, it is quite easy to perform File operations. But in FATfs we are dealing with an SD card, so does the library handles the SD card itself? Like after it is initialized, do i just have to make a code for File operations or do i need more commands apart from f_ commands?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Btw what is the FRESULT ?

If it turns blue I guess you are using AS6? If so you can always put your cursor on any word in the code, right-click and "Goto implementation" to find out what an object is and how it's defined. For FRESULT you will find:

typedef enum {
	FR_OK = 0,				/* (0) Succeeded */
	FR_DISK_ERR,			/* (1) A hard error occurred in the low level disk I/O layer */
	FR_INT_ERR,				/* (2) Assertion failed */
	FR_NOT_READY,			/* (3) The physical drive cannot work */
	FR_NO_FILE,				/* (4) Could not find the file */
	FR_NO_PATH,				/* (5) Could not find the path */
	FR_INVALID_NAME,		/* (6) The path name format is invalid */
	FR_DENIED,				/* (7) Access denied due to prohibited access or directory full */
	FR_EXIST,				/* (8) Access denied due to prohibited access */
	FR_INVALID_OBJECT,		/* (9) The file/directory object is invalid */
	FR_WRITE_PROTECTED,		/* (10) The physical drive is write protected */
	FR_INVALID_DRIVE,		/* (11) The logical drive number is invalid */
	FR_NOT_ENABLED,			/* (12) The volume has no work area */
	FR_NO_FILESYSTEM,		/* (13) There is no valid FAT volume */
	FR_MKFS_ABORTED,		/* (14) The f_mkfs() aborted due to any parameter error */
	FR_TIMEOUT,				/* (15) Could not get a grant to access the volume within defined period */
	FR_LOCKED,				/* (16) The operation is rejected according to the file sharing policy */
	FR_NOT_ENOUGH_CORE,		/* (17) LFN working buffer could not be allocated */
	FR_TOO_MANY_OPEN_FILES,	/* (18) Number of open files > _FS_SHARE */
	FR_INVALID_PARAMETER	/* (19) Given parameter is invalid */
} FRESULT;

So each of the f_*() function you call might return any of these numbers to indicate whether it worked (FR_OK==0) or if there was a problem (!=0). For example if you call f_open() to read a file and it's not there you might get FR_NO_FILE. This highlights the fact that each time you call an f_*() function you should test the return value and only proceed if there was not problem. Something like:

FRESULT retval;
retval = f_fopen(&fil, "test.fil", "r");
if (retval == FR_OK) {
  retval = f_gets(buff, 10, &fil);
  if (retval == FR_OK) {
    ...

This way you only go on to do the f_gets() if the f_open() succeeded and you only go into the code beyond the f_gets() if that succeeded and so on.

Quote:

But in FATfs we are dealing with an SD card, so does the library handles the SD card itself? Like after it is initialized, do i just have to make a code for File operations or do i need more commands apart from f_ commands?

You can do everything with f_*() commands thought it is VITAL that the very first f_*() function you call is f_mount (and CHECK the FRESULT!). The f_mount is perhaps the one place where FatFs filing differs from DOS/Unix filing because in those systems the filing system is already mounted (though Linux uses may well be familiar with "mount" and etc/fstab which is something you do before running a program to access files on a drive). In the AVR there is no operating system so it's your program's responsibility to start by mounting the file system (which basically means "initialise everything so we're ready to read/write").

Chan's example on this page of the manual is useful:

http://elm-chan.org/fsw/ff/en/op...

However note that he is actually doing something a little unusual here. He has a system with TWO SD/MMC cards connected so he has to call mount twice. As most of us only have one SD/MMC attached to our AVRs we generally only need to make one call to the f_mount function.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you, couldn't be explained any better.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sheesh. Everything I've tried to do today is smack into a wall.

Since I've managed to read text with FatFS, I thought I'd try to write some. Of course, google finds me unrelated stuff.

	if (disk_initialize(0) != STA_NOINIT)
	{
		FRESULT res;
		FATFS fs;

		res = f_mount(0, &fs);
		res = f_unlink("Reg10.txt");
		FIL *f ;
		res = f_open(f, "Reg10.txt",FA_WRITE | FA_CREATE_NEW);
		for (uint8_t i = 0 ; i < 10 ; i++)
		{
			char st[20];
			itoa(TenRegs[i],st,16) ;
			f_puts(st,f);
			f_putc(" ",f);
			itoa(TenRegs[i],st,2);
			f_puts(st,f);
			f_putc(13,f);
			f_putc(10,f);
		}
		f_close(f);
	}

So, naturally, it gives me dozens of errors.

1. Expected TCHAR but argument is *c. It points to

int f_putc (TCHAR c, FIL* fp);

in ff.h.

2. Undefined reference to f_unlink.

Of course, he wouldn't include "how to" in http://elm-chan.org/fsw/ff/en/pu... We're all supposed to intuitively know that. Google gives me examples that look nothing like fatfs code.

274,207,281-1 The largest known Mersenne Prime

Measure twice, cry, go back to the hardware store

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) You used:

         f_putc(" ",f);

that needs to be:

         f_putc(' ',f);

(a character not a string).

2) The chances are f_unlink is not being built. Take a look at ffconf.h:

#define _FS_READONLY	0	/* 0:Read/Write or 1:Read only */
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/  writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/  f_truncate and useless f_getfree. */


#define _FS_MINIMIZE	1	/* 0 to 3 */
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/
/   0: Full function.
/   1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
/      are removed.
/   2: f_opendir and f_readdir are removed in addition to 1.
/   3: f_lseek is removed in addition to 2. */

My guess is that you either have _FS_READONLY set to 1 or _FS_MINIMIZE is not 0 - from 1 onwards there is no unlink.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

_F_MINIMIZE was set to 1.

274,207,281-1 The largest known Mersenne Prime

Measure twice, cry, go back to the hardware store

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just checked back in after my post of 12/5/2012 got no replies for several months. So, I assumed that very few people had tried using the latest code from Chan and that the older code on which the original tutorial based was no longer available. I had many projects in progress, so tabled getting the SD hardware working on a couple of cards until I had more time.

Thanks meslomp for your write-up and Clawson' April 11 and June 22 updates!

I printed and read again all 62, double sided pages on this topic. It looks pretty straight forward starting with the June-22 AV6 project and the few posts that are actually relevant to me post 1 to now.

I see conflicting information about the code size on something like an Atmega328, so I might run into trouble there.

I'll post how things go.

Thanks again!

Dave Thomas

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I see conflicting information about the code size on something like an Atmega328,

That's down to how much you switch on or off in ffconf.h. You can pare it back to not much over 10K or you can fill 32K. Smaller obviously means less functionality of course.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I saw that, but one reader was talking about over 40K!

But, I got it to compile fine under 11K program memory:

Task "RunOutputFileVerifyTask"
Program Memory Usage : 10900 bytes 33.3 % Full
Data Memory Usage : 1262 bytes 61.6 % Full

No Joy yet on getting it to run, though. The call to send_cmd(CMD0,0) in disk_initialize isn't returning 1.

Still debugging. I don't have a console, so it's a bit painful--just inserting code to light an LED at various places in the code to home in on what's going on.

I ordered a Dragon yesterday--if I don't find something in an hour or so, I'm just going to wait until it arrives. Single-stepping through the code would be much quicker than what I'm doing.

Thanks,

Dave

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Testing using the main.c provided in the June 22 Clawson post. My hardware doesn't have a way to display UART output, so I right now I just turn on an LED if the f_open succeeds.

It didn't until I put a poem.txt on the SD (using my laptop). So, I think that's a good start.

I need to write to the SD, so I'll figure a test case to write a hello world on the SD and see if that works.

But, I think I do have an issue with my board. The SPI is used on another device and I swapped the CS I planned to use for the SD with that of the other device. So, the SS pin goes to the other device and PD4 is actually the CS for the SD card.

I'm "bit-banging" the SPI for the other device. I think I'll have to do this for the SD card too. Otherwise, the required SS pin toggles will mess up the SPI hardware module.

So, I'm debating whether I should just turn another card, or just bit-bang the SPI for SD access too. Speed isn't an issue for my application, since all the data that will be written to the card comes from a 4800 baud serial interface.

Also, the FatFs code just blocks waiting for SPI completion, so it's not like use of the SPI hardware on the processor is any better than bit-banging.

There's also some "flakiness". After programming, I have to remove the power to get through the code and light my "success" LED. Just doing a reset isn't sufficient. Maybe has to do with the other device on the SPI, though the test case should be keeping it off the SPI by holding its CS high.

Also, someone mentioned in one of the posts that he had to remove the SD card when ISP programming? I understand why that's necessary if an external pull-up isn't used on the SD CS, since all outputs of the processor to to Hi-Z when the part is in reset. So, the SS pin could drive low or get capacitively bounced active.

I've had that issue on other cards with SPI peripherals and fixed by adding an external pull-up..

If SPI devices are CS is held inactive (high), even during reset using an external pull-up, should the SD card interfere with ISP (mine doesn't seem to).

Thanks for the great posts!

Dave Thomas

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've got this up and working too.

Only things I would add--

no problem using ISP with the SD card inserted--just make sure you have an external resistor pull-up on the pin you use for the SD pull-up.

If you have multiple SPI devices, note that the power_down functions disables SPI. Which means communication to ALL SPI devices will be disabled, not just the mmc.

Other than that, no issues!

Great tutorial, thanks.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know what i'm doing wrong ...
I try it for 3 weeks to make the fat fs working ... no susces.
I'm using an atmega328p at 12Mhz
on portc 0-1-2 have an rgb led for debug.
portb 0 ->CS
portb 5 ->SCLK
portb 4 ->MISO
portb 3 ->MOSI
i've failed with the fool_proof example from witch i have seen it's using bitbanging.
Anny help is welcome
sdmmc.c

#define DO_INIT()					/* Initialize port for MMC DO as input */
#define DO			(PINB & _BV(PB4))	/* Test for MMC DO ('H':true, 'L':false) */

#define DI_INIT()	DDRB  |= _BV(3)	/* Initialize port for MMC DI as output */
#define DI_H()		PORTB |= _BV(3)	/* Set MMC DI "high" */
#define DI_L()		PORTB &= ~_BV(3)	/* Set MMC DI "low" */

#define CK_INIT()	DDRB  |= _BV(5)	/* Initialize port for MMC SCLK as output */
#define CK_H()		PORTB |= _BV(5)	/* Set MMC SCLK "high" */
#define	CK_L()		PORTB &= ~_BV(5)	/* Set MMC SCLK "low" */

#define CS_INIT()	DDRB  |= _BV(0)	/* Initialize port for MMC CS as output */
#define	CS_H()		PORTB |= _BV(0)	/* Set MMC CS "high" */
#define CS_L()		PORTB &= ~_BV(0)	/* Set MMC CS "low" */
############################
main.c
############################
#define F_CPU 12000000
#include 	/* Device specific declarations */
#include 
#include "ff.h"		/* Declarations of FatFs API */

FATFS FatFs;		/* FatFs work area needed for each volume */
FIL File;			/* File object needed for each open file */

void blink(unsigned int led, unsigned int nr);
int main (void)
{
	DDRC=0b00000111;
	_delay_ms(200);
	for (;;){
		if(f_mount(&FatFs,"",1)== FR_OK){
			blink(1,1);// blink blue one time
	}
		blink(0,1);//blink red one time
}
}

void blink(unsigned int led, unsigned int nr){
	while(nr){
		PORTC |=_BV(led);
		_delay_ms(100);
		PORTC &=~_BV(led);
		_delay_ms(900);
	}
}

/*---------------------------------------------------------*/
/* User Provided RTC Function called by FatFs module       */

DWORD get_fattime (void)
{
	/* Returns current time packed into a DWORD variable */
	return	  ((DWORD)(2013 - 1980) << 25)	/* Year 2013 */
			| ((DWORD)7 << 21)				/* Month 7 */
			| ((DWORD)28 << 16)				/* Mday 28 */
			| ((DWORD)0 << 11)				/* Hour 0 */
			| ((DWORD)0 << 5)				/* Min 0 */
			| ((DWORD)0 >> 1);				/* Sec 0 */
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
void blink(unsigned int led, unsigned int nr){ 
   while(nr){ 
      PORTC |=_BV(led); 
      _delay_ms(100); 
      PORTC &=~_BV(led); 
      _delay_ms(900); 
   } 
} 

Remind me again what nr is for in this routine. Was the plan to decrement it?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry, yes nr-- (number of blinks) I deleted from mistake

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've manage to write files on SD! I'm using the SPI routines for sdc card, and finally .. it's working!!! I changed to the 20 Mhz crystal, setting up TIMER2 CTC to obtain 100Hz. I don't know why but bitbanging sd card didn't worked for me ... Now I'm trying to play an wav file ... timer0 fast pwm , timer1 ctc mode with variable OCR1A from wav ... I will compare the first post of the thread and put the changes that i've been made to the code, if I found differences . :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have ATMEGA32 with 8MHz internal oscilator i connected everything, coppy files from avr_complex sample(ff.c, ff.h, diskio.h, integer.h, mmc.c, ffconf.h) and i just change the mmc.c on my ports in macros and power functions but the problem is further:

f_mount(&fs, "", 0); 
res = f_open(&Fil, "file.txt", FA_OPEN_EXISTING | FA_READ);

on every card there is a #13 error code which is:
FR_NO_FILESYSTEM
i tried on FAT, FAT32 with default size and other options...

I think the problem might be with uC and SPI
as someone tried to discuss in this topic but there was no correct anwser for him, well i have the same problem.

Or with timers i just call thease two blocks in main:

volatile UINT Timer;		/* Performance timer (100Hz increment) */
	
	/*---------------------------------------------------------*/
	/* 100Hz timer interrupt generated by OC2                  */
	/*---------------------------------------------------------*/


	ISR(TIMER2_COMPA_vect )
	{
		Timer++;			/* Performance counter for this module */
		disk_timerproc();	/* Drive timer procedure of low level disk I/O module */
	}

/* Start 100Hz system timer (TC2.OC) */
OCR2 = F_CPU / 1024 / 100 - 1;
TCCR2 = 0b00001101;
TIMSK |= _BV(OCIE2);
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well two questions:

1) Have you plugged the cards into a PC and downloaded a copy of WinHex from Xways software (the read-only version is free to try)? It will confirm what filesystem the cards actually have. Is it FAT12, FAT16, FAT32 or something else?

2) do you own/have access to an oscilloscope or logic analyser? There's nothing quite like it for diagnosing the operation of SPI.

In FatFs the checks made that might return FR_NO_FILESYSTEM are as follows:

	if (fmt) return FR_NO_FILESYSTEM;		/* No FAT volume is found */

	/* An FAT volume is found. Following code initializes the file system object */

	if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))		/* (BPB_BytsPerSec must be equal to the physical sector size) */
		return FR_NO_FILESYSTEM;

	fasize = LD_WORD(fs->win+BPB_FATSz16);				/* Number of sectors per FAT */
	if (!fasize) fasize = LD_DWORD(fs->win+BPB_FATSz32);
	fs->fsize = fasize;

	fs->n_fats = b = fs->win[BPB_NumFATs];				/* Number of FAT copies */
	if (b != 1 && b != 2) return FR_NO_FILESYSTEM;		/* (Must be 1 or 2) */
	fasize *= b;										/* Number of sectors for FAT area */

	fs->csize = b = fs->win[BPB_SecPerClus];			/* Number of sectors per cluster */
	if (!b || (b & (b - 1))) return FR_NO_FILESYSTEM;	/* (Must be power of 2) */

	fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);	/* Number of root directory entries */
	if (fs->n_rootdir % (SS(fs) / SZ_DIR)) return FR_NO_FILESYSTEM;	/* (BPB_RootEntCnt must be sector aligned) */

	tsect = LD_WORD(fs->win+BPB_TotSec16);				/* Number of sectors on the volume */
	if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);

	nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt);				/* Number of reserved sectors */
	if (!nrsv) return FR_NO_FILESYSTEM;					/* (BPB_RsvdSecCnt must not be 0) */

	/* Determine the FAT sub type */
	sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR);	/* RSV+FAT+DIR */
	if (tsect < sysect) return FR_NO_FILESYSTEM;		/* (Invalid volume size) */
	nclst = (tsect - sysect) / fs->csize;				/* Number of clusters */
	if (!nclst) return FR_NO_FILESYSTEM;				/* (Invalid volume size) */

Prior to that is a call to check_fs() which should have returned 0 if it found the AA55 signature of an MBR or BPB. I'd suggest, with the aid of WinHex working through each of those tests in turn and assuming the cards do have a FAT filing system find out which of the policed rules is being violated.

Alternatively either breakpoint each of those return points if you have a JTAG debugger or put some diagnostic code (UART, LEDs, whatever) at each point in your local copy of ff.c and find out exactly which of those rules is violated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

how should i do the same thing with xmega64a3u and 128mb mmc?? tanx

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In Chan's documentation, he frequently uses the word "collapted." For example in the description of disk_initialize() this appears:

Quote:

Application program MUST NOT call this function, or FAT structure on the volume can be collapted. To re-initialize the file system, use f_mount() function instead. This function is called on volume mount process by FatFs module to manage the media change.

Can anyone tell me what he means, I am not familiar.

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I read it to mean "corrupted"

(I know a joke about far eastern pronunciation but I better not recount it ;-))

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have been using FATfs with an ATmega1284P and an SD card via the hardware SPI, and it works fine.

I am working on an MP3 player using the 1284P and a VLSI 1063 DSP which allows me to output a 44.1 KHz Mp3 to a Class D amplifier in the I2S format. My first attempt used the hardware SPI to communicate with both the SD card and the DSP. This did not work fine. Probably because of the fairly slow access time to the SD card over the SPI.

So, I decided to use the second SPI available on the 1284P, which is an MSPI, or a USART converted to use as a SPI. This seemed like a good solution, because I could use the MSPI to acquire data from the SD card and, simultaneously, send it to the DSP with the SPI, interrupt driven.

The problem, is that I have not been successful making the MSPI talk to the SD card. I altered the FATfs file mmc.c for the MSPI as shown in the attached file.

I was hoping that someone might have done this and recognize why FATfs reports FR_INVALID_OBJECT when I try to access it with the MSPI, but works fine when I use the SPI. The code that calls the SPI(MSPI) is the same in either case, so the problem must be in mmc.c.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Usual question : what's the return value from disk_initialize()?

Also does a scope show the MOSI MISO SCK lines making the right noises?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The MSPI acts normally, I get CS, MOSI, MISO and SCLK on the scope. The return value of disk initialize is 0. It pounds out the dummy bits and there appears to be an answer back from the SD card. But when I f_open, I get res = NO_FILE_SYSTEM. If I take exactly the same code, but swap out the mmc.c file back to the one using the regular SPI, I get FR_OK and I can read the MP3 file without any problem.

I was just hoping that someone else had done this and seen the same problem. Its probably some little glitch that I am missing.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A follow up on this. The two SPI's work fine if you use the MSPI to send data to the codec, and use the SPI communicate with the SD card. I do not know why, but for some reason, FATfs doesn't like the MSPI. Using both SPI's vastly increases the data rate you can send from the SD card to a digital signal processor using FATfs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
FATfs doesn't like the MSPI.
I'd be very surprised if FatFs held ANY kind of opinion about any hardware device. If the device works like an SPI then FatFs simply works. If it didn't then it's because the MSPI was not behaving entirely like an SPI, FatFs's opinion didn't count.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hellow all!

I have no skills about communication between microcontroller and sd car but i want to writing data from my temperature sensor ds18b20 into the sd card.
I'll capture the temperature from sensor for example every 1 miunute and this value i want to put into csv file on every line for each value at every one minute.
I wonder whether is this hard to do with this FatFs library.
I am using atmega16 mcu and I appreciate of any help and suggestions.
TNX

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No it's not hard, in fact once you are over the hurdle of getting card communication working it's incredibly easy, which is why so many people use FatFs. Which C compiler?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using AVR studio, i don't know at first how should i begin with this.
At the beginning i downloaded fatfs library from this page:
http://elm-chan.org/fsw/ff/00index_e.html
I was importing all files in map ffsample/avr-toolproof into avr studio and compiled the code, it was successsfuly.
Now i must organize all code that it will compatibile with atmega16 MCU and then try to write somenthing into sd card...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I you missed it and just posted a question here because the posts seems to be about SD card: The first page of this thread start out with a tutorial about exactly this.

Have you read it?
Have you tried to repeat what is done in the tutorial?

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also don't just read the first post/page, FatFs has developed and so has this thread so read all 17 pages.

Note that mega16 with just 1K of SRAM can be "tight" for FAT work. Consider trading up to a larger micro (mega32?) or consider using the "petit" version of FatFs. Also don't just read the first post/page, FatFs has developed and so has this thread so read all 17 pages.

Note that mega16 with just 1K of SRAM can be "tight" for FAT work. Consider trading up to a larger micro (mega32?) or consider using the "petit" version of FatFs. Also don't just read the first post/page, FatFs has developed and so has this thread so read all 17 pages.

Note that mega16 with just 1K of SRAM can be "tight" for FAT work. Consider trading up to a larger micro (mega32?) or consider using the "petit" version of FatFs.

EDIT: Wow what happened in this post? I didn't type that multiple times so something went wrong when I posted it?!?

Last Edited: Mon. May 12, 2014 - 08:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just try to write a test program from page mentioned above in MCU and works great!
The program has created a txt file and write some words into it.
My next goal is write data to csv file as described.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If someone of you working on sime kind of data logging with sd card using FATFS library?
I want to write data (temperature for example ) in csv file every 1 minute and each of data should be written in separate line.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Where's the complication in that? Don't you just f_open() then either f_printf() or sprintf/f_puts() to put the data in the file then? If you were doing it on a PC you would:

$ cat test4.c
#include <stdio.h>
#include <stdint.h>

FILE * fout;

int main(void) {
int i;
fout = fopen("data.csv", "wt");
if (fout) {
for (i=0; i< 10; i++) {
fprintf(fout, "%u, %u\n", i, i*i);
}
fclose(fout);
}
return 0;
}
$ gcc test4.c -o test4
$ ./test4
$ cat data.csv
0, 0
1, 1
2, 4
3, 9
4, 16
5, 25
6, 36
7, 49
8, 64
9, 81

The way you'd do this in FatFs is almost identical (which is kind of the point).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

im tryring to use fatfs with my atmega32 but seems not working.

can i redefine F_CPU to use it at my crystal? (14.7456mhz)

 

i had made SPI working code before.

 

i tried to play with this example several times. but without results (post #278)

http://www.avrfreaks.net/comment...

 

i'm using atmega32 with 147456mhz crystal and microsd card module from ebay.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

F_CPU has very little to do with FatFs anyway. The only place timing really comes into things is that you should have a 100ms timer used for timeouts and to scan the card present and write protect state but if the timing is off a bit it doesn't really matter. If you have problems they are more likely elsewhere. It can help a lot to have a scope or logic analyser to check the SPI signals are doing what you expect. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey, clawson

 

Do you think I will be able to convert your ffsamp-jun22 to support xmega or will I run into major issues. I have started doing so, however questioned if it would work in the end...

 

Jed

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah that should be quite possible. As this whole thing has hopefully shown the actual dependency on hardware interaction in FatFs is actually really small and the good news is that it's pretty much all isolated into mmc.c (in the ffsamp-jun22 files - later it is called mmc_avr.c). It just consists of using the SPI and a couple of IO pin (card detect and write protect sensors). So that's pretty much the only "porting" required to move this to Xmega. Just compare the tiny/mega way of doing those things (SPCR/SPDR/SPR/DDR/PORT/PIN) with the Xmega way of doing it and make adjustments accordingly. The only other "hardware interaction" that will need to be changed is the setting up of a timer interrupt - you need to set a timer to 100Hz /10ms and it should call Disk_TimerProc() each time the interrupt occurs.

 

But that is ALL you have to change. Everything else in FatFs is completely independent of the hardware and should not need to change for Xmega. This is one of the clever things about FatFs - it isolates the h/w specific bits so porting to new targets is very easy (which is why it's available for all kinds of CPU and "drive" types).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, I think i've ported it. it builds....

I think I have a hardware issue... the program doesn't get receive anything from the card within disk_initialize>send_cmd. I'm trying to communicate with a micro SD via a SD adapter, I believe the pin-out is different. 9(SD) is 1(microSD)  and pin 3(SD) is not connected to the microSD. I have an LED set up as shown in foolproof.jpg

 

I may have an issue with the timer as well, I'm fixing that up now.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A scope or logic analyser is invaluable when it comes to debugging SPI activity. A decent device will even decode the "protocol" for you ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Managed to finally write to the card!! the issue I have now is at power-up some times it works sometimes it doesn't.

 

It seems to have more success when I wait about 5 seconds before powering up again, however I wish for it to be able to power off and on within 0.5 seconds. I have 100nF caps from Vcc to ground that seem to be holding charge for a bit, Could this be why? I added a bleeding resistor hoping it would discharge faster, didn't really change much.

Is there something I can do to power down faster? I only have one capacitor between my regulator and the uC , I know it sounds bad but its a small scale design?

TWI comms work perfectly. It may be something to do with my clock settings or something as well I guess.  I'm a little lost haha. I have probably been pretty vague as well, which doesn't help anyone.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have the BOD enabled? It may help.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to say (despite how it looks!) this thread isn't really the place to diagnose FatFs and/or SD/MMC usage problems. The plan should be that this is just here to develop the text of the first post. So if you have some issue to diagnose it might be better to start a new thread elsewhere.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interesting. I want to follow this thread.

Chris PE

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Thank you to all the people who have contributed to this forum.

 

In gratitude, find attached my working source code to implement FATFS (version R0.12a ) on the XMEGA (ATXMEGA192D3).

 

This is a very simple example so you don't have to sort through lots of code to find what you are looking for.

 

Make sure the following project symbol definitions are added:

DRV_MMC=0

F_CPU=32000000

 

Don't forget to have a pull up resistor on the MISO line (between 50k & 100k) and supply the card with 3.3V!

 

And oh yes, make sure any other SPI devices on the same SPI bus are not interfering by turning them off by asserting their respective CS pins high!

Attachment(s): 

Last Edited: Sun. Sep 11, 2016 - 10:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey guys,

FI have read through this forum (well, most of it) and pretty much all the documentation by elm-chan.  I downloaded the latest sample project release oct. 14th 2017 which can be found here: http://elm-chan.org/fsw/ff/ffsample.zip There are a couple of new files in here that I am unfamiliar with and unsure of how to proceed.

 

It would be great to continue this thread documenting various avr platforms and newer revisions of FatFs.  

 

Problem summary:

Every time I do a disk_initialize(0) I get a STA_NOINIT.  I have probed my spi lines and I see nothing.

 

hardware:

I am using a mega2560 as my development avr.  (uses the atmega2560) I am using the spi lines through a level shifter to connect to the SD card (microSD to SD adapter) my connections are as follows:

 

DAT1-------NC
DO---------MISO (PB3)
Vss2-------GND
CLK--------SCK (PB1)
Vcc--------3.3V
Vss1-------GND
DI---------MOSI (PB2)
CS---------SS (PG1)
DAT2-------NC

 

Software:

First, I set up mmc_avr_spi.c to define my SPI ports and chip select ports.  I am not using the SD_PWR_PIN nor the MMC_CD / MMC_WP (card detect and write protect).

#ifndef F_CPU
#define F_CPU 16000000UL
#endif
/*
#define loop_until_bit_is_set(sfr,bit) \
		do { } while (bit_is_clear(sfr, bit))
*/
#include <avr/io.h>
#include "diskio.h"
#include "mmc_avr.h"

#define DD_MISO (1<<PB3) //DDB3 pin50
#define DD_MOSI	(1<<PB2) //DDB2 pin51
#define DD_SCK	(1<<PB1) //DDB1 pin52
#define DDR_SPI	DDRB
#define DD_CS	(1<<PG1)

#define SD_CS_PIN	1
#define SD_CS_PORT	PORTG
#define SD_PWR_PIN	0
#define SD_PWR_PORT	PORTC

/* Peripheral controls (Platform dependent) */
#define CS_LOW()		PORTG &= ~_BV(1)	/* Set MMC_CS = low */
#define	CS_HIGH()		PORTG |= _BV(1)	/* Set MMC_CS = high */
//#define MMC_CD			1 //(!(PINB & _BV(3)))	/* Test if card detected.   yes:true, no:false, default:true */
//#define MMC_WP			0 //(PINB & _BV(2))		/* Test if write protected. yes:true, no:false, default:false */
#define	FCLK_SLOW()		SPCR = (1<<SPE)|(1<MSTR)|(1<<SPR1)|(0<<SPR0);	/* Set SPI clock for initialization (100-400kHz) */
#define	FCLK_FAST()		SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);	/* Set SPI clock for read/write (20MHz max) */

 

Next, I set up the power_on and power_off functions. 

static
void power_on (void)
{
	//#if (defined SD_PWR_PIN | defined SD_PWR_PORT)
		DDRC|=(1<<SD_PWR_PIN); 			// Turns on PWR pin as output
		SD_PWR_PORT|=(1<<SD_PWR_PIN);	// Drives PWR pin high
		SD_CS_PORT |=(1<<SD_CS_PIN); 			// Turns on CS pin as output
		CS_LOW();
	//#endif
		
		CS_HIGH();
		
		PORTB |= (1<<DD_MOSI)|(1<<DD_SCK); //mosi and sck as output
		PORTB &= ~(1<<DD_MISO); //MISO as input
		SPCR = (1<<SPE)|(1<<MSTR); /* Initialize SPI port (Mode 0) */
}


static
void power_off (void)
{
	SPCR = 0;		/* Disable SPI function */

	DDRB  &= ~(DD_SCK | DD_MOSI);	/* Set SCK/MOSI/CS as hi-z, INS#/WP as pull-up */
	PORTB &= ~(DD_SCK | DD_MOSI);
	DDRB  &= ~DD_CS;
	PORTB &= ~DD_CS;
	
	#if 0	// not using
	PORTB |=  0b00110000;

	#endif
}

I then commented out some of the mmc_disk_timerproc function as I am not using write protection and card detect. 

void mmc_disk_timerproc (void)
{
	BYTE n;//, s;


	n = Timer1;				/* 100Hz decrement timer */
	if (n) Timer1 = --n;
	n = Timer2;
	if (n) Timer2 = --n;

	/*
	s = Stat;

	if (MMC_WP) {			// Write protected 
		s |= STA_PROTECT;
	} else {				// Write enabled 
		s &= ~STA_PROTECT;
	}
	if (MMC_CD) {			// Card inserted 
		s &= ~STA_NODISK;
	} else {				// Socket empty 
		s |= (STA_NODISK | STA_NOINIT);
	}
	Stat = s;				// Update MMC status 
	*/
}

In cfc_avr.c There are some control ports that seem platform dependent, but I am unsure of where those are being used. 

/* Contorl ports */
#define	CTRL_PORT		PORTC
#define	CTRL_DDR		DDRC
#define	DAT_PORT		PORTA
#define	DAT_DDR			DDRA
#define	DAT_PIN			PINA

I have removed their uart.h and uart.c and added my own to facilitate debug output. 

 

Problem Detail:

I called disk_initialize(0) and see that I get a STA_NOINIT returned. 

So I then step through with Atmel studios debugger and simply jumps to the end of the disk_initialize() function inside of diskio.c which returns “STATUS” which is defined as STA_NOINIT. 

I then probe the spi lines to see nothing on any of them.  I believe my error lies here: Mmc_avr_spi might not be set up correctly.

 

I have tried a new sd card, with the same result.  I have also tried a pull up on MISO lines with the same result. 

 

 

Been scratching my head at this for a couple of days now, any help would be appreciated.  

I have attached my atmel studio project files for convenience.  

 

Thanks!

Attachment(s): 

Pages