You are on page 1of 16

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). 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 winAVRAVRStudio. Version 2.4.1 (RTC added for Date/Time entries) 17 May 2010/24 Apr 2011 Version 2.3 (SDHC support added) 09 May 2010 Version 2.2 (No SDHC support) 13 Sep 2009

Download EAGLE schematic file of Ver 2.4


Download/view source code files V2.1 (for ATmega8): Following files are compiled using winAVR inside AVRStudio. This Version does not support SDHC cards. Also, append file feature is not available. 1. SD_main.c 2. SD_routines.c & SD_routines.h

3. FAT32.c & FAT32.h (Ver 2.1, last updated-13 Sep 09) 4. SPI_routines.c & SPI_routines.h 5. UART_routines.c & UART_routines.h 6. Makefile 7. HEX file (Ver 2.1, last updated-13 Sep 09) Please put up a comment or mail me if you find a bug in the code. The updates are because of valuable suggestions & comments from the users of this code. Thanks a lot!! 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 09 to 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

SD card

Pin description of an SD card


Pin Name 1 2 3 4 5 6 7 8 9 DAT3/CS CMD/DI VSS1 VDD CLK VSS2 DAT0/DO DAT1/IRQ DAT2/NC Function (SD Function (SPI Mode) Mode) Chip Select/Slave Data Line 3 (SS) Command Mater Out Slave In Line (MOSI) Ground Ground Supply Supply Voltage Voltage Clock Clock (SCK) Ground Ground Master In Slave Out Data Line 0 (MISO) Data Line 1 Unused or IRQ Data Line 2 Unused

Important SD card commands


Command Argument CMD0 CMD16 None 32-bit Block Length Type Description Response Tell the card to reset and enter R1 its idle state. R1 Select the block length.

CMD17 CMD24 CMD55 CMD58

32-bit Block Address 32-bit Block Address None None

R1 R1 R1 R3 R1

Read a single block. Write a single block. Next command will be application-specific (ACMDXX). Read OCR (Operating Conditions Register). Initialize the card.

ACMD41 None

Initialize SD card
Initialization begins by setting the SPI control clock signal to 400kHz, which is required for compatibility of most SD and MCC memory cards. Then reset the tab order at CMD0 activated CS input card (CS at level L). CRC byte for the command CMD0 and zero argument command is 0x95. CMD55 followed orders and ACMD41. If after the idle bit in the level L handshake is completed and anticipates that further management framework. Command CMD58 For example, we check whether the card supports the same supply voltage as the MCU, which is typically in the range of 2.7 V to 3.6 V. SPI clock signal to set the maximum allowed value.

Program part
SD card connection to microcontroller
#define DI 6 (data from MMC) #define DT 5 (data to MMC) #define CLK 7 #define CS 4 for MMC // Port B bit 6 (pin7): data in // Port B bit 5 (pin6): data out // Port B bit 7 (pin8): clock // Port B bit 4 (pin5): chip select

