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 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
#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;
}
No comments:
Post a Comment