Saturday, January 31, 2009

SD/SDHC Card Interfacing with ATmega8 /32 (FAT32 implementation)

Hi friends,
Here is my project on interfacing of SD Card (microSD). microSD cards are available very cheap nowadays, a great option for having a huge memory in any embedded system project. It is compatible with SPI bus, so the interfacing is easy. SD card adapters are also easily available in market, one can easily make a bread-board adapter by soldering few pins on it. Following figures show the SD card pin-out & the bread-board adapter design by soldering 7-pins of a breakout header on the microSD adapter (Click on images for larger view).

I had started this project with 1GB microSD card from SanDisk (later on tested with transcend cards also). The microcontroller is AVR ATmega8 or ATmega32 running at 8Mhz internal clock. MAX232 is used to interface the circuit with PC for monitoring the data. A 3.3v supply is used for powering the mega8, microSD and max232 (though the specified supply for max232 is 5v, it works comfortably at 3.3v).7 pins of the microSD are used here, shown in the figure of pin-out.

Schematic for ATmega8 is shown here (updated on 10 May 2010, SD series resistors are removed, as they were limiting the speed of SPI bus. 51k pullups are added on CMD/DAT lines. This gives better stability with different cards. Also, two 3.6v zeners are added to protect SD in case when the ISP programmer voltage levels are of 5v. these diodes are not required if your programmer has settings for 3.3v output)(Note: VCC & GND pins of MAX232 are not shown in the schematic, but they must be connected in the actual hardware)
Following is the schematic for ATmega32, without RTC (updated on 10 May 2010):

Following is the schematic for ATmega32, with RTC (added on 17 May 2010; CS pin correction, PB4 instead of PB1, done in Mar 2014). Here two supply voltages are used, 3.3v for SD & 5v for remaining ICs.

The aim of this project was to learn interfacing of SD card and to understand the data transfer in raw format as well as in FAT32 format. I started with raw data transfer, sending some data to any block of the microSD, reading a block of it, reading and writing multiple blocks, erasing multiple blocks. All this in raw format. I used RS232 for viewing the data read by microcontroller from SD card. The uc sends the data to HyperTerminal. Similarly, to write data to card, the data was fed thru HyperTerminal, by typing some text.

Once raw data transfer achieved, I formatted the card with windowsXP (FAT32) and loaded it with some text files, directories and other files (all stored in root directory of the card). After that I wrote the FAT32 routines to read files, get file list (using HyperTerminal again), finding the total/free memory of card. All this data is sent to HyperTerminal by the uc.

Following is the HyperTerminal window showing different options:
Options 0 to 4 are low level functions dealing with raw data. If you use option 0, 1 or 3, you may have to reformat the card before using the FAT32 routines.
0: Erases selected number of blocks strating from selected block
1: Writes data to specified SD block address. Data to be entered in HyperTerminal using PC keyboard
2: Readss data of specified SD block address. Data is displayed on HyperTerminal window
3. Writes selected number of blocks strating from selected block
4. Reads selected number of blocks strating from selected block

Here, the multiple-block functions related to options 3 & 4 are disabled due to memory constraint as that time mega8 was used for testing and these functions are not required for FAT32 testing. While testing with mega32, options 3 & 4 can be enabled by removing a macro (#define FAT_TESTING_ONLY) defined in SD_routines.h.

Options 5 to 9 are related to FAT32 . Only short file names are supported right now, 8byte name+3bytes extension. If you store a long name file in SD, it will be displayed by these routines in short name format only.
For testing these options, format the card with FAT32 file system and store some directories and text files (because text files can be read & checked thru HyperTerminal).

5: Displays list of available directories and files with size (in the root directory of the card)
6: Reads a specified file and displays the file contents on HyperTerminal
7: Create/Append file with specified name, enter text from HyperTerminal
8: Deletes any existing file with specified name
9: Displays total & free memory of the card (using FSinfo sector of the SD card)

Following figures show the HyperTerminal window when options 5 & 9 are selected:(These figures show menu from Ver2.3 or earlier. Menu style is changed from Ver_2.4 onwards, which is shown in the update history)

Note: HyperTerminal is used here at 19200 baudrate, No parity, Flow Control 'none'.

This project needs very few components and can be done easily at home. Try it out!

Download the source code files from here:Download here the zipped source code files modified for mega32, written in winAVR-AVRStudio.

Related posts:
You can visit my post of microSD ATmega32 Data-Logger, which uses modified FAT32 library for automatically creating files without using hyper terminal.
If you want to test FAT32 functions or learn more without making the microcontroller hardware, you can visit my post here: microSD-FAT32 using Visual C++)

Update History-----------------------------------------------------------------------------Version 2.4:
- Real Time Clock circuit support is added for time & date entries in the files. Now the current date of file creation and file update will be entered in the FAT table (can be viewed by checking file 'properties' using a PC)
(The RTC will also be useful in data-logging with time-stamp)
- Three more options added in the Hyper Terminal menu for displaying or updating RTC date & time. New menu is shown in the above figure.

Ver 2.4.1:
- Same as 2.4, with a bug fix for RTC: 'twi_init' function added to define I2C clock freq. 100K@ 16MHz (50k@8MHz). This was taking default values earlier, which was as high as 500K@8MHz, not desirable

(Note: Version 2.2, 2.3 & 2.4 are tested on ATmega32, but they can be adopted to any controller having RAM >= 1KB and Flash >= 16KB)Current memory usage (Ver_2.4): Flash: 12908 Bytes; RAM: 700 Bytes (appx.);

Version 2.3:
- Support for SDHC cards added (tested with SanDisk & Transcend microSD and microSDHC cards). The initialization sequence and command formats are modified.
- A bug which was causing the program flow to go into infinite loop if the character number 512 in a sector was a CR (Carriage Return, '\r'), in the writeFile function. Thanks to David & Piotr M. who pointed it out in the comments.
- Code is also tested successfully at 16MHz clock (8MHz SPI clock) with for SD/SDHC cards.

Follwing are the Hyper Terminal windows showing card detection (One window shows baudrate as 38400, that was while testing for higher clock speeds, current code still uses 19200 baud and 8MHz internal clock of Mega32).

