COSA
An Object-Oriented Platform for Arduino Programming
SD.cpp
Go to the documentation of this file.
1 
21 #include "SD.hh"
22 #include "Cosa/RTT.hh"
23 
24 // Configuration: Allow SPI transfer interleaving, table driven CRC.
25 #define USE_SPI_PREFETCH
26 #define USE_CRCTAB
27 
28 static inline uint8_t crc7(const void* buf, size_t size)
29  __attribute__((always_inline));
30 
31 static inline uint8_t
32 crc7(const void* buf, size_t size)
33 {
34  uint8_t* bp = (uint8_t*) buf;
35  uint8_t crc = 0;
36  while (size--) {
37  uint8_t data = *bp++;
38  data ^= crc << 1;
39  if (data & 0x80) data ^= 9;
40  crc = data ^ (crc & 0x78) ^ (crc << 4) ^ ((crc >> 3) & 0x0f);
41  }
42  crc = (crc << 1) ^ (crc << 4) ^ (crc & 0x70) ^ ((crc >> 3) & 0x0f);
43  return (crc | 1);
44 }
45 
46 #if defined(USE_CRCTAB)
47 static const uint16_t crctab[] __PROGMEM = {
48  0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
49  0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
50  0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
51  0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
52  0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
53  0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
54  0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
55  0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
56  0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
57  0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
58  0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
59  0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
60  0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
61  0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
62  0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
63  0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
64  0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
65  0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
66  0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
67  0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
68  0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
69  0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
70  0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
71  0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
72  0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
73  0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
74  0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
75  0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
76  0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
77  0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
78  0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
79  0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
80 };
81 
82 static inline uint16_t _crc_xmodem_update(uint16_t crc, uint8_t data)
83  __attribute__((always_inline));
84 
85 static inline uint16_t
86 _crc_xmodem_update(uint16_t crc, uint8_t data)
87 {
88  return (pgm_read_word(&crctab[((crc >> 8) ^ data) & 0Xff]) ^ (crc << 8));
89 }
90 
91 #else
92 #include <util/crc16.h>
93 #endif
94 
95 uint8_t
96 SD::send(CMD command, uint32_t arg)
97 {
98  // Build request with command, argument and add check-sum (CRC7)
99  request_t request;
100  request.command = (0x40 | command);
101  request.arg = swap(arg);
102  request.crc = crc7(&request, sizeof(request) - 1);
103 
104  // Issue the command; wait while busy
105  while (spi.transfer(0xff) != 0xff)
106  ;
107  spi.transfer(&request, sizeof(request));
108  if (command == STOP_TRANSMISSION) spi.transfer(0xff);
109 
110  // Wait for the response
111  uint8_t response;
112  for (uint8_t i = 0; i < RESPONSE_RETRY; i++) {
113  response = spi.transfer(0xff);
114  if ((response & 0x80) == 0) break;
115  }
116  return (m_response = response);
117 }
118 
119 bool
120 SD::send(uint16_t ms, CMD command, uint32_t arg)
121 {
122  uint16_t start = RTT::millis();
123  do {
124  uint8_t state = send(command, arg);
125  if (state < IDENT_STATE) return (true);
126  } while (((uint16_t) RTT::millis()) - start < ms);
127  return (false);
128 }
129 
130 uint8_t
131 SD::send(ACMD command, uint32_t arg)
132 {
133  send(APP_CMD);
134  return (send((CMD) command, arg));
135 }
136 
137 bool
138 SD::send(uint16_t ms, ACMD command, uint32_t arg)
139 {
140  uint16_t start = RTT::millis();
141  do {
142  send(APP_CMD);
143  uint8_t state = send((CMD) command, arg);
144  if (state < IDENT_STATE) return (true);
145  } while (((uint16_t) RTT::millis()) - start < ms);
146  return (false);
147 }
148 
149 bool
150 SD::await(uint16_t ms, uint8_t token)
151 {
152  uint16_t start = RTT::millis();
153  do {
154  uint8_t response = spi.transfer(0xff);
155  if (response != 0xff) {
156  m_response = response;
157  return (token != 0 ? response == token : true);
158  }
159  } while ((ms == 0) || (((uint16_t) RTT::millis()) - start < ms));
160  return (false);
161 }
162 
163 uint32_t
165 {
166  univ32_t res;
167 #if defined(USE_SPI_PREFETCH)
168  spi.transfer_start(0xff);
169  res.as_uint8[3] = spi.transfer_next(0xff);
170  res.as_uint8[2] = spi.transfer_next(0xff);
171  res.as_uint8[1] = spi.transfer_next(0xff);
172  res.as_uint8[0] = spi.transfer_await();
173 #else
174  res.as_uint8[3] = spi.transfer(0xff);
175  res.as_uint8[2] = spi.transfer(0xff);
176  res.as_uint8[1] = spi.transfer(0xff);
177  res.as_uint8[0] = spi.transfer(0xff);
178 #endif
179  return (res.as_uint32);
180 }
181 
182 bool
183 SD::read(CMD command, uint32_t arg, void* buf, size_t count)
184 {
185  uint8_t* dst = (uint8_t*) buf;
186  uint16_t crc = 0;
187  bool res = false;
188  uint8_t data;
189 
190  // Issue read command and receive data into buffer
191  spi.acquire(this);
192  spi.begin();
193  if (send(command, arg)) goto error;
194  if (!await(READ_TIMEOUT, DATA_START_BLOCK)) goto error;
195 
196 #if defined(USE_SPI_PREFETCH)
197  spi.transfer_start(0xff);
198  while (--count) {
199  data = spi.transfer_next(0xff);
200  *dst++ = data;
201  crc = _crc_xmodem_update(crc, data);
202  }
203  data = spi.transfer_await();
204  *dst = data;
205  crc = _crc_xmodem_update(crc, data);
206 #else
207  do {
208  uint8_t data = spi.transfer(0xff);
209  *dst++ = data;
210  crc = _crc_xmodem_update(crc, data);
211  } while (--count);
212 #endif
213 
214  // Receive the check sum and check
215  crc = _crc_xmodem_update(crc, spi.transfer(0xff));
216  crc = _crc_xmodem_update(crc, spi.transfer(0xff));
217  res = (crc == 0);
218 
219  error:
220  spi.end();
221  spi.release();
222  return (res);
223 }
224 
225 bool
227 {
228  bool res = false;
229  uint32_t arg;
230  R1 status;
231 
232  // Start with unknown card type
234 
235  spi.acquire(this);
236  spi.begin();
237  // Card needs 74 cycles minimum to start up
238  for (uint8_t i = 0; i < INIT_PULSES; i++) spi.transfer(0xff);
239 
240  // Reset card
241  if (!send(INIT_TIMEOUT, GO_IDLE_STATE)) goto error;
242 
243  // Enable CRC
244  status = send(CRC_ON_OFF, true);
245  if (status.is_error()) goto error;
246 
247  // Check for version of SD card specification; 2.7-3.6V and check pattern
248  m_type = TYPE_SD1;
249  arg = (0x100 | CHECK_PATTERN);
250  status = send(SEND_IF_COND, arg);
251  if (status.in_idle_state) {
252  R7 r7 = receive();
253  if (r7.check_pattern != CHECK_PATTERN) goto error;
254  m_type = TYPE_SD2;
255  }
256 
257  // Tell the device that the host supports SDHC
258  arg = (m_type == TYPE_SD1) ? 0L : 0X40000000L;
259  for (uint8_t i = 0; i < INIT_RETRY; i++) {
260  if (!send(INIT_TIMEOUT, SD_SEND_OP_COND, arg)) goto error;
261  if (m_response == 0) break;
262  }
263 
264  // Read OCR register and check type
265  if (m_type == TYPE_SD2) {
266  status = send(READ_OCR);
267  if (status.is_error()) goto error;
268  uint32_t ocr = receive();
269  if ((ocr & 0xC0000000L) == 0xC0000000L) m_type = TYPE_SDHC;
270  }
271 
272  // Set the request clock rate
273  set_clock(rate);
274  res = true;
275 
276  error:
277  spi.end();
278  spi.release();
279  return (res);
280 }
281 
282 bool
284 {
285  return (true);
286 }
287 
288 bool
289 SD::erase(uint32_t start, uint32_t end)
290 {
291  bool res = false;
292 
293  // Check if block address should be mapped to byte address
294  if (m_type != TYPE_SDHC) {
295  start <<= 9;
296  end <<= 9;
297  }
298 
299  // Send commands for block erase
300  spi.acquire(this);
301  spi.begin();
302  if (send(ERASE_WR_BLK_START, start)) goto error;
303  if (send(ERASE_WR_BLK_END, end)) goto error;
304  if (send(ERASE)) goto error;
305  if (!await(ERASE_TIMEOUT)) goto error;
306  res = true;
307  error:
308  spi.end();
309  spi.release();
310  return (res);
311 }
312 
313 bool
314 SD::write(uint32_t block, const uint8_t* src)
315 {
316  uint16_t crc = 0;
317  uint16_t count = BLOCK_MAX;
318  uint8_t status;
319  uint8_t data;
320  bool res = false;
321 
322  // Check for byte address adjustment
323  if (m_type != TYPE_SDHC) block <<= 9;
324 
325  // Issue write block command, transfer block, calculate check sum
326  spi.acquire(this);
327  spi.begin();
328  if (send(WRITE_BLOCK, block)) goto error;
330 
331 #if defined(USE_SPI_PREFETCH)
332  data = *src++;
333  spi.transfer_start(data);
334  while (--count) {
335  crc = _crc_xmodem_update(crc, data);
336  data = *src++;
338  spi.transfer_start(data);
339  }
340  crc = _crc_xmodem_update(crc, data);
342 #else
343  do {
344  data = *src++;
345  spi.transfer(data);
346  crc = _crc_xmodem_update(crc, data);
347  } while (--count);
348 #endif
349 
350  // Transfer the check sum and receive data response token and check status
351  spi.transfer(crc >> 8);
352  spi.transfer(crc);
353  status = spi.transfer(0xff);
354  if ((status & DATA_RES_MASK) != DATA_RES_ACCEPTED) goto error;
355 
356  // Wait for the write operation to complete and check status
357  if (!await(WRITE_TIMEOUT)) goto error;
358  status = send(SEND_STATUS);
359  if (status != 0) goto error;
360  status = spi.transfer(0xff);
361  res = (status == 0);
362 
363  error:
364  spi.end();
365  spi.release();
366  return (res);
367 }
368 
uint8_t as_uint8[4]
Definition: Types.h:136
static uint16_t _crc_xmodem_update(uint16_t crc, uint8_t data)
Definition: SD.cpp:86
uint8_t transfer(uint8_t data)
Definition: SOFT_SPI.cpp:87
uint8_t crc
Definition: SD.hh:294
Clock
Definition: SPI.hh:60
bool is_error() const
Definition: SD.hh:225
bool erase(uint32_t start, uint32_t end)
Definition: SD.cpp:289
static uint8_t crc7(const void *buf, size_t size)
Definition: SD.cpp:32
static const uint16_t ERASE_TIMEOUT
Definition: SD.hh:299
static const uint16_t WRITE_TIMEOUT
Definition: SD.hh:301
Definition: SD.hh:266
static const size_t BLOCK_MAX
Definition: SD.hh:38
Turns the CRC on/off.
Definition: SD.hh:184
uint8_t in_idle_state
Definition: SD.hh:215
static const uint8_t INIT_RETRY
Definition: SD.hh:307
CARD m_type
Definition: SD.hh:314
void acquire(Driver *dev)
Definition: SOFT_SPI.cpp:43
void set_clock(Clock rate)
Definition: SPI.cpp:297
static const uint8_t INIT_PULSES
Definition: SD.hh:304
Write block length bytes.
Definition: SD.hh:171
Next command is application specific command.
Definition: SD.hh:181
bool write(uint32_t block, const uint8_t *src)
Definition: SD.cpp:314
Definition: SD.hh:212
Reset the SD Memory Card.
Definition: SD.hh:152
Sends SD Memory Card interface condition.
Definition: SD.hh:158
uint8_t transfer_next(uint8_t data)
Definition: SPI.hh:261
static const uint8_t CHECK_PATTERN
Definition: SD.hh:278
static const uint16_t INIT_TIMEOUT
Definition: SD.hh:298
uint32_t arg
Definition: SD.hh:293
uint8_t check_pattern
Definition: SD.hh:269
Set first write block to be erased.
Definition: SD.hh:177
Asks the selected card status register.
Definition: SD.hh:163
ACMD
Definition: SD.hh:188
static uint32_t millis()
Definition: RTT.cpp:121
CMD
Definition: SD.hh:151
uint32_t as_uint32
Definition: Types.h:131
void begin()
Definition: SPI.hh:216
#define swap(a, b)
Definition: Canvas.cpp:164
bool await(uint16_t ms=0, uint8_t token=0)
Definition: SD.cpp:150
void end()
Definition: SPI.hh:226
uint8_t m_response
Definition: SD.hh:311
bool read(CMD command, uint32_t arg, void *buf, size_t count)
Definition: SD.cpp:183
uint8_t transfer_await()
Definition: SPI.hh:249
static const uint16_t READ_TIMEOUT
Definition: SD.hh:300
bool begin(SPI::Clock rate=SPI::DIV128_CLOCK)
Definition: SD.cpp:226
static const uint8_t RESPONSE_RETRY
Definition: SD.hh:308
Set last write block to be erased.
Definition: SD.hh:178
Host capacity support information.
Definition: SD.hh:193
static const uint16_t crctab[] __PROGMEM
Definition: SD.cpp:47
Read OCR register of a card.
Definition: SD.hh:183
void transfer_start(uint8_t data)
Definition: SPI.hh:238
bool end()
Definition: SD.cpp:283
SPI spi
Definition: SPI.cpp:29
void release()
Definition: SOFT_SPI.cpp:64
uint8_t send(CMD command, uint32_t arg=0L)
Definition: SD.cpp:96
Stop Multiple Block Read.
Definition: SD.hh:162
uint8_t command
Definition: SD.hh:292
Erases selected write blocks.
Definition: SD.hh:179
uint32_t receive()
Definition: SD.cpp:164