SPI Initialization:
void ini_SPI(void) { DDRB &= ~(_BV(DI)); DDRB |= _BV(CLK); DDRB |= _BV(DT); DDRB |= _BV(CS); SPCR |= _BV(SPE); SPCR |= _BV(MSTR); SPCR &= ~(_BV(SPR1)); SPCR |= _BV(SPR0); SPSR &= ~(_BV(SPI2X)); PORTB &= ~(_BV(CS)); SD card //input //outputs //outputs //outputs //SPI enable //Master SPI mode //fosc/16 //fosc/16 //speed is not doubled //Enable CS pin for the

Functions for sending and receiving one byte through SPI:


char SPI_sendchar(char chr) { char receivedchar = 0; SPDR = chr; while(!(SPSR & (1<<SPIF))); receivedchar = SPDR; return (receivedchar); }

Function to send a command frame Command:


char Command(char cmd, uint16_t ArgH, uint16_t ArgL, char crc ) { SPI_sendchar(0xFF); SPI_sendchar(cmd); SPI_sendchar((uint8_t)(ArgH >> 8)); SPI_sendchar((uint8_t)ArgH); SPI_sendchar((uint8_t)(ArgL >> 8)); SPI_sendchar((uint8_t)ArgL); SPI_sendchar(crc); SPI_sendchar(0xFF); return SPI_sendchar(0xFF); // Returns the last byte received }

Initialization card:
void ini_SD(void) { char i; PORTB |= _BV(CS); for(i=0; i < 10; i++) SPI_sendchar(0xFF); pulses 400 kHz PORTB &= ~(_BV(CS)); for(i=0; i < 2; i++) SPI_sendchar(0xFF); pulses 400 kHz Command(0x40,0,0,0x95); idle_no: if (Command(0x41,0,0,0xFF) !=0) goto idle_no; SPCR &= ~(_BV(SPR0)); }

//disable CS // Send 10 * 8 = 80 clock //enable CS // Send 2 * 8 = 16 clock // reset //idle = L? //fosc/4

Writing to the card: The function returns 1 if an error occurs else returns 0 if successful
int write(void) { int i; uint8_t wbr; //Set write mode 512 bytes if (Command(0x58,0,512,0xFF) !=0) { //Determine value of the response byte 0 = no errors return 1; //return value 1 = error } SPI_sendchar(0xFF); SPI_sendchar(0xFF); SPI_sendchar(0xFE); //recommended by posting a terminator sequence [2] //write data from chars [512] tab uint16_t ix; char r1 = Command(0x58,0,512,0xFF); for (ix = 0; ix < 50000; ix++) { if (r1 == (char)0x00) break; r1 = SPI_sendchar(0xFF); } if (r1 != (char)0x00) { return 1; //return value 1 = error } //recommended by the control loop [2] SPI_sendchar(0xFF); SPI_sendchar(0xFF); wbr = SPI_sendchar(0xFF); //write block response and testing error wbr &= 0x1F; //zeroing top three indeterminate bits 0b.0001.1111 if (wbr != 0x05) { // 0x05 = 0b.0000.0101 //write error or CRC error return 1; } while(SPI_sendchar(0xFF) != (char)0xFF); //wait for the completion of a write operation to the card return 0; }

Reading from the card: The function returns 1 if an error occurs else returns 0 if successful
int read(void) { int i;

uint16_t ix; char r1 = Command(0x51,0,512,0xFF); for (ix = 0; ix < 50000; ix++) { if (r1 == (char)0x00) break; r1 = SPI_sendchar(0xFF); } if (r1 != (char)0x00) { return 1; } //read from the card will start after the framework while(SPI_sendchar(0xFF) != (char)0xFE); for(i=0; i < 512; i++) { while(!(SPSR & (1<<SPIF))); chars[i] = SPDR; SPDR = SPI_sendchar(0xFF); } SPI_sendchar(0xFF); SPI_sendchar(0xFF); return 0;

Adding all the codes:


#include <avr/io.h> #include <avr/iom16.h> #include <avr/interrupt.h> #define FOSC 6400000 char chars[512]; int main(void) { ini_SPI(); ini_SD(); sei(); write(); read(); } return 0;

SD_Card_FAT32_Implementation.doc (Size: 307.5 KB / Downloads: 39) Abstract In last couple of years the Secure Digital (SD) memory Card has proved itself as a de facto memory solution for all the portable devices and Equipments like camera, PDA, mobile phones, GPS navigation modules, gaming consoles, MP3 players etc. This article demonstrates how to interface SD card to expand AVR microcontrollers nonvolatile data storage capacity. So as to fulfill the excessive memory requirements of a typical embedded application. In this project ATmega16 is interfaced with Transcend 1 GB SD Card (TS1GSDC). The aim of the project is to accept data from the User through keyboard of the PC and store it in the SD CARD and Retrieve the same when the user wants. The user at first, will be given the option either to read the data from the SDCARD or write to the SDCARD. The 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.But what if your embedded system is memory hungry for application like Data logger for Weather Station or an application in Industrial Automation to Log Alarms and Trends require more nonvolatile memory storage (Flash / EEPROM). A 5v dc adaptor is used which converts the wall plug power (230v AC) to a 5v DC. The SD card works only at 3.3v and the operation voltage range of ATmega16 is 2.7v to 5.5v, hence an LD33 regulator is used to convert the 5v DC to 3.3v DC. This 3.3v is supplied to all the components in this project.The five 47K resistors have been used to Pull up the PORT pins which are connected in between the microcontroller and SD CARD pins.The Socket which holds the SD Card has two Gulls on either side it. These gulls are soldered to the General purpose Board in order to fix it firmly onto the general purpose board. 1. Introduction The SD Card interface allows for easy integration into any design, regardless of microprocessor used. For compatibility with existing controllers, the SanDisk SD Card offers, in addition to the SD Card interface, an alternate communication protocol, which is based on the SPI standard. Software Requirements 1. Windows Xp OS 2. AVR Studio 4.18 3. WinAVR GCC Compiler 4. AT Prog Serial Programmer Hardware Requirements 1. DC power supply 5v,3.3v(230/9v transformer,7805 regulator) 2. ATmega16/32 Microcontroller 3. 1 GB Sd card 4. MAX-232 IC,Standard Cabels 5. SDcard Holder Applications 1. Data Storages 2. Mobiles, Camera Applications

3. MP3 Players Future Scope 1. Iimages Introduction to sd card The Secure Digital Card is a flash-based memory card that is specifically designed to meet the security, capacity, performance and environmental requirements inherent in newly emerging audio and video consumer electronic devices. The SD Card includes a copyright protection mechanism that complies with the security of the SDMI standard, and is faster and capable of higher Memory capacity. The SD Card security system uses mutual authentication and a new cipher algorithm to protect from illegal usage of the card content. A non-secured access to the users own content is also available. The physical form factor, pin assignment and data transfer protocol are forward compatible with the SD Card, with some additions. The SD Card communication is based on an advanced nine-pin interface (Clock, Command, 4xData and 3xPower lines) designed to operate in a low voltage range. The communication protocol is defined as part of this specification. The SD Card host interface supports regular Multimedia Card operation as well. In other words, MultiMediaCard forward compatibility was kept. Actually the main difference between SD Card and Multimedia Card is the initialization process. The SD Card specifications were originally defined by MEI (Matsushita Electric Company), Toshiba Corporation and SanDisk Corporation. Currently, the specifications are controlled by the Secure Digital Association (SDA). The SanDisk SD Card was designed to be compatible with the SD Card Physical Specification. The SD Card interface allows for easy integration into any design, regardless of microprocessor used. For compatibility with existing controllers, the SanDisk SD Card offers, in addition to the SD Card interface, an alternate communication protocol, which is based on the SPI standard. General Pin Description. The SD Card has nine exposed contacts on one side (see Figure 2-1). The host is connected to the SD Card using a dedicated 9-pin connector. Table 2-1 lists the pin assignments and definitions in SPI Mode NOTES: 1) S=power supply; I=input; O=output. 2) The RSV pins are floating inputs. It is the responsibility of the host designer to connect external pullup resistors to those lines. Otherwise non-expected high current consumption may occur due to the floating inputs SDCARD Images SPI Communication While the SD Card channel is based on command and data bit-streams, which are initiated by a start bit and terminated by a stop bit, the SPI channel is byte oriented. Every command or data block is built of eight bit bytes and is byte aligned (multiples of eight clocks) to the CS signal. Similar to the SD Bus protocol, the SPI messages are built from command, response and data-block tokens. All communication between host and cards is controlled by the host (master). The host starts every bus transaction by asserting the CS signal low. A serial peripheral interface (SPI) is an interface that enables the serial (one bit at a time) exchange of data between two devices, one called a master and the other called a slave.

An SPI operates in full duplex mode. This means that data can be transferred in both directions at the same time. The SPI is most often employed in systems for communication between the central processing unit (CPU) and peripheral devices Two identical SPI units are displayed. The left unit is configured as master while the right unit is configured as slave. The MISO, MOSI and SCK lines are connected with the corresponding lines of the other part. The mode in which a part is running determines if they are input or output signal lines. Because a bit is shifted from the master to the slave and from the slave to the master simultaneously in one clock cycle both 8-bit shift registers can be considered as one 16-bit circular shift register. This means that after eight SCK clock pulses the data between master and slave will be exchanged. The system is single buffered in the transmit direction and double buffered in the receive direction. This influences the data handling in the following ways: 1. New bytes to be sent can not be written to the data register (SPDR) / shift register before the entire shift cycle is completed. 2. Received bytes are written to the Receive Buffer immediately after the transmission is Completed. 3. The Receive Buffer has to be read before the next transmission is completed or data will be lost. 4. Reading the SPDR will return the data of the Receive Buffer. After a transfer is completed the SPI Interrupt Flag (SPIF) will be set in the SPI Status Register (SPSR). This will cause the corresponding interrupt to be executed if these interrupt and the global interrupts are enabled. Setting the SPI Interrupt Enable (SPIE) bit in the SPCR enables the interrupt of the SPI while setting the I bit in the SREG enables the global interrupts Reference: http://www.seminarprojects.com/Thread-sd-card-interfacing-with-atmega1632-fat32-implementation#ixzz1ZUeHWVQv

You might also like