Version 2.2:
- Append file feature added. 'createFile' function replaced with writeFile, which looks for the filename first, if the given file name doesn't exist then it creates new file and writes data, but if the file already exists, then it opens it and appends the entered data.
- A bug removed which was giving error related to use of 'LONG'
- The FAT32.c & .h files are updated on 13 Sep 09to remove a bug which was limiting file size to 32MB (Thanks to Kun-Szabo Marton who pointed it out)

Data transfer rate: 1 raw data block (512 bytes) takes 4.15ms for reading or writing (123.37 KBytes/s) at current 4 MHz SPI clock rate. If you have flash more than 8k, you can declare the SPI_receive() and SPI_transmit() functions as 'inline' functions. This will increase the transfer rate to 140 KBytes/s. These transfer rates can be further increased by using a 16MHz crystal (8 MHz SPI clock). FAT32 file reading is done at 78 to 91 KBytes/sec.

Version 2.1:
- A bug removed which stopped creating new files after 32*8 files in the root directory
- The root directory was unnecessarily getting expanded by one cluster whenever a file was created. Fixed in the new version
- Also, the fixed cluster size of 8 sectors is removed, this version will support other cluster sizes as well

Version 2.0:
- Support added for SD cards having first sector as MBR rather than the boot sector
- createFile and deleteFile functions added
- A bug fixed in reading files stord at far locations in memory also correction made to accept 8+3 char file name (by mistake, it was taking 7+3 earlier)
- FSinfo sector used for storing total free cluster count &
next free cluster number for faster file access
- Instant freeMemory display (earlier it was taking more than 30secs) using FSinfo sector. FSinfo sector is updated now whenever a file is created or deleted
- File memory size display in decimal, like windows (earlier it was in hex)
- Raw SD functions multiple block read and write, which are not required for FAT32, are disabled using FAT32_TESTING_ONLY macro for getting extra space required by createFile & deleteFile changes (you can activate it if you have more than 8k flash) Right now flash is 99.9% full
- Clock speed raised from 1Mhz to 8 MHz, new SPI speed (after SD initialization): 4MHz instead of 500K & baudrate: 19200 (for HyperTerminal) instead of 4800
-------------------------------------------------------------------------------References:1. Microsoft's FAT32 specification document2. SD-Simplified Physical Layer Specifications4. F. Foust's Application Note on SD5. FAT32 Structure info, includes MBR details6. Simple FAT32 Structure explanation7. Chan's FAT library8. SD Association's Website for further info

extremely grateful to you for this project .....i was hunting like anything for something like this....just tell me one thing ...would it be wrong to use max232 at 5v.Max232 gives a 5v TTL output does it not affect ATmega8L when you are operating the microcontroller at 3.3v.PLEASE DONT MIND IF MY QUESTION IS TOO SILLY.I AM ONLY A BEGINNER.

Could you please tell name me any such diode......i need it badly.Would you mind giving me your mobile number at subhajitroy86@gmail.com.My purpose is totally academic.I am a B-Tech 3rd yr student from west Bengal.THANKS FOR YOUR REPLY

great job.. thanks a lot.. i am going to do exactly as u have done for one of my projects.. Between I2c and SPI what do u think is better, i was looking for a comparison between them. If you have any projects on I2c please let me know.. i also need to learn I2C for another project

your circuit diagrams looks so good a well made like in books - what software do u use to draw them.. i can draw them in Multisim or Altuim designer which i use for simulation or pcb designing but they dont look as cool as yours, i need well drawn professionals looking circuit diagrams for writing papers/presentations..

Hi Subrat,thanks for the comment.Selection between i2c & SPI depends on your application. If you need a simpler interface with speeds below 400k, go for i2c, it consumes only 2 pins of microcontroller and you can have many devices connected on the same 2-wire bus.SPI will be the choice if you are looking for high speed bus. Devices with 50MHz SPI are available. It takes 3 pins of controller plus a chip select pin for each device connected on the bus.For i2c code, you can check out my project:http://www.dharmanitech.com/2008/08/interfacing-rtc-serial-eeprom-using-i2c.html

For drawing schematics, I use EAGLE, it's pretty good and simple to use.

Hi Claudio,the microSD has to be operated at 3.3v only. For connecting microSD to a 5v controller, you can put voltage divider resistors on 3 pins: MOSI, SCK & Chip Select, to reduce the voltage applied to SD card pins from 5v to 3.3v. Also, it's better to use a separate 3.3v regulator for the Vcc of microSD.

Apart from feeding the vcc of the sd card with 3.3v, do all the rest 4 lines coming from the atmega8 and going to the sd card need to be sending pulses max of 3.3v?? can they be 5v?? voltage dividers as u suggested are not accurate , so what the max and min range of the voltage that needs to be send to the sd card.. i hope it doesn't have to be exact 3.3 v..

Moreover, as u said the manufacture r suggests pull up resistors on the pins of the SD card? do they say its needed for all the 4 lines on it.. i hope these need to be pulled up to 3.3v.. u havent used them but things change when the circuit is moved from bread board to real PCB.. i have experienced that quite many times , on boards i dint need pull up/down resistors but on pcb they dont work and i had to put them in.. so i was curious did to try this on a pcb?? if not i wd prefer to be safe and put those pull ups..

i also have another query.. since the same lines are being used for the isp as well as for the sd card, when i program the micro controller with an isp , do i need to remove the sd card? or they can both co-exist at same time.. after programming and the sd card is in there, do i need to remove the connections to the isp programmer for safe working??

i have noticed that once the programming is done, the micro controller starts working even if the isp programmer remains hooked up in there..but in this case the sd card was in there on the same lines so i thought better check with u..

i recently lost my expensive AVR jtag programmer now i dont want to buy another so i was wondering can i make my own usb to isp or may be serial to isp programmer..i found some circuit diagrams from the internet for serial to isp AVR programmer but wanted to check with u before i try any of them bcose some have mx232 and some dont, i thought max232 is compulsory for this job.. but i really want to make a usb to isp bcose i dont have serial port on my laptop and have to use a usb to serial adaptor which has a max232 then i have to put another max 232 on my serial to isp programmer, so i was thinking of making a usb to isp.. i know there are ftdi chips that can convert usb to serial at 5v and then if i cd implement a commonly used serial to isp programmer circuit, it shud do my job.. Please comment...

