[TUT][SOFT] SD/MMC with FAT from A to Z

Go To Last Post
24 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wrote this tutorial, and had it proof read. Here is the link. if you want a hard copy the page can easily be saved to disk with the "save page as" button, it's a very plain page.

http://basementcode.com/avr/sd_f...

There is space for comments there or here. I should get them either way.

If there is ANYTHING that isn't completely 100% clear please please let me know.

Thanks for any comments.

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

Thanks for posting this, good write up.
I have a problem that maybe someone here can answer:
I have the FAT FS system working in debug mode, but as soon as I program the uC it doesn't initialize in programmed mode. If its in programmed mode and i reset it by just turning on/off the JTAG (versus a hard unplug/ plug back in) it will begin working. Any ideas of what might cause this?

any help appreciated
-greg

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

Could you post some code? At least the parts up until it stops working. Also anything special you may have on the SPI port. I don't have any experience with JTAG, but maybe somebody or myself can spot the error just by looking. (the diskio.c file too)

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

gyang1127,

Check there's an appropriate pull-up resistor on the reset line.

Also, what type of system clock? If using an external crystal then try with fuses set for internal oscillator instead. It might be that the crystal isn't starting up unless the JTAG kicks it into life.

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

Just a question on the statement about native mode vs SPI mode.

If I remember correctly, SPI mode was removed from the SDHC standard, or it was at least made optional.

Can this be confirmed by anyone?

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

Thanks for pointing that out.
Wikipedia says it best.

Changes to the interface of the established SD format have made some older devices designed for standard cards (≤4GB) unable to handle newer formats such as SDHC (>4GB). All SD-cards have the same physical shape and form factor however, which causes confusion for some consumers (and avr freaks).

Hopefully fewer people will go buy a SDHC card and try to follow the tut.

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

With this system, can the SD card be removed, once data has been added to it, Then attached to a computer via a SD to USB converter so that data can be read from the card to a file on the computer?

I have an AVR stamp with an atmega128 as the microcontroller. I would like to use the 128 with a FAT system to store data on an SD card then read data from the card.

Thank you
Pat

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

Yup the library reads and writes files so a computer can read and write them automatically, just like a usb drive. Read the first paragraph of the page, that is all explained there.
Early on I had problems with data that wasn't written because I pulled the card before closing the file. Be sure you call the close function and unmount the disk to make sure everything was physically written, and not just added to a buffer. I still need to experiment more to see if the close and unmount are really necessary. Anybody know the answer to this?

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

sorry for late response, i just needed to disable SPI interrupts

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

Thelorax,
I don't believe its necessary to unmount the file, but you do need to f_sync, and or close the file before removing card

All,
Has anyone tested their data rates? My data rate is around 180KB/s for 100Meg file copy regardless of 2GB-8GB sd card.
I am using a 32Mhz System Clock (xmega128a1) with a 128 prescaler to make SPI run at 250Khz.
I've tried adjusting the SPI clock Prescaler so SPI was running at 1/4th System Clock and Double Speed (16Mhz), and this doesn't raise my data rate or cause crashes. Does anyone know if its possible and how to get higher data xfer rates?

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

Thanks for this tutorial, I finally managed to run fatfs on Atmega 32 :)

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

I am able to run FAT32 using my ATMega128 (running at 16MHz) as well! Thank you! My card socket is attached to PORTB only. PORTB also controls the +Vcc to the card.

I have tested this using a 4GB and 16GB SDHC cards, as well as a 2GB SD card. One peculiarity I did notice though, I could not delete the file from the card while it was plugged into my laptop running XP. If I wanted the file removed, I had to format the card. When I deleted the file, no error messages occured. It looked deleted, but if I refreshed the screen the file was back again.

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

Quote:

If I wanted the file removed, I had to format the card. When I deleted the file, no error messages occured. It looked deleted, but if I refreshed the screen the file was back again.

That sounds like it might be anti-virus or something trying to protect you from yourself? Or could it have been the card's write protect? (but why would format then work?)

If you have Winhex you could see if it'll let you write raw sectors - just try changing a directory entry to the E5'd state.

(Winhex needs to be licenced to allow writes to the media)

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

