-
Notifications
You must be signed in to change notification settings - Fork 2
/
sd_l0.cpp
210 lines (187 loc) · 4.78 KB
/
sd_l0.cpp
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
/* For AVR */
#if defined(__AVR__)
#include <avr/io.h>
#endif
/* For PIC32 */
#if defined(__PIC32MX__)
#include <DSPI.h>
#endif
#include <stdint.h>
#include "pins_arduino.h"
#include "sd_l0.h"
uint8_t SD_L0_CSPin;
DSPI0 spi;
/**
* Setup pins and SPI for operation with sd-card.
*
* Pin settings:
* - Set all pins for proper operation
* - power up card if needed
*
* SPI configuration:
* - enable uC for SPI master
* - typical no interrupts are used for SPI
* - data order: MSB is transmitted first
* - clock polarity: CLK is low when idle
* - clock phase: 1-0 > Sample, 0-1 > Setup
* - clock frequency: less than 400kHz
* (will be switched to higher value after initialization)
*
*/
void SD_L0_Init(void)
{
/* Power up card */
// not for arduino
/* Setup ports */
pinMode(SD_L0_CSPin, OUTPUT);
SD_L0_SetCSHigh();
// pinMode(SD_L0_SPI_MISO_PIN, INPUT);
// pinMode(SD_L0_SPI_MOSI_PIN, OUTPUT);
// pinMode(SD_L0_SPI_SCK_PIN, OUTPUT);
// pinMode(SD_L0_SPI_SS_FORCE_OUTPUT, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(SS, OUTPUT);
digitalWrite(SCK, LOW);
digitalWrite(MOSI, LOW);
digitalWrite(SS, HIGH);
/* Powering up takes at least 500us for capacitors to charge */
// not for arduino
/* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */
#if defined(__PIC32MX__)
spi.begin(SD_L0_CSPin);
spi.setSpeed(400000); //400kHz SCK
#else
SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
(1 << SPE) | /* SPI Enable */
(0 << DORD) | /* Data Order: MSB first */
(1 << MSTR) | /* Master mode */
(0 << CPOL) | /* Clock Polarity: SCK low when idle */
(0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
(1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
(1 << SPR0);
SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */
#endif
}
/**
* Setup pins and SPI for minimum power consumption.
* Deactivate SPI and power from card
*/
void SD_L0_DeInit(void)
{
#if defined(__PIC32MX__)
spi.end();
#else
SPCR &= ~(1 << SPE);
#endif
/* Setup ports */
/* for safe eject */
pinMode(SD_L0_CSPin, INPUT);
pinMode(MISO, INPUT);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
digitalWrite(SD_L0_CSPin, HIGH); // Set CS high
digitalWrite(SCK, HIGH);
/* Power down card */
// not for arduino
}
/**
* Set SPI for full operation speed (up to 25 MHz).
*
* Will be called after first part of card
* initialization was successful.
*/
void SD_L0_SpiSetHighSpeed(void)
{
#if defined(__PIC32MX__)
spi.setSpeed(10000000); //10MHz SCK
#else
SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */
SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */
#endif
}
/**
* Receives a raw byte from the SPI.
*
* \returns The byte which should be read.
*/
uint8_t SD_L0_SpiRecvByte()
{
/* send dummy data for receiving some */
#if defined(__PIC32MX__)
uint8_t rx;
rx = spi.transfer(0xFF);
return rx;
#else
SPDR = 0xff;
while(!(SPSR & (1 << SPIF)));
SPSR &= ~(1 << SPIF);
return SPDR;
#endif
}
/**
* Sends a raw byte to the SPI.
*
* \param[in] b The byte to sent.
*/
void SD_L0_SpiSendByte(uint8_t b)
{
#if defined(__PIC32MX__)
spi.transfer(b);
#else
SPDR = b;
/* wait for byte to be shifted out */
while(!(SPSR & (1 << SPIF)));
SPSR &= ~(1 << SPIF);
#endif
}
/**
* SPI read data - only one call so force inline
*
* Receives nbytes in buf. Send 0xff all the time.
*/
//inline __attribute__((always_inline))
void SD_L0_SpiRecvBlock(uint8_t *buf, uint16_t nbyte)
{
#if defined(__PIC32MX__)
spi.transfer(nbyte,0xFF,buf);
#else
if (nbyte-- == 0) return;
SPDR = 0xFF;
for (uint16_t i = 0; i < nbyte; i++) {
while (!(SPSR & (1 << SPIF)));
buf[i] = SPDR;
SPDR = 0xFF;
}
while (!(SPSR & (1 << SPIF)));
buf[nbyte] = SPDR;
#endif
}
/**
* SPI send block - only one call so force inline
*
* Sends the token and 512 data bytes from buffer afterwards.
*/
//inline __attribute__((always_inline))
void SD_L0_SpiSendBlock(uint8_t token, const uint8_t *buf) //>>was was "const uint8_t *buf"
{
#if defined(__PIC32MX__)
spi.transfer(token);
spi.transfer(512,(uint8_t*)buf);
#else
SPDR = token;
for (uint16_t i = 0; i < 512; i += 2) {
while (!(SPSR & (1 << SPIF)));
SPDR = buf[i];
while (!(SPSR & (1 << SPIF)));
SPDR = buf[i + 1];
}
while (!(SPSR & (1 << SPIF)));
#endif
}