AddThis

Bookmark and Share

Thursday 29 July 2010

Reading and writing SD card using Atmega16

This project explains how to read and write an SD card using an AVR microcontroller.

SD card

sdcard

Pin description of an SD card

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

Important SD card commands

Command Argument Type Response Description
CMD0 None R1 Tell the card to reset and enter its idle state.
CMD16 32-bit Block Length R1 Select the block length.
CMD17 32-bit Block Address R1 Read a single block.
CMD24 32-bit Block Address R1 Write a single block.
CMD55

None

R1

Next command will be application-specific (ACMDXX).
CMD58 None R3 Read OCR (Operating Conditions Register).
ACMD41 None R1 Initialize the card.

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                         // Port B bit 6 (pin7): data in (data from MMC)
#define DT 5                        // Port B bit 5 (pin6): data out (data to MMC)
#define CLK 7                     // Port B bit 7 (pin8): clock
#define CS 4                        // Port B bit 4 (pin5): chip select for MMC

SPI Initialization:

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

Functions for sending and receiving one byte through SPI:

char SPI_sendchar(char chr) {
     char receivedchar = 0;
     SPDR = chr;
     while(!(SPSR & (1< 
     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);                    //disable CS
     for(i=0; i <> 
       SPI_sendchar(0xFF);                // Send 10 * 8 = 80 clock pulses 400 kHz
     PORTB &= ~(_BV(CS));                 //enable CS
     for(i=0; i <> 
       SPI_sendchar(0xFF);                // Send 2 * 8 = 16 clock pulses 400 kHz
     Command(0x40,0,0,0x95);              // reset
idle_no:
     if (Command(0x41,0,0,0xFF) !=0) 
     goto idle_no;                        //idle = L?
     SPCR &= ~(_BV(SPR0));                //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 <> 
        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 <> 
        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 <> 
        while(!(SPSR & (1< 
        chars[i] = SPDR;
        SPDR = SPI_sendchar(0xFF);
    }
    SPI_sendchar(0xFF);
    SPI_sendchar(0xFF);
    return 0;
}

Adding all the codes:

#include 
#include 
#include 
 
#define FOSC 6400000
 
char chars[512];
 
int main(void) {
    ini_SPI();
    ini_SD();
    sei();
    
    write();
    read();
 
    return 0;
}

0 comments:

Post a Comment