the links of programmers that i cd findhttp://lea.hamradio.si/~s56wix/avrprog/http://elm-chan.org/works/avrx/avrx_com.png

Hi Subrat,I've not made PCB of my design, but two of the visitors of this blog have made it and tested (they sent me the pics), it works perfect even without any pull-ups on the SD lines on the PCB.

The 3.3v level on the three comm lines is not so strict, as per my experience, you can feed 3v to 3.7v without any problem (note: MY EXPERIENCE!!!) so, you don't need very accurate voltage dividers

If your AVR programmer voltage is 5v, then it would be better to use 3.3v zener diodes on MISO & SCK lines to protect the card from 5v applied to it. (again, my experience says you can keep the card in position while programming the micro, it doesn't get affected!!)

The link on I2C which I've provided earlier works very well, I just tested! (if any problem, become member of avrfreaks.net, it's not harmful, OR mail me asking to send the code files to your mail ID)

Hi Ziyauddin,the retry variable is declared to count how many tries you have to do before the card responds. if retry limit is 0xfe, then the controller will resend a message to card maximum of 255 times. If working properly, card will respond much before the number 255 is reached. If card does not respond within 255 tries, the controller will display an error message.

hey...can u please tell me which zener diode i should use to connect atmega32 to Micro SD card. Is there any power constraint for tht? please reply ASAP..if u can then gimme ur mail id on:kgzone2001@yahoo.co.in

There you'll find some of the options for making a programmer yourself. You can use any programmer for the SD card project, only the ISP connector may change depending on the ISP unit. If the ISP programmer's voltage level is 5v, care should be taken that the voltage level on the SPI bus is around 3.3v while programming the controller.

Don't worry about the power consumption of mega32, it can very well drive the SPI bus, it's designed for it!!

I had suggested the use of zener diodes in case when your AVR programmer doesn't sense the voltage level of the circuit and always outputs signals of the level of 5v. This can be damaging to the controller & the SD card both.

What is real transfer rate for writing and reading a 1MB file for example, using the FAT32 and haw many megahertz has the controller while doing this test. I want you to do a test to determine artificial transfer rate without internal serial unit intervention.I made a library of FAT32 in asm and the details are here:http://digitalelectronicsandprograming.blogspot.com/2009/02/fat32-complete-library-in-asm-linguage.html

Hi Morgoth,the data transfer rate which I've mentioned in my post is measured during raw data transfer. As you know, the actual transfer rate while transferring files will differ as it involves going thru the cluster chain stored in the FAT table. Here in my code, I'm using a single 512 byte buffer for accessing data as well as reading the FAT table, hence, the buffer allocation is done back and forth, which will result into lower transfer rates compared to the systems having an extra buffer (more RAM).Anyways, good suggestion, I'll measure the transfer rate for 1MB file, after blocking the UART routines, to get the actual file transfer rate.

To khushal:Hi man, the zeners are required actually for mega32L, not for mega32, since you'll operate the mega32 at 5v anyways. The problem comes when you are operating the controller at 3.3v AND if your AVR programmer signals are of 5v level. You better use zeners there.(If you operate controller at 5v, then anyways you'll be using the voltage divider resistors with SD card, which will make sure that 5v coming from controller or the programmer gets converted to 3.3v before it goes to SD, so no need of zeners there).

dear sir,how to write the block of data in MMC card,i define block size is 32bytes and i make a function that pass 1 byte only .i want to write my 32 bytes data which is stored in char array.so how to write this data in MMC card.

Hi Ziyauddin,the initialization sequence for MMC card is little different then SD cards. I've not tested my code for MMC.

In case of the readSingleBlock & writeSingleBlock functions, the 'start block' specifies the block-number of a data block which you want to read or write. For readMultipleBlocks or writeMultipleBlocks or eraseBlocks, the 'start block' specifies the block-number from which the multiple-block read/write or erase will be started.

Pefect work, thank you. But I don't be able to run the project without a litle changes. This is about SS line. It is PB2 for ATmega8 MC. Is this mistake? So makro definition SD_CS_DEASSERT (SD_CS_ASSERT) will be another: PORTB |= 0x04.P.S. Sorry for broken english

I had some problems with the Makefile, and I think it's because I'm using Cygwin in WINDOZE, but...

I changed the makefile to replace the four spaces in front of some of the lines to tabs. Apparently, tab is some sort of instruction as a prefix in the makefile. Also, I changed ../meh.c to meh.c on all of the source files. Everything is in the same directory for me.

Hi Dharmani,Hats off to you man. After seeing your blog I started to do some embedded project as a hobby. I am new to this AVR core. I am using Atmega32 with winavr GCC compiler. My problem is, controller not detecting the external 8MHZ crystal, instead it is running with internal 1 MHZ oscillator. what is the command for the fuse setting in winavr Or else is some other way for Fuse setting? If so please let me know.

Sir, I download the source code. I am new to Win Avr. After unzipping the rar u gave, there are C files another default folder with .elf files , Make file and def folder. I cpied all this files to the main folder. I didn change anything in Make file. But it is showing error"make.exe: *** No rule to make target `../FAT32.c', needed by `FAT32.o'. Stop. "

To Tarun:Yes, it'll run on atmega16 also. Just keep the connections same and change the controller in your project configuration settings (if you are using AVRstudio) orin the makefile (if you are using winAVR separately).

To Saran: you have to change the fuse low byte. For using external crystal, you can make the CKSEL3 to CKSEL0 bits 1111. For using internal 8 MHz oscillator, you can set those bits to 0100. How to write fuse to the controller depends on which programmer you are using. Check out your programming software for setting fuse bytes. Also, refer to the AVR datasheet. 'memory programming' section where the details of the fuse bits are given

to 'anonymous': For using the folder which you've downloaded, you've to install the AVRStudio. The winAVR will run inside AVRStudio. In the AVRStudio, click on 'open project' and select the project from the unzipped folder, named 'SD_Card.aps'.Once you open the project, all the files will automatically appear in the project file list. Then you can compile it without any error.

Hi Dharmani,I am using winavr GCC compiler, it is having AVRdude version5.5 & gcc version 3.3.3I don't know what command i have to give in the command prompt for the Fuse bit setting. Can u help me reg.., this.

