-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
132 lines (102 loc) · 2.52 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <avr/io.h>
#include <util/delay.h>
// pin definitions
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define CS PINB2
#define MOSI PINB3
#define MISO PINB4
#define SCK PINB5
// macros
#define CS_ENABLE() PORT_SPI &= ~(1 << CS)
#define CS_DISABLE() PORT_SPI |= (1 << CS)
// command definitions
#define CMD0 0
#define CMD0_ARG 0x00000000
#define CMD0_CRC 0x94
// SPI functions
void SPI_init(void);
uint8_t SPI_transfer(uint8_t data);
// SD functions
void SD_powerUpSeq(void);
void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc);
uint8_t SD_readRes1(void);
uint8_t SD_goIdleState(void);
int main(void)
{
// initialize SPI
SPI_init();
// start power up sequence
SD_powerUpSeq();
// command card to idle
SD_goIdleState();
while(1);
}
void SPI_init()
{
// set CS, MOSI and SCK to output
DDR_SPI |= (1 << CS) | (1 << MOSI) | (1 << SCK);
// enable pull up resistor in MISO
DDR_SPI |= (1 << MISO);
// enable SPI, set as master, and clock to fosc/128
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
}
uint8_t SPI_transfer(uint8_t data)
{
// load data into register
SPDR = data;
// Wait for transmission complete
while(!(SPSR & (1 << SPIF)));
// return SPDR
return SPDR;
}
void SD_powerUpSeq()
{
// make sure card is deselected
CS_DISABLE();
// give SD card time to power up
_delay_ms(1);
// send 80 clock cycles to synchronize
for(uint8_t i = 0; i < 10; i++)
SPI_transfer(0xFF);
}
void SD_command(uint8_t cmd, uint32_t arg, uint8_t crc)
{
// transmit command to sd card
SPI_transfer(cmd|0x40);
// transmit argument
SPI_transfer((uint8_t)(arg >> 24));
SPI_transfer((uint8_t)(arg >> 16));
SPI_transfer((uint8_t)(arg >> 8));
SPI_transfer((uint8_t)(arg));
// transmit crc
SPI_transfer(crc|0x01);
}
uint8_t SD_readRes1()
{
uint8_t i = 0, res1;
// keep polling until actual data received
while((res1 = SPI_transfer(0xFF)) == 0xFF)
{
i++;
// if no data received for 8 bytes, break
if(i > 8) break;
}
return res1;
}
uint8_t SD_goIdleState()
{
// assert chip select
SPI_transfer(0xFF);
CS_ENABLE();
SPI_transfer(0xFF);
// send CMD0
SD_command(CMD0, CMD0_ARG, CMD0_CRC);
// read response
uint8_t res1 = SD_readRes1();
// deassert chip select
SPI_transfer(0xFF);
CS_DISABLE();
SPI_transfer(0xFF);
return res1;
}