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

Go To Last Post
376 posts / 0 new

Pages

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

I didn't look at your entire code, but one thing catched my eye since I stumbled across it myself not too long ago.

 

 

In the main.c, you commented out the following lines:

#ifdef DRV_MMC
	xprintf(PSTR("MMC ==> %u\n"), DRV_MMC);
#endif

 

What happens if you put that code in your main function (or something equivalent) before calling disk_initialize? What value do you get for DRV_MMC?

 

It looks like you never defined "#define DRV_MMC", at least I couldn't find it.

 

Either disk_initialize itself returns STA_NOINIT if neither cf_disk_initialize nor mmc_disk_initialize got called (in diskio.c) or if it isn't cleared in the mmc_disk_initialize function (in mmc_disk_initialize.c).

 

If you did not define it, do so. I set a "#define DRV_MMC 0" in the diskio.h. Then test again what the lines above output.

 

And if I am not mistaken, you don't have to call disk_initialize yourself, you simply use f_mount.

For example:

FATFS fs;
FIL file1;
...
xprintf(PSTR("mount rc=%d\n"), f_mount(&fs,"",0));
xprintf(PSTR("open1 rc=%d\n"), f_open(&file1,"test.txt",FA_WRITE|FA_OPEN_ALWAYS));
...

 

 

The function f_mount will call find_volume which will then call disk_status and disk_initialize, if you call f_mount with opt == 1. Or it will be called when you use f_open which calls find_volume aswell.

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

Hello FileNotFound,

I wanted to see if there were any intialization errors as f_mount () initializes later (not at time of calling).

I came to this realization yesterday: the lack of DRV_MMC, however i did not place it in diskio.h. after doing so, mmc_disk_initialize () hangs. I placed a few printf statements in mmc_disk_initialize () and found that it hangs during the 80 dummy clocks.

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

quick update after playing around with it some more.  

 

I dug up an old version of ffexample from 2015 project attached below.  i corrected a couple of bugs in the mmc_avr.c file and have gotten SPI working.  When i run disk_initialize(0) i am successfully able to initialize the sd card, however, when i move onto f_mount() and f_open() specifically f_open() it hangs in the disk_initialize() function that is called out of find_volume() which is called from f_open().  

 

probing the SPI lines, MISO is still quite with 0 activity 

 

one weird thing that i noticed is the SD card still initializes even when its not inserted... 

 

this is what i fixed in mmc_avr.c 

 

#define	FCLK_SLOW() SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0);  //SPCR = 0x52		// Set slow clock (F_CPU / 128) 
#define	FCLK_FAST()	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);           //SPCR = 0x50		// Set fast clock (F_CPU / 2) 

 

any help would be appreciated.  

Attachment(s): 

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

Sorry i had classes getting in the way but i was able to figure it out.  Updated to the newest release, and a few minor typos in setting up SPI and some of the FFCONF settings.  Attached is a working project of the latest FATFS sample code for the ATEMGA 2560.  

Attachment(s): 

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

desai401 wrote:

Sorry i had classes getting in the way but i was able to figure it out.  Updated to the newest release, and a few minor typos in setting up SPI and some of the FFCONF settings.  Attached is a working project of the latest FATFS sample code for the ATEMGA 2560.  

 

Hi Thanks for your code.

 

I have modifed the code for Sam3x8E Ardunio and using SD card shield sourced from china

Read file test and rest works ok only the ERROR: FR_DISK_ERR occurs when i try to write file using f_write function (since if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR); line gets true) snippet of my code is as follows


    FATFS Ftfs;
	FILINFO finfo;
	FIL fil;        /* File object */
	FRESULT fr=FR_OK;     /* FatFs return code */
	FATFS *fs;
	char line[120];
    FSIZE_t offset;
    char Buff[4096];

    f_mount(&Ftfs, "", 1);

    printfGlobal("%s", "02 **** Write file test started ****\r\n");
    fr = f_stat("write.txt", &finfo);
    if(fr == FR_OK)
        {
            printfGlobal("write.txt file exists hence Deleting\r\n", fr);
            fr = f_unlink("write.txt");
            delay_ms(250);
        }

    fr = f_open(&fil, "write.txt", FA_WRITE | FA_CREATE_ALWAYS);
    if(fr != FR_OK)
        {error(fr); return;}

    offset = 0;
	printfGlobal("%s", "f_lseek started\r\n");
    fr = f_lseek(&fil, offset);
	if(fr != FR_OK)
		{error(fr); f_close(&fil); f_mount(NULL, "", 0); return;}

	memset(Buff, 0, sizeof(Buff));
	strcpy(Buff, "This data is written by SAM\r\n\0");
	printfGlobal("%s", "f_write started\r\n");
    fr = f_write(&fil, (const void*)Buff, strlen(Buff), &bw);
	if(fr != FR_OK)
		{error(fr); f_close(&fil); f_mount(NULL, "", 0); return;}

    f_sync(&fil);

    f_close(&fil);

 

 