Clawson - the write protection is definitely disabled. I will give your Winhex suggestion a try and post my findings.

One other thing I noticed ... My ATMega128 circuit seems totally fine overwriting the file. I have verified this by making changes to the content (in source code) to be written to the data file on the card. Reading the data file in Windows again shows the changes did take place.

I haven't tried appending the file as of yet to see what happens but that will be next. I'm happy just the same to have come this far! ;-)

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

Here are two Winhex copies of the first 512 bytes of my memory card. There is only one file on this card. For some reason, I was able to delete this file with no problem. This is indicated at the top of the "after delete.jpg" file compared to the "before delete.jpg" file.

Attachment(s): 

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

And exactly what were you excepting to change in the boot/BPB sector for a file deletion?

I guess we could play one of those "spot the difference" competitions (using something like vbindiff on binary copies would be easier!) but my prediction is that the two pictures are identical.

The things that will have changed between a before and after file deletion are the root dir (file entries first byte changed to 0xE5) and the FAT chain for the file in FAT1 (and 2 if there's 2 of them) will have been returned to 0x00

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

LOL - and what was I thinking ... good point. Wrong screen dumps. I'll change the ones I posted after work today. (or just repost them as a reply).

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

Did you know that WinHex has various special forms of Edit-CopyBlock. My favourite one is "Editor Display":


==================================================================================
Offset       0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F

000000000   33 C0 8E D0 BC 00 7C 8E  C0 8E D8 BE 00 7C BF 00   3ÀŽÐ¼.|ŽÀŽØ¾.|¿.
000000010   06 B9 00 02 FC F3 A4 50  68 1C 06 CB FB B9 04 00   .¹..üó¤Ph..Ëû¹..
000000020   BD BE 07 80 7E 00 00 7C  0B 0F 85 10 01 83 C5 10   ½¾.€~..|..…..ƒÅ.
000000030   E2 F1 CD 18 88 56 00 55  C6 46 11 05 C6 46 10 00   âñÍ.ˆV.UÆF..ÆF..
000000040   B4 41 BB AA 55 CD 13 5D  72 0F 81 FB 55 AA 75 09   ´A»ªUÍ.]r..ûUªu.
000000050   F7 C1 01 00 74 03 FE 46  10 66 60 80 7E 10 00 74   ÷Á..t.þF.f`€~..t
000000060   26 66 68 00 00 00 00 66  FF 76 08 68 00 00 68 00   &fh....fÿv.h..h.
000000070   7C 68 01 00 68 10 00 B4  42 8A 56 00 8B F4 CD 13   |h..h..´BŠV.‹ôÍ.
000000080   9F 83 C4 10 9E EB 14 B8  01 02 BB 00 7C 8A 56 00   ŸƒÄ.žë.¸..».|ŠV.
000000090   8A 76 01 8A 4E 02 8A 6E  03 CD 13 66 61 73 1E FE   Šv.ŠN.Šn.Í.fas.þ
0000000A0   4E 11 0F 85 0C 00 80 7E  00 80 0F 84 8A 00 B2 80   N..…..€~.€.„Š.²€
0000000B0   EB 82 55 32 E4 8A 56 00  CD 13 5D EB 9C 81 3E FE   ë‚U2äŠV.Í.]ëœ.>þ
0000000C0   7D 55 AA 75 6E FF 76 00  E8 8A 00 0F 85 15 00 B0   }Uªunÿv.èŠ..…..°
0000000D0   D1 E6 64 E8 7F 00 B0 DF  E6 60 E8 78 00 B0 FF E6   Ñædè..°ßæ`èx.°ÿæ
0000000E0   64 E8 71 00 B8 00 BB CD  1A 66 23 C0 75 3B 66 81   dèq.¸.»Í.f#Àu;f.
0000000F0   FB 54 43 50 41 75 32 81  F9 02 01 72 2C 66 68 07   ûTCPAu2.ù..r,fh.
000000100   BB 00 00 66 68 00 02 00  00 66 68 08 00 00 00 66   »..fh....fh....f
000000110   53 66 53 66 55 66 68 00  00 00 00 66 68 00 7C 00   SfSfUfh....fh.|.
000000120   00 66 61 68 00 00 07 CD  1A 5A 32 F6 EA 00 7C 00   .fah...Í.Z2öê.|.
000000130   00 CD 18 A0 B7 07 EB 08  A0 B6 07 EB 03 A0 B5 07   .Í. ·.ë. ¶.ë. µ.
000000140   32 E4 05 00 07 8B F0 AC  3C 00 74 FC BB 07 00 B4   2ä...‹ð¬<.tü»..´
000000150   0E CD 10 EB F2 2B C9 E4  64 EB 00 24 02 E0 F8 24   .Í.ëò+Éädë.$.àø$
000000160   02 C3 49 6E 76 61 6C 69  64 20 70 61 72 74 69 74   .ÃInvalid partit
000000170   69 6F 6E 20 74 61 62 6C  65 00 45 72 72 6F 72 20   ion table.Error 
000000180   6C 6F 61 64 69 6E 67 20  6F 70 65 72 61 74 69 6E   loading operatin
000000190   67 20 73 79 73 74 65 6D  00 4D 69 73 73 69 6E 67   g system.Missing
0000001A0   20 6F 70 65 72 61 74 69  6E 67 20 73 79 73 74 65    operating syste
0000001B0   6D 00 00 00 00 62 7A 99  E3 75 69 0D 00 00 00 20   m....bz™ãui.... 
0000001C0   21 00 27 FE FF FF 00 08  00 00 00 00 60 01 80 FE   !.'þÿÿ......`.€þ
0000001D0   FF FF 07 FE FF FF 00 08  60 01 00 68 01 12 00 FE   ÿÿ.þÿÿ..`..h...þ
0000001E0   FF FF 07 FE FF FF 00 70  61 13 00 00 70 11 00 FE   ÿÿ.þÿÿ.pa...p..þ
0000001F0   FF FF 12 FE FF FF 00 70  D1 24 00 70 71 00 55 AA   ÿÿ.þÿÿ.pÑ$.pq.Uª


(that's the MBR from my laptop's main NTFS drive). Using this mode it's easy to use "diff" tools to compare before/after copies - far easier than comparing pictures.

Another copy-block option is:

unsigned char data[512] = {
	0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0x8E, 0xC0, 0x8E, 0xD8, 0xBE, 0x00, 0x7C, 0xBF, 0x00, 
	0x06, 0xB9, 0x00, 0x02, 0xFC, 0xF3, 0xA4, 0x50, 0x68, 0x1C, 0x06, 0xCB, 0xFB, 0xB9, 0x04, 0x00, 
	0xBD, 0xBE, 0x07, 0x80, 0x7E, 0x00, 0x00, 0x7C, 0x0B, 0x0F, 0x85, 0x10, 0x01, 0x83, 0xC5, 0x10, 
	0xE2, 0xF1, 0xCD, 0x18, 0x88, 0x56, 0x00, 0x55, 0xC6, 0x46, 0x11, 0x05, 0xC6, 0x46, 0x10, 0x00, 
	0xB4, 0x41, 0xBB, 0xAA, 0x55, 0xCD, 0x13, 0x5D, 0x72, 0x0F, 0x81, 0xFB, 0x55, 0xAA, 0x75, 0x09, 
	0xF7, 0xC1, 0x01, 0x00, 0x74, 0x03, 0xFE, 0x46, 0x10, 0x66, 0x60, 0x80, 0x7E, 0x10, 0x00, 0x74, 
	0x26, 0x66, 0x68, 0x00, 0x00, 0x00, 0x00, 0x66, 0xFF, 0x76, 0x08, 0x68, 0x00, 0x00, 0x68, 0x00, 
	0x7C, 0x68, 0x01, 0x00, 0x68, 0x10, 0x00, 0xB4, 0x42, 0x8A, 0x56, 0x00, 0x8B, 0xF4, 0xCD, 0x13, 
	0x9F, 0x83, 0xC4, 0x10, 0x9E, 0xEB, 0x14, 0xB8, 0x01, 0x02, 0xBB, 0x00, 0x7C, 0x8A, 0x56, 0x00, 
	0x8A, 0x76, 0x01, 0x8A, 0x4E, 0x02, 0x8A, 0x6E, 0x03, 0xCD, 0x13, 0x66, 0x61, 0x73, 0x1E, 0xFE, 
	0x4E, 0x11, 0x0F, 0x85, 0x0C, 0x00, 0x80, 0x7E, 0x00, 0x80, 0x0F, 0x84, 0x8A, 0x00, 0xB2, 0x80, 
	0xEB, 0x82, 0x55, 0x32, 0xE4, 0x8A, 0x56, 0x00, 0xCD, 0x13, 0x5D, 0xEB, 0x9C, 0x81, 0x3E, 0xFE, 
	0x7D, 0x55, 0xAA, 0x75, 0x6E, 0xFF, 0x76, 0x00, 0xE8, 0x8A, 0x00, 0x0F, 0x85, 0x15, 0x00, 0xB0, 
	0xD1, 0xE6, 0x64, 0xE8, 0x7F, 0x00, 0xB0, 0xDF, 0xE6, 0x60, 0xE8, 0x78, 0x00, 0xB0, 0xFF, 0xE6, 
	0x64, 0xE8, 0x71, 0x00, 0xB8, 0x00, 0xBB, 0xCD, 0x1A, 0x66, 0x23, 0xC0, 0x75, 0x3B, 0x66, 0x81, 
	0xFB, 0x54, 0x43, 0x50, 0x41, 0x75, 0x32, 0x81, 0xF9, 0x02, 0x01, 0x72, 0x2C, 0x66, 0x68, 0x07, 
	0xBB, 0x00, 0x00, 0x66, 0x68, 0x00, 0x02, 0x00, 0x00, 0x66, 0x68, 0x08, 0x00, 0x00, 0x00, 0x66, 
	0x53, 0x66, 0x53, 0x66, 0x55, 0x66, 0x68, 0x00, 0x00, 0x00, 0x00, 0x66, 0x68, 0x00, 0x7C, 0x00, 
	0x00, 0x66, 0x61, 0x68, 0x00, 0x00, 0x07, 0xCD, 0x1A, 0x5A, 0x32, 0xF6, 0xEA, 0x00, 0x7C, 0x00, 
	0x00, 0xCD, 0x18, 0xA0, 0xB7, 0x07, 0xEB, 0x08, 0xA0, 0xB6, 0x07, 0xEB, 0x03, 0xA0, 0xB5, 0x07, 
	0x32, 0xE4, 0x05, 0x00, 0x07, 0x8B, 0xF0, 0xAC, 0x3C, 0x00, 0x74, 0xFC, 0xBB, 0x07, 0x00, 0xB4, 
	0x0E, 0xCD, 0x10, 0xEB, 0xF2, 0x2B, 0xC9, 0xE4, 0x64, 0xEB, 0x00, 0x24, 0x02, 0xE0, 0xF8, 0x24, 
	0x02, 0xC3, 0x49, 0x6E, 0x76, 0x61, 0x6C, 0x69, 0x64, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 
	0x69, 0x6F, 0x6E, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x00, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x20, 
	0x6C, 0x6F, 0x61, 0x64, 0x69, 0x6E, 0x67, 0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6E, 
	0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x00, 0x4D, 0x69, 0x73, 0x73, 0x69, 0x6E, 0x67, 
	0x20, 0x6F, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 
	0x6D, 0x00, 0x00, 0x00, 0x00, 0x62, 0x7A, 0x99, 0xE3, 0x75, 0x69, 0x0D, 0x00, 0x00, 0x00, 0x20, 
	0x21, 0x00, 0x27, 0xFE, 0xFF, 0xFF, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0x80, 0xFE, 
	0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x00, 0x08, 0x60, 0x01, 0x00, 0x68, 0x01, 0x12, 0x00, 0xFE, 
	0xFF, 0xFF, 0x07, 0xFE, 0xFF, 0xFF, 0x00, 0x70, 0x61, 0x13, 0x00, 0x00, 0x70, 0x11, 0x00, 0xFE, 
	0xFF, 0xFF, 0x12, 0xFE, 0xFF, 0xFF, 0x00, 0x70, 0xD1, 0x24, 0x00, 0x70, 0x71, 0x00, 0x55, 0xAA
};

Last Edited: Tue. Mar 9, 2010 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I didn't know that. Thanks for the tip.

Also, posting your information as code is wonderful. It sure beats comparing JPGs for sure! :-)

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

I'm working on porting fatfs to the EVK1100 board (AVR32 UC3A0512) and I'm having trouble deciphering some compile errors and how to clean them up. Most of them are like this:

../../SERVICES/FATFS/diskio.c: In function 'rcvr_spi':
../../SERVICES/FATFS/diskio.c:76: error: 'SPDR' undeclared (first use in this fu
nction)
../../SERVICES/FATFS/diskio.c:76: error: (Each undeclared identifier is reported
 only once
../../SERVICES/FATFS/diskio.c:76: error: for each function it appears in.)
../../SERVICES/FATFS/diskio.c:77: warning: implicit declaration of function 'loo
p_until_bit_is_set'
../../SERVICES/FATFS/diskio.c:77: error: 'SPSR' undeclared (first use in this fu
nction)
../../SERVICES/FATFS/diskio.c:77: error: 'SPIF' undeclared (first use in this fu
nction)
../../SERVICES/FATFS/diskio.c:79: warning: control reaches end of non-void funct
ion

I'm guessing that this has something to do with implementing the proper SPI code for the EVK1100 board in the rcvr_spi() function. Is this the case? Would I just need to include spi.h and sd_mmc_spi.h in the diskio.c file and then use the appropriate SPI functions to port this code?

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

You need to completely replace diskio.c as those registers named in your errors are the AVR8's names for the SPI control and data registers and control bits.

BTW this is an AVR8 forum so your post is slightly off-topic here. I cannot help thinking that other AVR32 users must already have used FatFs so you might want to search the AVR32 fora for mentions of FatFs

EDIT: there are 5 such threads - a couple of them look very interesting.

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

Ah thanks for the heads up... I didn't see a tutorial sub-forum in the AVR32 forums so I just assumed that this one was a conglomeration. Thanks!

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

Thanks for a great tutorial. Between this one and kubark42's most of the heavy lifting is done for us. I'm implementing the FAT file system on the ATMEGA644P and things are going fairly well so far. I do have a couple of questions, though. In the function descriptions (online, sfileinfo.html), the disk_initialize() function has the statement "Application program should not call this function, or FAT structure on the volume can be collapsed. To re-initialize the file system, use f_mount function." This implies that you should just do an f_mount() to initialize. However looking through the f_mount() code it appears that disk_initialize is never referenced, and casual experimentation indicates that calling disk_initialize() after f_mount() has no obvious ill effect. Anybody have any experience pro or con?
Also, I plan to open and append to existing files, and I assume the best way to find the end of the file is to do an f_stat() call and use FILINFO.fsize value in an f_lseek() command. Anybody used this, or found a better way? If memory serves, DOS had an f_seek(END) type call to go right to the end.
Finally, I'd like to mention some problems with power control- I'm using a FET switch under program control since my application is battery powered. The switch works fine but the 'switched' side (power pin of the card) stays high when the switch is off, I believe because of backfeed through the SPI pins. I can't really pull these pins low when the card is off because I need to talk to the RTC and other SPI devices while running. Has this issue been encountered and addressed by anyone? I guess I could put switches on the SPI lines to the card but that seems a bit excessive in terms of cost & real estate. It may be a non-issue since I don't think the card is really consuming any significant power while the switch is off, but on the other hand the power pin IS at 3.3V.
I apologize for the long post, and thanks again for a super tutorial.
Thanks,
Harry

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

disk_initialize() will get called as apropriate when you do somthing that realy needs to access the card you do not need to do it yourself. FILINFO.fsize will get filled in when you do f_open so no need for the f_stat just f_open then f_lseek.

Not sure about the power side of things but it may well be card dependent. With my system mostly used for loging so mainly writing so long as I finish up by closeing my files the card looks to go low power. Straight after a read the card I am using can be using an anoying amount of power.