I made the circuit as shown in your schematic. Only changes were that i used Atmeg 16 and that i didnt connect an ISP connector(I couldnt find one).

But as soon as i give power, the interrupt LED glows and the hyper terminal shows nothing(except for some abstract text). Please Help ASAP!!! I am making the project for my final semester and the date is near...

I am Tarun's friend and working on the same project with him.Cant there be any other reason to the above problem stated by Tarun. Because we have checked the circuit, and the connections are correct. Hyper Terminal is running at 19200 baud.Also the controller is running at 8 Mhz.

Hi Rajiv,as tarun said that the LED glows, that means the program has started. And also he mentioned some garbage coming on Hyper Terminal, that can happen when there is mismatch of the bauds. Check again that in the hyper terminal settings, the flow control is selected as 'none'.

Try this also, set the hyper terminal at 4800 to check whether the controller is running at 1 MHz. (keep the 'flow control' always 'none')

If still problem, mail me the project folder, I'll have a look!ccd@dharmanitech.com

Hello once agian,i would also want to clarify from you that in AVRStudio we have chosen the debug platform as "AVR Simulator", device "ATmega16".Is it correct or we need to choose other debug platform?

I am preety impressed with work done by you.I want to interface SD card to P89v51RD2.how complex it is acheive this interface??later i wont to store some images on it ,and it might be required to display those stored images on the colour LCD.so can i carry on my work with the RD2, or i have to go with another controllers like arm7 ?Please help me ............

To Milind:Hi, the controller you've selected is not having the SPI bus hardware inbuilt. So, if you want to use it for this project, you'll need have a software SPI library, may be using the UART. There are some examples on net on how to implement the SPI using UART. Try google, you'll get it.Other alternative is to use SD card in non-SPI mode (standard SD mode). Got thru the SD manual for more info (I've put up a link for downloading the manual in my post)

Or, a better solution would be to use a microcontroller with SPI bus hardware inbuilt, like the one I've used, AVR controller.

Hi, i tried using your code. Works well for file sizes less than 4KB. but after that it repeats what it has read in the first 4KB. Doesn't seems to read beyond that. It keeps repeating until it exceeds the file size.

Hi Dharmani,Thanks for the Fuse setting command. It is working well. I am having 2GB SD card. Is it advisable to have this card to work out ??

And I have one more query, assume that I am having one mp3 files in the SD card. Is it possible to run those files. I am not stressing by means of ATmega. Suggest me proper controller for this kind of application. Does any RTOS is necessary for this ??Need H/w & S/w support

To Ash:That means the controller is reading only the first cluster of the file (assuming usual 512 bytes/sector & 8 sectors/cluster). Have you made any changes in the code, in the FAT32.c?

To Saran:There are lot of examples on net of designing an mp3 player using a microcontroller. Search in the project section of www.avrfreaks.net, you'll find such designs using avr controllers.

to Miling:Sorry man, my mistake, the controller you specified does have the SPI bus. You can use the code given here with very few modifications.The code takes 8k FLASH, including FAT32. The size can be reduced if you remove the UART message strings. And if you just want to dump data into SD without FAT format, the code can be made less than 2k. RAM usage is around 600-700 bytes.

Finally i managed to compile the code without any error in keil compiler for P89v51RD2.I have made some changes in the code.i have made buffer[512] as xdata.will it matter??????right now my Program Size is: data=23.2 xdata=768 code=14189also right now i am tryin to build the circuit for the same.i have a CKT made with controller running at 11.0592MHZ at 5V and max232 for serial comm.how do i set the speed of spi to 4mhz??i have made it as #define SPI_HIGH_SPEED SPCR = 0x50; SPSR = 0x00;is it ok???do i require a 3.3V zener for all the 4 pins of spi??

Hi Milind, you are using a different controller, and the macro that I've used is for AVR controller only. I've not used the one you've mentioned. Refer to datasheet of the microcontroller to check out how to set the SPI clock speed. Also your compiler documentation for details on xdata definition.

If you ISP programmer and SD card are connected on the same lines, you may need zener to limit the 5v of programmer to 3.3v (refer to some of the earlier comments on this post)

ya you are correct.i tried with same code.the response for CMD0 is 0x00.but for cmd1 i m gettin 0x05 or 0x55.which i feel is illegal command.i haven't changed the code logic i am just tryin to view the response at the hyperterminal.quite frustrating but for so long i am looking for 0x00 but gettin 0x05 .(i tried with both transend sd 1gb and sandisk SD 2gb)please help??????

Hi milind, I had missed the SPI clock speed in your previous comment. It's 11.592M/16 as you mentioned, which makes it go beyond 400K. Usually, SD cards need SPI clock below 400K during initialization. Reduce the clock speed and try the code again.The CRC is disabled by default in SPI mode. IT's required to be 0x95 only during the first command, CMD0, which makes the card enter into SPI mode. So, CMD1 won't haveany eefect of what CRC value is.One more thing, check out the phase & polarity settings of the SPI clock. The phase should be Low & the clock signal should remain high when idle.

SPI settings i have used:master mode,msb first,CPOL=CPHA=0.these settings are same as you have done.card doesnt initalise if i make cpol = 1.p89v51rd2 datasheet saysif CPOL is 1 = SCK is high when idle (active LOW), if CPOL is 0 = SCK islow when idle (active HIGH).

making CPOL = 0.i checked the clk line which i found to be 0 volts when no data communication.for CMD0 response is 0x01for CMD1 response is 0x00seems initialisation is done.

but after that i receivedFAT32 not found!(means not able to read boot sector)how to resolve it???

writing single block it showsWrite successful!but after that when i read a single block by pressing '2'it just prints 512 spaces & then prints - Read succesfully!but it has never shown the read data????

in my controller i have 4 settings for spi clk: FOSC/4,FOSC/16,FOSC/64,FOSC/128.during SD init i used FOSC/16 and i found initilisation successful.after SD init i used FOSC/4.

To Milind:The messages show that the card is initialized properly!Are you sure of not reading a blank sector? Did you try reading block 0? OR try to write a block with some characters and read the same block. The same characters should appear.If problem continues, try to display hex value of what you're receiving.Also, check the readSingleBlock function, whether anything is changed where the characters are being printed on the hyperTerminal?