Last Edited: Mon. Dec 25, 2017 - 03:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your code but it only works when the sdcard size is 4 mb. I simulated your project in proteus. When the sd card volume is 4 mb it works fine but when the volume is greater or less than 4 mb it initialises and mounts the sd card successfully but gets stuck in f_open(). I have attached the proteus file.

Attachment(s): 

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

desai401 wrote:

Sorry i had classes getting in the way but i was able to figure it out.  Updated to the newest release, and a few minor typos in setting up SPI and some of the FFCONF settings.  Attached is a working project of the latest FATFS sample code for the ATEMGA 2560.  

 

Thanks for your code but it only works when the sdcard size is 4 mb. I simulated your project in proteus. When the sd card volume is 4 mb it works fine but when the volume is greater or less than 4 mb it initialises and mounts the sd card successfully but gets stuck in f_open(). I have attached the proteus file

Attachment(s): 

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

There indeed seems to be something fishy with the zip file added by "desai401" like "usrrsr" I could not get this or the official FatFs sample to write to a file.

As I had other priorities I then stopped working on this.

 

But as you have Protheus you can tell us exactly what is going wrong as that is what these simulators are for.

So why have you not done any more indepth investigation into at what level the code actually stops working?

 

 

 

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

meslomp wrote:

There indeed seems to be something fishy with the zip file added by "desai401" like "usrrsr" I could not get this or the official FatFs sample to write to a file.

As I had other priorities I then stopped working on this.

 

But as you have Protheus you can tell us exactly what is going wrong as that is what these simulators are for.

So why have you not done any more indepth investigation into at what level the code actually stops working?

 

 

 

 

the simulation stops because there is no communication b/w card and controller, somewhat here

 

<<<while(!(SPSR & (1<<SPIF)));>>>

 

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

The SPI peripheral should be an autonomous working thing. regardless if you have anything attached or not.

 

I have noticed that for some reason the SPI peripheral gets turned off at a couple of places.

Can you see in the simulation if, at the point were you actually are now waiting forever, the SPI peripheral is actually turned on or not?

This might be a clue as to what is going on (perhaps even solve the problems)

 

IIRC SPI is fire and forget, put byte in SPDR register and it gets spit out+readback. But when the peripheral is not enabled/configured correctly you can put a byte in the SPDR register, but it will never be transmitted.......

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

