Вы находитесь на странице: 1из 5

Reading and writing SD card using

Atmega16
by Binu June 3, 2014
This project explains how to read and write an SD card using an AVR microcontroller.
SD card

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 095. 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<<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); //disable CS
for(i=0; i < 10; i++)
SPI_sendchar(0xFF); // Send 10 * 8 = 80 clock pulses
400 kHz
PORTB &= ~(_BV(CS)); //enable CS
for(i=0; i < 2; 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 < 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;
}

Вам также может понравиться