The transmitHex was not working so i introduced a delay of 1ms in the function transmitString,so now its working.now am tryin to send the data to hyperterm in hex format.as seen that when i try to read the 0000 block.in the boot code area it showed all 00,in the first partition area it shows some hex data0x00 0x04 0x04 0x00 0x0B 0x06 0xE6 0xCD 0xFF 0x00 0x00 0x00 0x01 0xEF 0x1D 0x00and it shows the signature as 0x55 0xAA Read successful!then i tried writing to block 5000it displayed Write successful!then i tried reading the block 5000it displayed all 0xFF Read successful!

what is wrong?????????????????If you want to go through the code ,i can mail it to you.anyway i have mailed you the captured text.

i downloaded the zipped code modified for mega32 and program the hex file in the folder into my mega32 without any change(is this the right way to run the test program??), but it didn't show up anything on the hyperterminal.

then i checked the sd_main.c and find a problem with the port_init function, why should the PORTB be set 0xBF and DDRB 0xEF ?? also DDRD? i changed the port_init with PORTB--0xEF,DDRB--0xBF and DDRD--0xFE (the way which i think is right)and compile it with winavr, this time the hyperterminal show up the menu, but the options didn't work well showing "fat32 options disabled".

Hi Kyle.thanks for pointing it out. You are right about the port init. But since it never gave any problem to me so i never changed it. Just now I compiled and tested the code in my circuit again the earlier code and with the corrections you mentioned. Both are working perfect for me!Anyways, I've changed the zip file for mega32 to include this change.

Regarding the FAT32 options, the message 'FAT32 options disabled' comes when the controller is not able to detect the FAT32 file system in the card. You can retry after formatting the card with FAT32 file system using your PC.

sir did u received my mail??i have sent u the zipped code.i searched over the net for my problem and i found that MBR is located in different places for different card.i am using 1GB transcend card.(and the other card which i have is 2gb sandisk is china made ,so might be the problem with this card).but right now i must stick to transend one bcoz i can view the the MBR of it.

problem is getting the cluster.

i am bit confused about finding the appropriate cluster?????

bcoz i end up getting Error getting cluster!can i get some docs explaining fat structure for sd card???equations for accessing sector,clusters....etc..??????????

Hi Milind,the first sector in the card is either boot sector or the MBR (Master Boot Record). If the first byte of the sector is 0xEB or 0xE9, then it's boot sector. IF it's not, then it should be MBR with end signature of 0xaa55. You are getting the first sector end signature correctly (the 0xaa55 gets stored with 0x55 first and 0xaa last).In your case, the first sector is not the boot sector, but it contains the valid signature of the MBR. The problem is, MBR should contain the partition info from bytes 446 to 509 (total 64 bytes)from where the address of the boot sector can be obtained, which is essential for the controller to get information on importatnt parameters lile cluster size, fat volume, root cluster etc.

Surprisingly, your card MBR contains no partition info, so the controller is declaring that no FAT32 found.

For raw data transfer, you need not worry about the cluster, sector etc. It only needs that the card is initialized, no problem if the fat32 is not found.

There can be other reasons for 'FAT32 not found'. If you are using AVR controller, you won't need to do little endian - big endian conversion, as they follow little endian convention which is followed by the FAT32 file system.

I'm using the ATMEGA8. I have everything connected, and have a 2GB SD Card connected formatted with FAT32 (does it matter what the allocation unit size is?) When I load in your hex file, it says "SD init fail..FAT32 not found!" When I press any key, I can write to the file but not read from it.

Do you (or another who read this) know if the toshiba microSD card 1Gb support the SPI mode ? I know that SPI mode is officialy an "option" for the microSD, and for the moment I'm not able to get any response of this card ...

To Mark:Hi, the main reason for SD init fail is improper connections. Check out all the SD connections again to match with the schematic I've provided in this post. Also, check out the SD adapter properly, if you've soldered it, whether pins inside are bent.Since you are getting the hyper terminal messages, i don't doubt the controller frequency (8 MHz).

Hi Marc,during the SPI communication, the clock is provided by the master. Here the AVR is master, and AVR sends out the clock only when you load the SPDR register with something. So, when we write SPDR = 0xff, the AVR actually transmits the 0xff along with the clock. Since the slave (SD) is waiting for the clock, to put it's data on the bus, as soon as the clock is activated, it starts transmitting the data. In this process, the slave receives the 0xff. But, since it is not expecting any data at that point, it'll simply ignore that byte.Actually, you can use a single function for receive and transmit both on SPI, as during any of these two processes, the AVR will perform receive and transmit both. I'm using separate function only to avoid confusion.

Ahh that makes sense. For some reason I thought the SCK is sent out the moment SS is asserted.

Lastly, I am now able to initilaize and list files in my SD card, but when I try to "Read File" on an MP3 file in my 2GB SD card, all I see is an endless stream of junk that gets sent to my hyperterminal.

It kind of looks like that it's repeating the data over and over again. I saw in one of your earlier posts you mentioned that the controller is only reading the first cluster. I have not changed anything with the code, I'm using your hex file you posted.

Ofcourse marc, you can't display an mp3 file on hyper terminal, it can display only text files properly. mp3 file will look there junk only. Try to read a text file and check if the hyper terminal displays it correctly, if it is, the code is working perfect there. you have to treat mp3 files separately. For example, you can read it and send it directly to an mp3 decoder chip which can decode the file and produce audio signal. This code just demonstrates how to access files from the SD card with FAT32 file system. you can put it into various uses by adding your own code.

I did indeed expect garbage to come out, but it was an infinite loop of garbage, is that expected? I was expecting some sort of end to the junk-data and returning to the menu. I apologize if that is an uneducated question, I'm more of an EE than a Computer Science guy.

Hi marc, today I converted a 3.2MB mp3 file into text. It resulted into a text file with total of 3356455 characters. If a non-stop text stream (with 8-bit ascii characters)with this length is transmitted to hyper terminal with 19200 baud-rate, without any other delay , it'll take (3356455*10/19200=) 1748 seconds, or 29 minutes, for displaying complete file on hyper terminal. Now add into this, the delay taken by the microcontroller to go thru the FAT32 structure to find next cluster in the cluster-chain, by searching thru the FAT entries and other over-head delays which occur due to calling the functions.