of6569 wrote:
the simulation stops because there is no communication b/w card and controller, somewhat here while(!(SPSR & (1<<SPIF)));
Surely this is the classic AVR gotcha? SS pulled low (because it's not being driven) and MSTR switches to slave so when SPDR is written SPIF never occurs. Suggest you sort out your SS handling.

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

meslomp wrote:

The SPI peripheral should be an autonomous working thing. regardless if you have anything attached or not.

 

I have noticed that for some reason the SPI peripheral gets turned off at a couple of places.

Can you see in the simulation if, at the point were you actually are now waiting forever, the SPI peripheral is actually turned on or not?

This might be a clue as to what is going on (perhaps even solve the problems)

 

IIRC SPI is fire and forget, put byte in SPDR register and it gets spit out+readback. But when the peripheral is not enabled/configured correctly you can put a byte in the SPDR register, but it will never be transmitted.......

 

Yes u are right. SS is inactive while f_open operation. What is its remedy? What should i do?

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

Hi

I m able to simulate the proteus file and the code works perfectly fine but doesn't work in hardware. i have patched a uC with an Sd card module and using 8 gb micro sd card. But the code gets stuck in disk_initialize().

I think there are some issues in interrupts. 

 

OCR0A = F_CPU / 1024 / 100 - 1;

TCCR0A = _BV(WGM01);

TCCR0B = 0b101;

TIMSK0 = _BV(OCIE0A);

sei();

 

Can anybody help me with this? I tried to clear the interrupts by putting "cli();" but then the code doesnt work even in software. i am using 8 mhz internal clock.

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

You haven't said which model of AVR it is so no one here has any chance of knowing what this line:

TCCR0B = 0b101;

is doing. If you had written it like the other lines using _BV(bit_name) then, of course, it would have been self documenting.

 

As your register names have a 0 in them I'm going to take a wild guess that this is a mega328P. If so then:

#define TCCR0B _SFR_IO8(0x25)
#define CS00 0
#define CS01 1
#define CS02 2
#define WGM02 3
#define FOC0B 6
#define FOC0A 7

So the 101 is presumably just setting CS bits?

 

On the whole the timer code looks OK then. You are enabling it in CTC mode and the CS setting is /1024

 

Do you have a scope or analyser? Best way to diagnose SPI on rela hardware is to watch the signals on the wires.

 

Having said that the disk_initialize should not "lock up". The whole point of the timer interrupt is that it will operate timeout counters for the wait loops in disk_initialize.

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

clawson wrote:

You haven't said which model of AVR it is so no one here has any chance of knowing what this line:

TCCR0B = 0b101;

is doing. If you had written it like the other lines using _BV(bit_name) then, of course, it would have been self documenting.

 

As your register names have a 0 in them I'm going to take a wild guess that this is a mega328P. If so then:

#define TCCR0B _SFR_IO8(0x25)
#define CS00 0
#define CS01 1
#define CS02 2
#define WGM02 3
#define FOC0B 6
#define FOC0A 7

So the 101 is presumably just setting CS bits?

 

On the whole the timer code looks OK then. You are enabling it in CTC mode and the CS setting is /1024

 

Do you have a scope or analyser? Best way to diagnose SPI on rela hardware is to watch the signals on the wires.

 

Having said that the disk_initialize should not "lock up". The whole point of the timer interrupt is that it will operate timeout counters for the wait loops in disk_initialize.

 

I am using atmega644p with 8 mhz internal clock. This is my hardware

 

Attachment(s): 

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

Hi 

I am using fatfs for my sd card project. i have simulated the code in proteus, works fine. It works fine on the hardware as well. I am saying this because debug LEDs are working same just as in proteus. But sdcard doesnt show the file. Why?

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

Take a binary snapshot of the card before you use it with the AVR (dd in Linux is an easy way to do this - there is a version of dd for Windows too). Then take a snapshot afterwards. Then download/install vbindiff and/or WinHex by X-ways and look to see what has changed. Has an entry been added to the directory. Have clusters being allocated from the FAT. Are there added data sectors in the data region?

 

You might want to let a tool such as chkdsk/scandisk loose on the card too and see if it can identify what is wrong (something like "orphaned chains" perhaps?)

 

PS forgot to say that the binary snapshot does not need to be the WHOLE card (Gigabytes!) but just a few 10's or 100's of MBs as allocation generally happens from the "front" onwards. In fact as long as you get a little way into the data region you shod be fine. On some cards I've done this with only 3..4MB of data snapshotted.

Last Edited: Wed. Jun 13, 2018 - 12:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

Take a binary snapshot of the card before you use it with the AVR (dd in Linux is an easy way to do this - there is a version of dd for Windows too). Then take a snapshot afterwards. Then download/install vbindiff and/or WinHex by X-ways and look to see what has changed. Has an entry been added to the directory. Have clusters being allocated from the FAT. Are there added data sectors in the data region?

 

You might want to let a tool such as chkdsk/scandisk loose on the card too and see if it can identify what is wrong (something like "orphaned chains" perhaps?)

 

PS forgot to say that the binary snapshot does not need to be the WHOLE card (Gigabytes!) but just a few 10's or 100's of MBs as allocation generally happens from the "front" onwards. In fact as long as you get a little way into the data region you shod be fine. On some cards I've done this with only 3..4MB of data snapshotted.

 

I am sorry for my ignorance but i dont know this binary snapshot thing....and google was not much of help as well so i look up to you ;)

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

A file system on an SD/MMC card is just a sea of 512 byte sectors of information in a defined layout. What I am suggesting is that if the AVR appears to write a file but then it does not show up that you should try to determine what WAS written and which bit is "Missing" - this may give you a clue as to how the AVR code is failing. To do that you need to compare the "before" and "after" state of a card. So start by formatting one so it has a "clean" layout. Then get the AVR to make a write attempt. Before and after you do that you need to take the snapshots. In Linux this is easy, as standard it has a utility called dd that is very powerful. When an SD card is inserted into a Linux machine the card likely appears as /dev/sdX for the whole card and /dev/sdX0, /dev/sdX1, /dev/sdX2... for the partitions (might only be one in fact). So you do something like "dd if=/dev/sdf of=snapshot.bin bs=512 count=10000". That copies the first 10,000 sectors that are each 512 bytes from the card to a file called snapshot.bin. So now you have a copy of the data structure on the card. Do the same after the write attempt then do a binary difference operation between the two files to see what sectors were written. If you have an "intelligent" binary editor that knows what FAT12/16/32 formats look like it will be able to tell you the significance of the sectors that have been written. For that bit I switch to Windows and use the most excellent WinHex editor which is a FAT analysis tool.

 

