1 /*
2 * Copyright (c) 2017-2020, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * ======== SDSPI.c ========
35 */
36
37 #include <stdint.h>
38 #include <stdbool.h>
39
40 #include <ti/drivers/dpl/ClockP.h>
41 #include <ti/drivers/dpl/HwiP.h>
42 #include <ti/drivers/dpl/SemaphoreP.h>
43 #include <ti/drivers/GPIO.h>
44 #include <ti/drivers/SD.h>
45 #include <ti/drivers/sd/SDSPI.h>
46 #include <ti/drivers/SPI.h>
47
48 /* Definitions for MMC/SDC command */
49 #define CMD0 (0x40+0) /* GO_IDLE_STATE */
50 #define CMD1 (0x40+1) /* SEND_OP_COND */
51 #define CMD8 (0x40+8) /* SEND_IF_COND */
52 #define CMD9 (0x40+9) /* SEND_CSD */
53 #define CMD10 (0x40+10) /* SEND_CID */
54 #define CMD12 (0x40+12) /* STOP_TRANSMISSION */
55 #define CMD16 (0x40+16) /* SET_BLOCKLEN */
56 #define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
57 #define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
58 #define CMD23 (0x40+23) /* SET_BLOCK_COUNT */
59 #define CMD24 (0x40+24) /* WRITE_BLOCK */
60 #define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
61 #define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */
62 #define CMD55 (0x40+55) /* APP_CMD */
63 #define CMD58 (0x40+58) /* READ_OCR */
64 #define START_BLOCK_TOKEN (0xFE)
65 #define START_MULTIBLOCK_TOKEN (0xFC)
66 #define STOP_MULTIBLOCK_TOKEN (0xFD)
67
68 #define SD_SECTOR_SIZE (512)
69
70 #define DRIVE_NOT_MOUNTED ((uint16_t) ~0)
71
72 void SDSPI_close(SD_Handle handle);
73 int_fast16_t SDSPI_control(SD_Handle handle, uint_fast16_t cmd,
74 void *arg);
75 uint_fast32_t SDSPI_getNumSectors(SD_Handle handle);
76 uint_fast32_t SDSPI_getSectorSize(SD_Handle handle);
77 int_fast16_t SDSPI_initialize(SD_Handle handle);
78 void SDSPI_init(SD_Handle handle);
79 SD_Handle SDSPI_open(SD_Handle handle, SD_Params *params);
80 int_fast16_t SDSPI_read(SD_Handle handle, void *buf,
81 int_fast32_t sector, uint_fast32_t sectorCount);
82 int_fast16_t SDSPI_write(SD_Handle handle, const void *buf,
83 int_fast32_t sector, uint_fast32_t sectorCount);
84
85 static inline void assertCS(SDSPI_HWAttrs const *hwAttrs);
86 static inline void deassertCS(SDSPI_HWAttrs const *hwAttrs);
87 static bool recvDataBlock(SPI_Handle handle, void *buf, uint32_t count);
88 static uint8_t sendCmd(SPI_Handle handle, uint8_t cmd, uint32_t arg);
89 static int_fast16_t spiTransfer(SPI_Handle handle, void *rxBuf,
90 void *txBuf, size_t count);
91 static bool waitUntilReady(SPI_Handle handle);
92 static bool transmitDataBlock(SPI_Handle handle, void *buf, uint32_t count,
93 uint8_t token);
94
95 /* SDSPI function table for SDSPI implementation */
96 const SD_FxnTable SDSPI_fxnTable = {
97 SDSPI_close,
98 SDSPI_control,
99 SDSPI_getNumSectors,
100 SDSPI_getSectorSize,
101 SDSPI_init,
102 SDSPI_initialize,
103 SDSPI_open,
104 SDSPI_read,
105 SDSPI_write
106 };
107
108 /*
109 * ======== SDSPI_close ========
110 */
SDSPI_close(SD_Handle handle)111 void SDSPI_close(SD_Handle handle)
112 {
113 SDSPI_Object *object = handle->object;
114
115 if (object->spiHandle) {
116 SPI_close(object->spiHandle);
117 object->spiHandle = NULL;
118 }
119
120 if (object->lockSem) {
121 SemaphoreP_delete(object->lockSem);
122 object->lockSem = NULL;
123 }
124
125 object->cardType = SD_NOCARD;
126 object->isOpen = false;
127 }
128
129 /*
130 * ======== SDSPI_control ========
131 */
SDSPI_control(SD_Handle handle,uint_fast16_t cmd,void * arg)132 int_fast16_t SDSPI_control(SD_Handle handle, uint_fast16_t cmd, void *arg)
133 {
134 return (SD_STATUS_UNDEFINEDCMD);
135 }
136
137 /*
138 * ======== SDSPI_getNumSectors ========
139 */
SDSPI_getNumSectors(SD_Handle handle)140 uint_fast32_t SDSPI_getNumSectors(SD_Handle handle)
141 {
142 uint8_t n;
143 uint8_t csd[16];
144 uint16_t csize;
145 uint32_t sectors = 0;
146 SDSPI_Object *object = handle->object;
147 SDSPI_HWAttrs const *hwAttrs = handle->hwAttrs;
148
149 SemaphoreP_pend(object->lockSem, SemaphoreP_WAIT_FOREVER);
150
151 assertCS(hwAttrs);
152
153 /* Get number of sectors on the disk (uint32_t) */
154 if ((sendCmd(object->spiHandle, CMD9, 0) == 0) &&
155 recvDataBlock(object->spiHandle, csd, 16)) {
156 /* SDC ver 2.00 */
157 if ((csd[0] >> 6) == 1) {
158 csize = csd[9] + (csd[8] << 8) + 1;
159 sectors = csize << 10;
160 }
161 /* MMC or SDC ver 1.XX */
162 else {
163 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) +
164 ((csd[9] & 3) << 1) + 2;
165
166 csize = (csd[8] >> 6) + ((uint16_t) csd[7] << 2) +
167 ((uint16_t) (csd[6] & 3) << 10) + 1;
168 sectors = (uint32_t)csize << (n - 9);
169 }
170 }
171
172 deassertCS(hwAttrs);
173
174 SemaphoreP_post(object->lockSem);
175
176 return (sectors);
177 }
178
179 /*
180 * ======== SDSPI_getSectorSize ========
181 */
SDSPI_getSectorSize(SD_Handle handle)182 uint_fast32_t SDSPI_getSectorSize(SD_Handle handle)
183 {
184 return (SD_SECTOR_SIZE);
185 }
186
187 /*
188 * ======== SDSPI_init ========
189 */
SDSPI_init(SD_Handle handle)190 void SDSPI_init(SD_Handle handle)
191 {
192 GPIO_init();
193 SPI_init();
194 }
195
196 /*
197 * ======== SDSPI_initialize ========
198 */
SDSPI_initialize(SD_Handle handle)199 int_fast16_t SDSPI_initialize(SD_Handle handle)
200 {
201 SD_CardType cardType = SD_NOCARD;
202 uint8_t i;
203 uint8_t ocr[4];
204 uint8_t txDummy[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
205 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
206 int_fast16_t status;
207 uint32_t currentTime;
208 uint32_t startTime;
209 uint32_t timeout;
210 SPI_Params spiParams;
211 SDSPI_Object *object = handle->object;
212 SDSPI_HWAttrs const *hwAttrs = handle->hwAttrs;
213
214 SemaphoreP_pend(object->lockSem, SemaphoreP_WAIT_FOREVER);
215
216 /*
217 * The CS line should not be asserted when attempting to put the
218 * SD card into SPI mode.
219 */
220 deassertCS(hwAttrs);
221
222 /*
223 * To put the SD card in SPI mode we must keep the TX line high while
224 * toggling the clock line several times. To do this we transmit 0xFF
225 * 10 times. Do not assert CS during this time
226 */
227 status = spiTransfer(object->spiHandle, NULL, &txDummy, 10);
228 if (status != SD_STATUS_SUCCESS) {
229 SemaphoreP_post(object->lockSem);
230 return (status);
231 }
232
233 /* Now select the SD Card's chip select to send CMD0 command */
234 assertCS(hwAttrs);
235
236 /*
237 * Send CMD0 to put the SD card in idle mode. Depending on the previous
238 * state of the SD card, this may take up to a couple hundred milliseconds.
239 * Rather than delay between attempts, we try up to 255 attempts.
240 * Failure is returned if the card does not respond will a valid byte
241 * within 255 attempts. When the card will respond with 0x1 when its
242 * in idle mode.
243 */
244 for (i = 255, status = 0xFF; i > 0 && status != 0x1; i--) {
245 status = sendCmd(object->spiHandle, CMD0, 0);
246 }
247
248 /* If the card never transitioned into idle mode */
249 if (status != 0x1) {
250 deassertCS(hwAttrs);
251 SemaphoreP_post(object->lockSem);
252 return (SD_STATUS_ERROR);
253 }
254
255 /*
256 * Proceed with initialization since the SD Card is in the idle state
257 * Determine what SD Card version we are dealing with
258 * Depending on which SD Card version, we need to send different SD
259 * commands to the SD Card, which will have different response fields.
260 */
261 if (sendCmd(object->spiHandle, CMD8, 0x1AA) == 1) {
262 /* SD Version 2.0 or higher */
263 status = spiTransfer(object->spiHandle, &ocr, &txDummy, 4);
264 if (status == SD_STATUS_SUCCESS) {
265 /*
266 * Ensure that the card's voltage range is valid
267 * The card can work at VDD range of 2.7-3.6V
268 */
269 if ((ocr[2] == 0x01) && (ocr[3] == 0xAA)) {
270 /*
271 * Wait for data packet in timeout of 1s - status used to
272 * indicate if a timeout occurred before operation
273 * completed.
274 */
275 status = SD_STATUS_ERROR;
276 timeout = 1000000/ClockP_getSystemTickPeriod();
277 startTime = ClockP_getSystemTicks();
278
279 do {
280 /* ACMD41 with HCS bit */
281 if ((sendCmd(object->spiHandle, CMD55, 0) <= 1) &&
282 (sendCmd(object->spiHandle, CMD41, 1UL << 30) == 0)) {
283 status = SD_STATUS_SUCCESS;
284 break;
285 }
286 currentTime = ClockP_getSystemTicks();
287 } while ((currentTime - startTime) < timeout);
288
289 /*
290 * Check CCS bit to determine which type of capacity we are
291 * dealing with
292 */
293 if ((status == SD_STATUS_SUCCESS) &&
294 sendCmd(object->spiHandle, CMD58, 0) == 0) {
295 status = spiTransfer(object->spiHandle, &ocr, &txDummy, 4);
296 if (status == SD_STATUS_SUCCESS) {
297 cardType = (ocr[0] & 0x40) ? SD_SDHC : SD_SDSC;
298 }
299 }
300 }
301 }
302 }
303 else {
304 /* SDC Version 1 or MMC */
305 /*
306 * The card version is not SDC V2+ so check if we are dealing with a
307 * SDC or MMC card
308 */
309 if ((sendCmd(object->spiHandle, CMD55, 0) <= 1) &&
310 (sendCmd(object->spiHandle, CMD41, 0) <= 1)) {
311 cardType = SD_SDSC;
312 }
313 else {
314 cardType = SD_MMC;
315 }
316
317 /*
318 * Wait for data packet in timeout of 1s - status used to
319 * indicate if a timeout occurred before operation
320 * completed.
321 */
322 status = SD_STATUS_ERROR;
323 timeout = 1000000/ClockP_getSystemTickPeriod();
324 startTime = ClockP_getSystemTicks();
325 do {
326 if (cardType == SD_SDSC) {
327 /* ACMD41 */
328 if ((sendCmd(object->spiHandle, CMD55, 0) <= 1) &&
329 (sendCmd(object->spiHandle, CMD41, 0) == 0)) {
330 status = SD_STATUS_SUCCESS;
331 break;
332 }
333 }
334 else {
335 /* CMD1 */
336 if (sendCmd(object->spiHandle, CMD1, 0) == 0) {
337 status = SD_STATUS_SUCCESS;
338 break;
339 }
340 }
341 currentTime = ClockP_getSystemTicks();
342 } while ((currentTime - startTime) < timeout);
343
344 /* Select R/W block length */
345 if ((status == SD_STATUS_ERROR) ||
346 (sendCmd(object->spiHandle, CMD16, SD_SECTOR_SIZE) != 0)) {
347 cardType = SD_NOCARD;
348 }
349 }
350
351 deassertCS(hwAttrs);
352
353 object->cardType = cardType;
354
355 /* Check to see if a card type was determined */
356 if (cardType == SD_NOCARD) {
357 status = SD_STATUS_ERROR;
358 }
359 else {
360 /* Reconfigure the SPI to operate @ 2.5 MHz */
361 SPI_close(object->spiHandle);
362
363 SPI_Params_init(&spiParams);
364 spiParams.bitRate = 2500000;
365 object->spiHandle = SPI_open(hwAttrs->spiIndex, &spiParams);
366 status = (object->spiHandle == NULL) ? SD_STATUS_ERROR :
367 SD_STATUS_SUCCESS;
368 }
369
370 SemaphoreP_post(object->lockSem);
371
372 return (status);
373 }
374
375 /*
376 * ======== SDSPI_open ========
377 */
SDSPI_open(SD_Handle handle,SD_Params * params)378 SD_Handle SDSPI_open(SD_Handle handle, SD_Params *params)
379 {
380 uintptr_t key;
381 int_fast16_t status;
382 SPI_Params spiParams;
383 SDSPI_Object *object = handle->object;
384 SDSPI_HWAttrs const *hwAttrs = handle->hwAttrs;
385
386 key = HwiP_disable();
387
388 if (object->isOpen) {
389 HwiP_restore(key);
390
391 return (NULL);
392 }
393 object->isOpen = true;
394
395 HwiP_restore(key);
396
397 /* Configure the SPI CS pin as output set high */
398 status = GPIO_setConfig(hwAttrs->spiCsGpioIndex,
399 GPIO_CFG_OUT_STD | GPIO_CFG_OUT_HIGH);
400 if (status != GPIO_STATUS_SUCCESS) {
401 object->isOpen = false;
402
403 return (NULL);
404 }
405
406 object->lockSem = SemaphoreP_createBinary(1);
407 if (object->lockSem == NULL) {
408 object->isOpen = false;
409
410 return (NULL);
411 }
412
413 /*
414 * SPI is initially set to 400 kHz to perform SD initialization. This is
415 * is done to ensure compatibility with older SD cards. Once the card has
416 * been initialized (in SPI mode) the SPI peripheral will be closed &
417 * reopened at 2.5 MHz.
418 */
419 SPI_Params_init(&spiParams);
420 spiParams.bitRate = 400000;
421 object->spiHandle = SPI_open(hwAttrs->spiIndex, &spiParams);
422 if (object->spiHandle == NULL) {
423 SDSPI_close(handle);
424
425 return (NULL);
426 }
427
428 /* Ensure the CS line is de-asserted. */
429 deassertCS(hwAttrs);
430
431 return (handle);
432 }
433
434 /*
435 * ======== SDSPI_read ========
436 */
SDSPI_read(SD_Handle handle,void * buf,int_fast32_t sector,uint_fast32_t sectorCount)437 int_fast16_t SDSPI_read(SD_Handle handle, void *buf, int_fast32_t sector,
438 uint_fast32_t sectorCount)
439 {
440 uint8_t ffByte = 0xFF;
441 int_fast16_t status = SD_STATUS_ERROR;
442 SDSPI_Object *object = handle->object;
443 SDSPI_HWAttrs const *hwAttrs = handle->hwAttrs;
444
445 if (sectorCount == 0) {
446 return (SD_STATUS_ERROR);
447 }
448
449 SemaphoreP_pend(object->lockSem, SemaphoreP_WAIT_FOREVER);
450
451 /*
452 * On a SDSC card, the sector address is a byte address on the SD Card
453 * On a SDHC card, the sector addressing is via sector blocks
454 */
455 if (object->cardType != SD_SDHC) {
456 /* Convert to byte address */
457 sector *= SD_SECTOR_SIZE;
458 }
459
460 assertCS(hwAttrs);
461
462 /* Single block read */
463 if (sectorCount == 1) {
464 if ((sendCmd(object->spiHandle, CMD17, sector) == 0) &&
465 recvDataBlock(object->spiHandle, buf, SD_SECTOR_SIZE)) {
466 status = SD_STATUS_SUCCESS;
467 }
468 }
469 /* Multiple block read */
470 else {
471 if (sendCmd(object->spiHandle, CMD18, sector) == 0) {
472 do {
473 if (!recvDataBlock(object->spiHandle, buf, SD_SECTOR_SIZE)) {
474 break;
475 }
476 buf = (void *) (((uint32_t) buf) + SD_SECTOR_SIZE);
477 } while (--sectorCount);
478
479 /*
480 * STOP_TRANSMISSION - order is important; always want to send
481 * stop signal
482 */
483 if (sendCmd(object->spiHandle, CMD12, 0) == 0 && sectorCount == 0) {
484 status = SD_STATUS_SUCCESS;
485 }
486 }
487 }
488
489 deassertCS(hwAttrs);
490
491 /* Send a 0xFF with CS high to try to put SD card into low power mode */
492 spiTransfer(object->spiHandle, NULL, &ffByte, 1);
493
494 SemaphoreP_post(object->lockSem);
495
496 return (status);
497 }
498
499 /*
500 * ======== SDSPI_write ========
501 */
SDSPI_write(SD_Handle handle,const void * buf,int_fast32_t sector,uint_fast32_t sectorCount)502 int_fast16_t SDSPI_write(SD_Handle handle, const void *buf,
503 int_fast32_t sector, uint_fast32_t sectorCount)
504 {
505 int_fast16_t status = SD_STATUS_SUCCESS;
506 SDSPI_Object *object = handle->object;
507 SDSPI_HWAttrs const *hwAttrs = handle->hwAttrs;
508
509 if (sectorCount == 0) {
510 return (SD_STATUS_ERROR);
511 }
512
513 SemaphoreP_pend(object->lockSem, SemaphoreP_WAIT_FOREVER);
514
515 /*
516 * On a SDSC card, the sector address is a byte address on the SD Card
517 * On a SDHC card, the sector addressing is via sector blocks
518 */
519 if (object->cardType != SD_SDHC) {
520 /* Convert to byte address if needed */
521 sector *= SD_SECTOR_SIZE;
522 }
523
524 assertCS(hwAttrs);
525
526 /* Single block write */
527 if (sectorCount == 1) {
528 if ((sendCmd(object->spiHandle, CMD24, sector) == 0) &&
529 transmitDataBlock(object->spiHandle, (void *) buf, SD_SECTOR_SIZE,
530 START_BLOCK_TOKEN)) {
531 sectorCount = 0;
532 }
533 }
534 /* Multiple block write */
535 else {
536 if ((object->cardType == SD_SDSC) || (object->cardType == SD_SDHC)) {
537 if (sendCmd(object->spiHandle, CMD55, 0) != 0) {
538 status = SD_STATUS_ERROR;
539 }
540
541 /* ACMD23 */
542 if ((status == SD_STATUS_SUCCESS) &&
543 (sendCmd(object->spiHandle, CMD23, sectorCount) != 0)) {
544 status = SD_STATUS_ERROR;
545 }
546 }
547
548 /* WRITE_MULTIPLE_BLOCK command */
549 if ((status == SD_STATUS_SUCCESS) &&
550 (sendCmd(object->spiHandle, CMD25, sector) == 0)) {
551 do {
552 if (!transmitDataBlock(object->spiHandle, (void *) buf,
553 SD_SECTOR_SIZE, START_MULTIBLOCK_TOKEN)) {
554 break;
555 }
556 buf = (void *) (((uint32_t) buf) + SD_SECTOR_SIZE);
557 } while (--sectorCount);
558
559 /* STOP_TRAN token */
560 if (!transmitDataBlock(object->spiHandle, NULL, 0,
561 STOP_MULTIBLOCK_TOKEN)) {
562 sectorCount = 1;
563 }
564 }
565 }
566
567 /*
568 * Wait for SD card to finish storing the data it received. This may help
569 * the card go into low power mode.
570 */
571 waitUntilReady(object->spiHandle);
572
573 deassertCS(hwAttrs);
574
575 SemaphoreP_post(object->lockSem);
576
577 return ((sectorCount) ? SD_STATUS_ERROR : SD_STATUS_SUCCESS);
578 }
579
580 /*
581 * ======== assertCS ========
582 */
assertCS(SDSPI_HWAttrs const * hwAttrs)583 static inline void assertCS(SDSPI_HWAttrs const *hwAttrs)
584 {
585 GPIO_write(hwAttrs->spiCsGpioIndex, 0);
586 }
587
588 /*
589 * ======== deassertCS ========
590 */
deassertCS(SDSPI_HWAttrs const * hwAttrs)591 static inline void deassertCS(SDSPI_HWAttrs const *hwAttrs)
592 {
593 GPIO_write(hwAttrs->spiCsGpioIndex, 1);
594 }
595
596 /*
597 * ======== recvDataBlock ========
598 * Function to receive a block of data from the SDCard
599 */
recvDataBlock(SPI_Handle handle,void * buf,uint32_t count)600 static bool recvDataBlock(SPI_Handle handle, void *buf, uint32_t count)
601 {
602 uint8_t rxBuf[2];
603 uint8_t txBuf[2] = {0xFF, 0xFF};
604 int_fast16_t status;
605 uint32_t currentTime;
606 uint32_t startTime;
607 uint32_t timeout;
608
609 /*
610 * Wait for SD card to be ready up to 1s. SD card is ready when the
611 * START_BLOCK_TOKEN is received.
612 */
613 timeout = 1000000/ClockP_getSystemTickPeriod();
614 startTime = ClockP_getSystemTicks();
615 do {
616 status = spiTransfer(handle, &rxBuf, &txBuf, 1);
617 currentTime = ClockP_getSystemTicks();
618 } while ((status == SD_STATUS_SUCCESS) && (rxBuf[0] == 0xFF) &&
619 (currentTime - startTime) < timeout);
620
621 if (rxBuf[0] != START_BLOCK_TOKEN) {
622 /* Return error if valid data token was not received */
623 return (false);
624 }
625
626 /* Receive the data block into buffer */
627 if (spiTransfer(handle, buf, NULL, count) != SD_STATUS_SUCCESS) {
628 return (false);
629 }
630
631 /* Read the 16 bit CRC, but discard it */
632 if (spiTransfer(handle, &rxBuf, &txBuf, 2) != SD_STATUS_SUCCESS) {
633 return (false);
634 }
635
636 /* Return with success */
637 return (true);
638 }
639
640 /*
641 * ======== sendCmd ========
642 * Function to send a command to the SD card. Command responses from
643 * SD card are returned. (0xFF) is returned on failures.
644 */
sendCmd(SPI_Handle handle,uint8_t cmd,uint32_t arg)645 static uint8_t sendCmd(SPI_Handle handle, uint8_t cmd, uint32_t arg)
646 {
647 uint8_t i;
648 uint8_t rxBuf;
649 uint8_t txBuf[6];
650 int_fast16_t status;
651
652 if ((cmd != CMD0) && !waitUntilReady(handle)) {
653 return (0xFF);
654 }
655
656 /* Setup SPI transaction */
657 txBuf[0] = cmd; /* Command */
658 txBuf[1] = (uint8_t)(arg >> 24); /* Argument[31..24] */
659 txBuf[2] = (uint8_t)(arg >> 16); /* Argument[23..16] */
660 txBuf[3] = (uint8_t)(arg >> 8); /* Argument[15..8] */
661 txBuf[4] = (uint8_t) arg; /* Argument[7..0] */
662
663 if (cmd == CMD0) {
664 /* CRC for CMD0(0) */
665 txBuf[5] = 0x95;
666 }
667 else if (cmd == CMD8) {
668 /* CRC for CMD8(0x1AA) */
669 txBuf[5] = 0x87;
670 }
671 else {
672 /* Default CRC should be at least 0x01 */
673 txBuf[5] = 0x01;
674 }
675
676 if (spiTransfer(handle, NULL, &txBuf, 6) != SD_STATUS_SUCCESS) {
677 return (0xFF);
678 }
679
680 /* Prepare to receive SD card response (send 0xFF) */
681 txBuf[0] = 0xFF;
682
683 /*
684 * CMD 12 has R1b response which transfers an additional
685 * "busy" byte
686 */
687 if ((cmd == CMD12) &&
688 (spiTransfer(handle, &rxBuf, &txBuf, 1) != SD_STATUS_SUCCESS)) {
689 return (0xFF);
690 }
691
692 /* Wait for a valid response; 10 attempts */
693 i = 10;
694 do {
695 status = spiTransfer(handle, &rxBuf, &txBuf, 1);
696 } while ((status == SD_STATUS_SUCCESS) && (rxBuf & 0x80) && (--i));
697
698 /* Return with the response value */
699 return (rxBuf);
700 }
701
702 /*
703 * ======== spiTransfer ========
704 * Returns SD_STATUS_SUCCESS when transfer is completed;
705 * SD_STATUS_ERROR otherwise.
706 */
spiTransfer(SPI_Handle handle,void * rxBuf,void * txBuf,size_t count)707 static int_fast16_t spiTransfer(SPI_Handle handle, void *rxBuf,
708 void *txBuf, size_t count) {
709 int_fast16_t status;
710 SPI_Transaction transaction;
711
712 transaction.rxBuf = rxBuf;
713 transaction.txBuf = txBuf;
714 transaction.count = count;
715
716 status = (SPI_transfer(handle, &transaction)) ?
717 SD_STATUS_SUCCESS : SD_STATUS_ERROR;
718
719 return (status);
720 }
721
722 /*
723 * ======== transmitDataBlock ========
724 * Function to transmit a block of data to the SD card. A valid command
725 * token must be sent to the SD card prior to sending the data block.
726 * The available tokens are:
727 * START_BLOCK_TOKEN
728 * START_MULTIBLOCK_TOKEN
729 * STOP_MULTIBLOCK_TOKEN
730 */
transmitDataBlock(SPI_Handle handle,void * buf,uint32_t count,uint8_t token)731 static bool transmitDataBlock(SPI_Handle handle, void *buf, uint32_t count,
732 uint8_t token)
733 {
734 uint8_t rxBuf;
735 uint8_t txBuf[2] = {0xFF, 0xFF};
736
737 if (!waitUntilReady(handle)) {
738 return (false);
739 }
740
741 /* transmit data token */
742 txBuf[0] = token;
743 if (spiTransfer(handle, NULL, &txBuf, 1) != SD_STATUS_SUCCESS) {
744 return (false);
745 }
746
747 /* Send data only when token != STOP_MULTIBLOCK_TOKEN */
748 if (token != STOP_MULTIBLOCK_TOKEN) {
749 /* Write data to the SD card */
750 if (spiTransfer(handle, NULL, buf, count) != SD_STATUS_SUCCESS) {
751 return (false);
752 }
753
754 /* Receive the 16 bit CRC, but discard it */
755 txBuf[0] = (0xFF);
756 if (spiTransfer(handle, NULL, &txBuf, 2) != SD_STATUS_SUCCESS) {
757 return (false);
758 }
759
760 /* Receive data response token from SD card */
761 if (spiTransfer(handle, &rxBuf, &txBuf, 1) != SD_STATUS_SUCCESS) {
762 return (false);
763 }
764
765 /* Check data response; return error if data was rejected */
766 if ((rxBuf & 0x1F) != 0x05) {
767 return (false);
768 }
769 }
770
771 return (true);
772 }
773
774 /*
775 * ======== waitUntilReady ========
776 * Function to check if the SD card is busy.
777 *
778 * Returns true if SD card is ready; false indicates the SD card is still busy
779 * & a timeout occurred.
780 */
waitUntilReady(SPI_Handle handle)781 static bool waitUntilReady(SPI_Handle handle)
782 {
783 uint8_t rxDummy;
784 uint8_t txDummy = 0xFF;
785 int_fast16_t status;
786 uint32_t currentTime;
787 uint32_t startTime;
788 uint32_t timeout;
789
790 /* Wait up to 1s for data packet */
791 timeout = 1000000/ClockP_getSystemTickPeriod();
792 startTime = ClockP_getSystemTicks();
793 do {
794 status = spiTransfer(handle, &rxDummy, &txDummy, 1);
795 currentTime = ClockP_getSystemTicks();
796 } while ((status == SD_STATUS_SUCCESS) && (rxDummy != 0xFF) &&
797 (currentTime - startTime) < timeout);
798
799 return (rxDummy == 0xFF);
800 }
801