I'm sure you wouldn't have waited so long for the file to get displayed completely!! :)

Well, I did it, just out of curiosity. I waited till 27 minutes (ofcourse, while doing some other stuff) for a 2.3MB file to get displayed completely, & finally the menu appeared!! ;)

Hi Saran,you can use a microSD card PCB connector which has a separate pin for card detection purpose. You can simply connect that to one of your controller input port-pin to detect presence/absence of the card.otherwise, in the code, the line where "SD init fail.." is written, you can replace it with "SD card not detected.."

Hi Morgoth,thanks for the suggestions. The code was originally written for ATmega8, and there it occupies 99.9% of flash. Declaring functions 'inline' would increase the speed, but it'll need more flash, which i didn't have (as i understand, inline function code is put up by compiler directly at all places wherever the function is called, rather than putting the call instruction to the function. This can be used to reduce the timing overhead occured by calling the function, but it certainly needs more code memory)

I've mentioned this fact in the post also where I've written about the data transfer rates.

But certainly, for controllers having more than 8K, those functions can be declared 'inline' to increase the speed of data transfer.

Hi, I'm also working with MCU SD card interface and I would like to ask for some help if you can. How do I get high data transfer to the SD card? What's the data rate that you acan achieve for writing to the SD card?Any help or advice you can give me is most welcomed.thanks

Hi felipe,as per the SD card association, "the SD Speed Class Ratings specify the following minimum write speeds based on 'the best fragmented state where no memory unit is occupied'

* Class 2: 2 MB/s * Class 4: 4 MB/s * Class 6: 6 MB/s

One critical difference between the Speed Class and the maximum speed ratings is the ability of the host device to query the SD card for the speed class and determine the best location to store data that meets the performance required"Some of the high speed cards even claim to have achieved 10 MB/s & 20 MB/s speeds also.

So, if you have a powerful microcontroller/processor with lots of RAM and high clock speed, you can achieve the specified speeds or even higher.

When interfacing with microcontrollers, main limitation is the controller's own clock speed, which is usually in few Mega Hertz. This limits the SPI clock speed which results in lower transfer rates.

For achieving maximum possible speed with microcontrollers, run your controller at maximum clock allowed, set the SPI clock speed with minimum prescaler.Also, reduce the timing overhead by declaring the frequently called functions as 'inline' (like the SPI transmit & receive functions). If you have more RAM, have separate buffers for data & the FAT table access. That will reduce the time consumed by buffer allocation.

Thanks a lot.Your project has been very useful to me. I am also doing a project in which I am interfacing a microSD card with ATMEGA8 to store the on field data. But instead of using a Hyperterminal to enter data I am trying to give the input from the microcontroller itself.In my project, the ATMEGA8 calculates the speed and I need to store this speed value onto the microSD card.In order to achieve this,can you please tell me what are the necessary changes to be made. I shall be very grateful if you help me.Thank you once again.

Hi again.Thanks for the fast response. I'm already running my SPI peripheral at 20MHz, but I still only get 200KB/s.I was thinking of implementing multi read/write, do you now how to do it?I've been trying to send multi block command(CMD25) and multi block start token(0xFC) to make it work but when I try to write/read to it but it only reads/writes 512bytes (1 sector).Another thing that isn't clear to me is the data transfer in this mode.After I send CMD25+0xFC, can I send any size of block, ie.2048bytes, or can I only send 512bytes (configured in BLOCKLEN)? Also, do I have to update the sector address every time or does the SD card handle this?Sorry for bothering you again and thanks very much for your earlier reply.

That's great! Thank you about your source code. I'm beginer with Atmega, and your code so helpful for me. By the way, I want to write draw data from computer to SD card. Have you ever written SD card from computer using C++. If you had, could you share for everyone! or show me which library to write draw data to SD cardThanks Dharmani!

To Jacky: Hi, did you change anything in the code, if yes, ou can send me the modified code, I'll chekc it out. I had verified the createFile function. If you generate .txt file using it, it'll open using the PC.

To Muthu: As you didn't mention about "Sd init fail.." message, I assume that the card is properly initialized. If you've used the raw data options (0, 1 or 3) to write anything in the SD, the FAT32 file structure might have got disturbed. Try again after re-formatting the card with FAT32 using your PC.

Regarding the file name problem, store the unused bytes in the fileName[] array with 0x00.

To Ankit Thanks for the comments. man!

To Loc Phuoc Nguyen: I haven't written code for C++. But if you want to write the card using C++ with a PC, and if you use this AVR circuit with the code loaded, the job is pretty easy. As you see, the hyper terminal is used here to send command to the microcontroller from PC for reading/writing the SD. All you need to do is to implement C++ code to access the serial port and send the command directly to the controller via that port just the way hyper terminal sends it. Using that code, you can read/write the card with C++, rather that the hyper terminal

Hi Sir,Thanks for the fast response.My sd card init process pass and i can able to read and write in the RAW formet.When i use in FAT32 formet ,it says FAT32 formet Found.Still Ok.But when i create file using createFile function i got File does not exist error.I gave fileName as two method

Dharmani sir,i a have a peculiar problem. i formatted transcend 1GB microSD card on machine running windowsXpSP2. the card gets initialized properly but sometimes it does not detect the fat32 filesystem sometimes it does.I would think it is a connection problem but then if the card is getting initialized that means the connections are ok. this happens very often.Can it be any other problem except loose connections?

PS: i did nt change the code except SD_CS_ASSERT & SD_CS_DEASSERT for using PB4 on ATMega32.

Sir, Even I have the same doubt as Muthu. Instead of giving the data from the hyperterminal to create a file, how should the code be changed so that I myself can give a name to create a file rather than accepting from the keyboard. And sir , one more thing. After creating a text file, how can we write text into it. I need to store some on field speed values into that text file. I shall be very grateful if you help me with this.Thank you.

To Muthu:In your first problem, it sounds like you are calling readFile() function by mistake instead of createFile(), check it out, if not solved yet!

To Ankit:In the main function, call the SD_init() function twice, instead of once, and check again.

To Muthu & Bharath:While writing these libraries, I had thought of it as just a learning aid for SD card & FAT32 for newcomers, that's why it uses hyper terminal for reading, writing as it's much easier to verify that way.But now, I'm modifying these routines to make them more generic, which can be used like the way you guys want.I'll post it here shortly (within a week) after testing it. Till then, try it your own way :)