If you only have Windows (shame!) then for the snapshot you need to locate something like dd. In fact you could probably use the aforementioned WinHex as it has options to open both "physical drive" and "logical drive". To take whole card images use "physical drive". There is also a version of "dd" for Windows but Microsoft have an extraordinarily weird way of naming drives for tools like that so you'd need to research that to find out how to access a "whole drive".

 

In both cases you may need n"admin privileges" to be able to do some of this kind of low level access stuff.

 

To be honest though, if you don't know how to use a tool like dd I'm guessing you don't know how FAT is structured either (MBR, BPB, FAT, DIR, data) so trying to diagnose this way may not be the best approach anyway.

 

Perhaps approach it from the highest level in the AVR code. Most of the f_*() functions return error codes. Have you checked these - are any of the calls you are making returning errors to say there was a problem?

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

h755288 wrote:
sdcard doesnt show the file

What, exactly, do you mean by that?

 

An SD Card doesn't "show" stuff by itself - so how are you observing this?

 

Did you properly close the file ... ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

"Win32 Disk Imager" is commonly suggested as a tool for reading & writing SD Card images under Windows

 

https://sourceforge.net/projects/win32diskimager/

 

Putting "Win32 Disk Imager" into google will also find you some YouTube videos on how to use it ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi forum.

After fooling around for 1 month I finally got FatFS to work.

Apart from having Logic Level translation problem, at least the generic simple code in "generic" sample folder worked for me.

P.S:I suggest You add in the code at the end f_mount(0, "", 0); /* Unmount drive */ unless you will get garbage scrambled files in the SD card while removing it destroying you the partition.

I am using an ATMEGA 328P and connecting as the picture suggest:

MISO to PINB0

MOSI to PINB1

SCK   to PINB2

CS.    to PINB3

It finally worked.

(Even if the SPI pin are different....)

As the library sdmm.c says it is not bit banging SPI but the fact is that I cannot change the pin assignment in the define part below:

the 4-SPI lines get tied to PB0-4

Apart from the fact that cannot understand #define CS_INIT() DDRB  |= 0x08 /* BIT 8?!?!

How is this possible?

Best regards and thanks

 

#define DO_INIT() /* Initialize port for MMC DO as input */

#define DO (PINB & 0x01) /* Test for MMC DO ('H':true, 'L':false) */

 

#define DI_INIT() DDRB  |= 0x02 /* Initialize port for MMC DI as output */

#define DI_H() PORTB |= 0x02 /* Set MMC DI "high" */

#define DI_L() PORTB &= 0xFD /* Set MMC DI "low" */

 

#define CK_INIT() DDRB  |= 0x04 /* Initialize port for MMC SCLK as output */

#define CK_H() PORTB |= 0x04 /* Set MMC SCLK "high" */

#define CK_L() PORTB &= 0xFB /* Set MMC SCLK "low" */

 

#define CS_INIT() DDRB  |= 0x08 /* Initialize port for MMC CS as output */

#define CS_H() PORTB |= 0x08 /* Set MMC CS "high" */

#define CS_L() PORTB &= 0xF7 /* Set MMC CS "low" */

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

Houseman74 wrote:
Apart from the fact that cannot understand #define CS_INIT() DDRB |= 0x08 /* BIT 8?!?!

How is this possible?

 

read again, what bit is this instruction toggling????

you might want to slap yourself after you found out...

as 0x08 is the 4th bit from the 8 available ( the 0xF7 inverse mask might have given it away)

 

coffee time ;)

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

Doh! What a moron!! TRAP for Young players!!

 

That's the result of 3hrs (0x03 or better 0b00000011) sleep every night for 1 month

Was thinking in decimal inside a byte... what a mess....

I will slap myself 0xFF, for sure.

THANKS MATE!

 

Last Edited: Fri. Oct 26, 2018 - 03:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

a, well you can not have it all.

been playing for a while with an if statement that I was making, then during the process decided I wanted to invert it as that was easier, so copied code from else to then and vice versa, got interrupted by a phonecall and some small thing to do. quickly read the things it had to do ran the program and spend an hour or so on finding out why the heck it would not do what I wanted it to do, only then to see the exclamation mark still in place......

Pages