hi sir adarsh here from iit mumbai....sir i have to design a device which read the contents and ppl near him will able to hear..

the basic idea is i have to take the data from the sd card....stored in wave/hex/text format and using that pwm is generated which is input to the amplifier and finally to the speaker..so what ever u was discussing is able to read a wave/hex file or not.also i want to know is data taken fron sd card bit by bit or in a cluster...basically i have to play a speech stored in sd card in wave format....so suggest me in what format data is to b stored and how it is taken using atmega 32..

Nice info about SD card interface.i am trying to use mega8 to play raw wav data stored on a SD card (raw image is stored on the SDcard).but want to do it in AVR assembly, can you help me with SD card read,write and init routines in asm

I was able to successfully interface your awesome library to my atmega328 and sd card. I am trying to play an mp3 file through a VS1002 mp3 decoder, but the song is playing in slow motion. I have spent the past 4 days trying to figure out what could be wrong. Just to rule your code out, do you know of any delays or functions or such that could possibily be hindering my transmit to SPI?

To Adarsh:How r u going to store the data in the SD card? If you are using your PC to store the wave files then you need to use FAT structure, not the raw SD functions. There you can decode the wave file to get the data chunks & send it byte-by-byte to the PWM.Other way would be to use an audio codec IC, like VS1002 on SPI bus(see the last comment), that would decode the WAVE file and give directly audio output. Also, that would be able to play mp3 files, if in future you decide to store data in mp3 format.

To Nischay:if you check the previous comments, Morgoth has written the SD routines in assembly, you can check out the link he has given:http://digitalelectronicsandprograming.blogspot.com/2009/02/fat32-complete-library-in-asm-linguage.html

To Anonymous:Did you try using higher frequency crystal like 16MHz? It will make the SPI bus speed double. Check out if that makes the songs play faster. Also, you can declare the SPI transmit & receive functions as "inline", that'll save some more time.

thanks for ur quick reply.....yes sir i want to store the wav files using pc only...so tell me how to store data in sd card using pc.....i have basically no idea about fat system plese give me a detail idea of storing the wav files in sd card using pc...

To anonymous:Ya, I don't think the FAT32 code is the reason for delayed audio. May be you can check out the VS1002 driver code & settings.

To anonymous:I haven't tried so far to modify the code for big-endian structure. You have to write code to get the values of the variables bigger then 1 byte by converting them from little-endian to big-endian structure.

To Adarsh:You can use an SD card reader to write files into SD card using PC. After storing the files, when u interface the card with the controller, u will also need to modify the FAT32 reading functions so that the controller doesn't send the data to hyper terminal but send it to PWM or the audio codec chip.

can i directly write wav files to sd card........is there some modification should be done....formatting should be done in which format.............is wave file is binary files.......in what format it should be written....so that data is taken byte by byte..........

Nice project, but i have a problem. When I try to write a file larger than 1kB it's unredable under Windows (file corrupt message). File is always readable via HT (atmega). After running ScanDisk under Windows corrupt files are healed.I'm working with Your code for M32 (low voltage). Any idea why it's like that? Do You have any problems with files >1kB?

Dear CC Dharmani,If it is not too much trouble I would like to ask you for help/suggestion(or to anyone in this forum that reads this msg).I'm trying to achieve maximum data write but I'm only able to achieve around 250KB/s. According to any SD card specification, they are able to transfer at least 1MB/s. I'm already running SPI at 20MHz and using multi block write and I can only write at 250KB/s. Although I'm 5Mhz short of the maximum frequency for the SPI I think that I should be writing at 700KB/s at least. So, if anyone has any ideia as how to do this I will be very thankful.Regards

To Adarsh:you can format the card with FAT32 and store the WAV files directly, using the SD card reader. WAV file contains the uncompressed audio data which can be accessed byte by byte. For this, you'll need to understand WAV file structure. Just go to google and search for 'wave file format', you'll get the format document. Go thru it for better understanding.

To M.Did you change anything in the createFile function? That error comes when the root directory is not extended to new limits after creating a file, even though the file is created properly. When you run the windows scan, it automatically corrects the root directory boundery, so the files appear properly. Check out the code, if you've chnaged anything!

To Felipe:If you have RAM more than 1KB, you can try to use two separate buffers for data access and the FAT access. This will reduce the time consumed for finding the files in clusters and will result in some increase in the speed.

Sorry, I forgot to mention that I'm writing the data in raw mode to SD card, i.e. I fill a buffer with 512Bytes and I tell the MCU to write this same buffer from sector 500 to sector 4500 using multi block write.I have 6KB of RAM to use but even with this memory I can't achieve high speed data transfer. I have also noted that the maximum sectors that I can write to the SD card, using multi write, is somewhere between 4000 and 5000 sectors (I guess this is about the size of the buffer inside my SD card). If I try to write more than this amount of sectors the data will not be written to the card BUT if I call a new multi block write it works just fine but even this way I'm not achieving the data speeds that the card should work.If you have anymore sugestions I'll be grateful. And thanks again for spending your time to answer me.Regards

CC Dharmani said..."Did you change anything in the createFile function?"

No, it's untouched. I've even tried with fresh copy of FAT32.c from both projects (M32 & M8). Verification showned that they are perfect match, as expected.My only change is location of CS pin.Could it be something witch SD card? (I'm using 128MB micro SD with regular size adapter made by SanDisk).

To Felipe: I think the other possibilities to increase the speed is to review your functions of filling the 512 byte buffer, how fast you are writing it and the internal writing speed of the SD card. Card to card writing speed varies. Have you tried another SD card?

To Adarsh:The MMC card has a small difference in the initialization command sequence, in my code I've not taken care of that, but the SD_init() function can be changed little to try with MMC card, though I've not tested it. If you have an SD/microSd card, try the code with that one or I'll send you the function of MMC initialization to your mail ID.

To M.:One of the reader of this blog has tested the code on 128MB card successfully. But anyways, you can try with another card. If possible you can send me the sector-0 data (512 bytes) in HEX. I'll just check the FAT structure if any difference is there.

Sir, I am using a data logger in one of my projects. If I write RAW data onto the SD card, how can I view that data on my computer? It would be much more helpful if you tell me how can I import that RAW data into Microsoft Excel.Because when a card formatted as RAW is opened in a computer ,it says "Card not Formatted. Do you want to format the card?" But I want to view my RAW data on the computer.Can you help me?

Thanks M., for suggesting that small but very effective change for compatibility with different size cards! :)I'm modifying my library for making it more general, there I'm using variables rather than fixed numbers, just like you suggested.

Sir, I am trying to read a file in FAT32 format from the SD Card. The file was directly loaded into the SD Card using PC but the problem is that it is unable to detect the file. Can u please point out what exactly could be the problem. Thanks.

P.S. - I have made quite a few modifications in the code but am pretty sure that the code is fine.

Sir, with reference to my previous post I want to add that I am only concerned with reading a FAT32 file from SD Card which was directly loaded into it by a PC. For this purpose I have made quite a few modifications in FAT32.c file. I have kept only the below listed functions and removed all other functions:

Dharmani Sir, If I wanted to use the first options i.e. reading and writing raw data , in which form should I initially format the card. I have a 2GB microSD card formatted in FAT32 form. Now if I want to use first two options ,into which other form should I format the card? And is there no other way of viewing the raw data other than the hyperterminal. Is there any software to accomplish this?Thank you.

To Vikrant:Hi, I've never tested anything big-endian as I'm using the AVRs, but I think now I need to look into it as this question is coming frequently. Which controller are you using?Can you just send me the sector-0 data? I just want to check it out for suggesting a solution.

To Bharath: For using the raw function, no need to worry about the format of the card. It doesn't make any difference whether you format the card or not!For viewing raw data, you can use the winHex, as suggested by Morgoth. You can download it from here:http://www.x-ways.net/winhex/index-m.htmlYou can also use Bray's Terminal:http://www.smileymicros.com/download/term20040714.zip?&MMN_position=42:42

Hello Mr Dharmani,I'm new to SD card..Your project is very interesting. Can you kindly confirm these points: 1.One cannot write less than 512 bytes to the SD card at one go, correct ? Does that mean I accumulate all my data (say in a data logger app) in an external (RAM) buffer till it reaches 512 bytes? What if power is removed before this point ? Also, if I just want to overwrite a few bytes, do I read the entire block into RAM, modify it & then write the whole thing back to the SD card ? Is there *any* way to just write a few bytes to the card ?2. Does this also mean that the uC needs to have at least 512b spare RAM for SD card operations?

Sir, I am working on a Freescale uC of Coldfire v1 series. I am trying to convert the code for big endian myself. I hope it will work. Sir can u plz tell me dat for reading a FAT32 file from SD Card are the functions listed below are sufficient or do I need to include anymore functions???

To Royce:Hi, the SD will always read/write a block the moment you send the block address. But, since the SD is operating on SPI bus, theoritically you can hold the communication after each byte by stopping the SPI clock, but practically I've not tested this one, one need to check out if the SD is having any time-out limit internally..

You can manage with RAM lower than 512 bytes, but compromising with the speed!

To Vikrant:For reading a file, you'll also need the convertFileName() function.

While reading /writing raw data, the little-endian big-endian doesn't make any difference as the data is accessed byte-by-byte.

Hi Royce,for reading the raw data, if you don't have a big buffer then you can read that block into smaller chunks, for example, if you have 50 byte buffer, you can get first 50 bytes over the SPI bus and do whatever process you want to do on them, after that read the next 50 bytes of the block using the same buffer, you can repeat the process till 500 bytes are over after that get the last 12 bytes.

So, here you will add some extra loops in the readSingleBlock() or writeSingleBlock() functions, which will reduce the overall reading/writing speed of the SD card.Well, whether some reduction of speed has any effect that depends on your application.

Hi,The challenge is actually with writing the data. If I have a logger where I read 5 integers( temperatures for example), I need to save the 10 bytes & exit. In the meantime, the user may ask to view the to-date log (or some other interruption), so there is no way the uC can hang around for 512B to be written (esp.if the logging is done once per 5 minutes), as it may want to switch to reading the card, before 512B are up.

So I may have to save in RAM & wait for 512 bytes to accumulate, which may take 2 days (at slow log intervals). This is not good 'coz if the power is disconnected, what happens to my RAM values waiting to be written to the card?

Am I missing something here ? Is there some way that these concerns have already been addressed?

All these issues are holding me back from implementing SD card in an upcoming logger project.

That can be achieved easily with a 512 byte buffer and an integer to keep track of where in that 512 bytes you have to add data. Read the block, modify those 10 bytes in the buffer and write the buffer back to the same block, as you had mentioned earlier. Then the controller is free to do other tasks till the next 10 bytes are ready to be written.

Dear CC Dharmani,I've tryied doing what you suggested so I bought a new card (8GB SDHC 4) to see if I can get higher writing speeds. According to the SD standards this card should be able to write 4MB/s continuously without any problem but all I got was 330KB/s. Any more ideas? ANYONE? I'm really running out of ideas and I need to achieve a high writing data speed.thanks again for all of your prompt replies.

Hi Felipe,if possible, you can interface the card with the controller using SD Bus protocol (4-line parallel) instead of SPI bus, there you can achieve speed almost four times as compared to SPI mode speed.

thanks for providing link to Morgoth's ASM library, iam able to write to sectors (No FAT- only raw data transfers) but unable to read from the sector/s ( starting from sector 0) - can you suggest any solution ?

I'm trying to adapt your code to an Atmega168. It's turning out to be harder than expected. The led lights up but nothing is displayed in the terminal. I need help with the port values and registers I think

Safe Landing, Welcome!!

Hi techies,this blog is created for sharing design ideas of circuits based on microcontrollers!! Be it any controller, i don't mind! my favourite microocntrollers are AVRs from Atmel (Microchip)Have a say if you find anything useful or the opposite on this blog!! You can also share your comments on the designs!

Free Datasheets

Translate this page

Subscribe To

Copyright (c) 2009-2018 CC DharmaniDisclaimer: Information presented on this blog is on a cost-free basis and though it is tested with best of my knowledge to make it error-free, no warranty is given for any mistake and hence no responsibility taken for any faults. Try it at your own risk! -CC Dharmani