]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/mmc.c
Integrate fatfs. Add some sd card test commands.
[z180-stamp.git] / avr / mmc.c
CommitLineData
7f552300
L
1/*-----------------------------------------------------------------------*/
2/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2007 */
3/*-----------------------------------------------------------------------*/
4/* Only spi_rcvr(), spi_xmit(), disk_timerproc() and some macros */
5/* are platform dependent. */
6/*-----------------------------------------------------------------------*/
7
8#include <avr/io.h>
9#include <stdbool.h>
10#include "timer.h"
11#include "spi.h"
12#include "diskio.h"
13#include "debug.h"
14#include "print-utils.h"
15
16
17/* Definitions for MMC/SDC command */
18#define CMD0 (0) /* GO_IDLE_STATE */
19#define CMD1 (1) /* SEND_OP_COND (MMC) */
20#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
21#define CMD8 (8) /* SEND_IF_COND */
22#define CMD9 (9) /* SEND_CSD */
23#define CMD10 (10) /* SEND_CID */
24#define CMD12 (12) /* STOP_TRANSMISSION */
25#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
26#define CMD16 (16) /* SET_BLOCKLEN */
27#define CMD17 (17) /* READ_SINGLE_BLOCK */
28#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
29#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
30#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
31#define CMD24 (24) /* WRITE_BLOCK */
32#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
33#define CMD55 (55) /* APP_CMD */
34#define CMD58 (58) /* READ_OCR */
35
36
37/* SD card socket connections */
38#if 0
39//#define MMC_PORT PORTG /* Socket contact port */
40//#define MMC_INPORT PING
41//#define SD_WP_PIN 5 /* Write protect switch */
42#endif
43
44/* SD card SPI access */
45#define SD_CD_PORT PORTG
46#define SD_CD_DDR DDRG
47#define SD_CD_INPORT PING
48#define SD_CD_PIN 3 /* Card detect switch */
49
50#define SD_WP_PORT PORTG
51#define SD_WP_DDR DDRG
52#define SD_WP_INPORT PING
53//#define SD_WP_PIN 5 /* Write protect switch */
54
55#define SD_CS_PORT PORTG
56#define SD_CS_DDR DDRG
57#define SD_CS_PIN 4 /* Chip select pin */
58
59
60/* Port Controls (Platform dependent) */
61
62#ifdef SD_CD_PIN
63static inline
64bool sd_cd(void)
65{
66 return (SD_CD_INPORT & _BV(SD_CD_PIN)) == 0;
67}
68#endif
69
70#ifdef SD_WP_PIN
71static inline
72bool sd_wp(void)
73{
74 return (SD_WP_INPORT & _BV(SD_WP_PIN)) == 0;
75}
76#endif
77
78#define CS_LOW() SD_CS_PORT &= ~(1<<SD_CS_PIN) /* MMC CS = L */
79#define CS_HIGH() SD_CS_PORT |= (1<<SD_CS_PIN) /* MMC CS = H */
80
81#define FCLK_SLOW() SPISetMMCInitClock() /* Set slow clock (100k-400k) */
82#define FCLK_FAST() SPISetFastClock() /* Set fast clock (depends on the CSD) */
83
84/*--------------------------------------------------------------------------
85
86 Module Private Functions
87
88 ---------------------------------------------------------------------------*/
89
90static volatile
91DSTATUS disk_stat = STA_NOINIT; /* Disk status */
92
93static
94BYTE CardType; /* Card type flags */
95
96/*-----------------------------------------------------------------------*/
97/* Wait for card ready */
98/*-----------------------------------------------------------------------*/
99
100static
101int wait_ready (void) /* 1:OK, 0:Timeout */
102{
103 uint32_t to = get_timer(0);
104
105 /* Wait for ready in timeout of 500ms */
106 do {
107 if (spi_rcvr() == 0xFF) {
108 return 1;
109 }
110 } while (get_timer(to) < 500);
111
112 return 0;
113}
114
115/*-----------------------------------------------------------------------*/
116/* Deselect the card and release SPI bus */
117/*-----------------------------------------------------------------------*/
118
119static
120void deselect (void)
121{
122// debug("*** enter deselect()\n");
123 CS_HIGH();
124 /* Dummy clock (TODO: force DO hi-z for multiple slave SPI) */
125 spi_rcvr();
126// debug("*** exit deselect()\n");
127}
128
129
130
131/*-----------------------------------------------------------------------*/
132/* Select the card and wait for ready */
133/*-----------------------------------------------------------------------*/
134
135static
136int select (void) /* 1:Successful, 0:Timeout */
137{
138// debug("*** enter select()\n");
139 CS_LOW();
140 /* Dummy clock (force DO enabled) */
141 spi_rcvr();
142
143 if (wait_ready()) {
144// debug("*** exit select() == 1\n");
145 return 1; /* OK */
146 }
147 deselect();
148// debug("*** exit select() == 0\n");
149
150 return 0; /* Timeout */
151}
152
153/*-----------------------------------------------------------------------*/
154/* Power Control (Platform dependent) */
155/*-----------------------------------------------------------------------*/
156/* When the target system does not support socket power control, there */
157/* is nothing to do in these functions and chk_power always returns 1. */
158
159static
160void power_on(void)
161{
162// debug("*** enter power_on()\n");
163
164#ifdef SD_PWR_PIN
165 SD_PWR_DDR |= _BV(SD_PWR_PIN); // Turns on PWR pin as output
166 SD_PWR_PORT &= ~_BV(SD_PWR_PIN); // Drives PWR pin high
167
168 for (uint32_t to = get_timer(0); get_timer(to) < 30;)
169 ; /* Wait for 30ms */
170#endif
171
172#ifdef SD_CD_PIN
173 /* Card detect, input with pullup */
174 SD_CD_DDR &= ~_BV(SD_CD_PIN);
175 SD_CD_PORT |= _BV(SD_CD_PIN);
176#endif
177#ifdef SD_WP_PIN
178 SD_WP_DDR &= ~_BV(SD_WP_PIN);
179 SD_WP_PORT |= _BV(SD_WP_PIN);
180#endif
181 SD_CS_PORT |= _BV(SD_CS_PIN);
182 SD_CS_DDR |= _BV(SD_CS_PIN); // Turns on CS pin as output
183
184// debug("*** exit power_on()\n");
185}
186
187static
188void power_off (void)
189{
190// debug("*** enter power_off()\n");
191 select(); /* Wait for card ready */
192 deselect();
193
194#ifdef SD_PWR_PIN
195 SD_PWR_PORT |= (1 << SD_PWR_PIN); /* Socket power OFF */
196#endif
197 disk_stat |= STA_NOINIT; /* Set STA_NOINIT */
198// debug("*** exit power_off()\n");
199}
200
201#if 0
202static
203int chk_power(void) /* Socket power state: 0=off, 1=on */
204{
205#ifdef SD_PWR_PIN
206 return (SD_PWR_PORT & (1 << SD_PWR_PIN)) ? 0 : 1;
207#else
208 return 1;
209#endif /* SD_PWR_PIN */
210}
211#endif
212
213/*-----------------------------------------------------------------------*/
214/* Receive a data packet from MMC */
215/*-----------------------------------------------------------------------*/
216
217static
218int rcvr_datablock (
219 BYTE *buff, /* Data buffer to store received data */
220UINT btr /* Byte count (must be multiple of 4) */
221) {
222 BYTE token, tmp;
223 uint32_t to = get_timer(0);
224
225 /* Wait for data packet in timeout of 200ms */
226 do {
227 token = spi_rcvr();
228 } while ((token == 0xFF) && get_timer(to) < 200);
229 if(token != 0xFE) return 0; /* If not valid data token, retutn with error */
230
231 tmp = spi_rcvr(); /* shift in first byte */
232 spi_write(0xff); /* start shift in next byte */
233 while (--btr) {
234 *buff++ = tmp;
235 asm volatile (""::"r"(buff), "r"(btr));
236 spi_wait();
237 tmp = SPDR;
238 spi_write(0xff);
239 }
240 *buff = tmp; /* store last byte in buffer while SPI module shifts in crc part1 */
241 spi_wait();
242 spi_rcvr(); /* second crc */
243
244 return 1; /* Return with success */
245}
246
247/*-----------------------------------------------------------------------*/
248/* Send a data packet to MMC */
249/*-----------------------------------------------------------------------*/
250
251#if _USE_WRITE
252static
253int xmit_datablock (
254 const BYTE *buff, /* 512 byte data block to be transmitted */
255 BYTE token /* Data/Stop token */
256)
257{
258 BYTE resp, tmp;
259 UINT btr;
260
261 if (!wait_ready()) return 0;
262
263 spi_write(token); /* Xmit data token */
264 if (token != 0xFD) { /* Is data token */
265 btr = 512;
266 do {
267 tmp = *buff++;
268 spi_wait();
269 spi_write(tmp);
270 }while (--btr);
271 spi_wait();
272 spi_xmit(0xff); /* CRC (Dummy) */
273 spi_xmit(0xff);
274 resp = spi_rcvr(); /* Reveive data response */
275 return ((resp & 0x1F) != 0x05) ? 0 : 1; /* If not accepted, return with error */
276 }
277
278 spi_wait();
279 return 1;
280}
281#endif /* _USE_WRITE */
282
283/*-----------------------------------------------------------------------*/
284/* Send a command packet to MMC */
285/*-----------------------------------------------------------------------*/
286
287static
288BYTE send_cmd ( /* Returns R1 resp (bit7==1:Send failed) */
289 BYTE cmd, /* Command index */
290 DWORD arg /* Argument */
291) {
292 union {
293 DWORD as32;
294 BYTE as8[4];
295 } argtmp;
296 BYTE n, res;
297
298// debug("*** send_cmd( %.2x )\n", cmd);
299
300 if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
301 cmd &= 0x7F;
302 res = send_cmd(CMD55, 0);
303 if (res > 1)
304 return res;
305 }
306
307 /* Select the card and wait for ready except to stop multiple block read */
308 if (cmd != CMD12) {
309 deselect();
310 if (!select())
311 return 0xFF;
312 }
313
314 /* Send command packet */
315 spi_xmit(0x40 | cmd); /* Start + Command index */
316 argtmp.as32 = arg;
317 spi_xmit(argtmp.as8[3]); /* Argument[31..24] */
318 spi_xmit(argtmp.as8[2]); /* Argument[23..16] */
319 spi_xmit(argtmp.as8[1]); /* Argument[15..8] */
320 spi_xmit(argtmp.as8[0]); /* Argument[7..0] */
321
322 n = 0x01; /* Dummy CRC + Stop */
323 if (cmd == CMD0)
324 n = 0x95; /* Valid CRC for CMD0(0) */
325 if (cmd == CMD8)
326 n = 0x87; /* Valid CRC for CMD8(0x1AA) */
327 spi_xmit(n);
328
329 /* Receive command response */
330 if (cmd == CMD12)
331 spi_rcvr(); /* Skip a stuff byte when stop reading */
332 n = 10; /* Wait for a valid response in timeout of 10 attempts */
333 do
334 res = spi_rcvr();
335 while ((res & 0x80) && --n);
336
337 return res; /* Return with the response value */
338}
339
340/*--------------------------------------------------------------------------
341
342 Public Functions
343
344 ---------------------------------------------------------------------------*/
345
346/*-----------------------------------------------------------------------*/
347/* Initialize Disk Drive */
348/*-----------------------------------------------------------------------*/
349
350#define MMC_INIT_TO 1000 /* 1s */
351
352DSTATUS disk_initialize (
353 BYTE drv /* Physical drive nmuber (0) */
354)
355{
356 BYTE n, cmd, ty, ocr[4];
357
358 if (drv)
359 return STA_NOINIT; /* Supports only single drive */
360 if (disk_stat & STA_NODISK)
361 return disk_stat; /* No card in the socket */
362
363 power_on(); /* Force socket power on */
364 FCLK_SLOW();
365 for (n = 10; n; n--)
366 spi_rcvr(); /* 80 dummy clocks */
367
368 ty = 0;
369 if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
370 /* Init timeout timer */
371 uint32_t timer = get_timer(0);
372
373 if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
374 for (n = 0; n < 4; n++) ocr[n] = spi_rcvr(); /* Get trailing return value of R7 resp */
375 if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
376 while (get_timer(timer) < MMC_INIT_TO && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
377 if (get_timer(timer) < MMC_INIT_TO && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
378 for (n = 0; n < 4; n++) ocr[n] = spi_rcvr();
379 ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
380 }
381 }
382 } else { /* SDv1 or MMCv3 */
383 if (send_cmd(ACMD41, 0) <= 1) {
384 ty = CT_SD1; cmd = ACMD41; /* SDv1 */
385 } else {
386 ty = CT_MMC; cmd = CMD1; /* MMCv3 */
387 }
388
389 /* Wait for leaving idle state */
390 while (get_timer(timer) < MMC_INIT_TO && send_cmd(cmd, 0));
391
392 /* Set R/W block length to 512 */
393 if (!(get_timer(timer) < MMC_INIT_TO) || send_cmd(CMD16, 512) != 0)
394 ty = 0;
395 }
396 }
397 CardType = ty;
398 deselect();
399
400 if (ty) { /* Initialization succeded */
401 disk_stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
402 FCLK_FAST();
403 } else { /* Initialization failed */
404 power_off();
405 }
406
407 return disk_stat;
408}
409
410/*-----------------------------------------------------------------------*/
411/* Get Disk Status */
412/*-----------------------------------------------------------------------*/
413
414DSTATUS disk_status (
415 BYTE drv /* Physical drive nmuber (0) */
416)
417{
418 if (drv) return STA_NOINIT; /* Supports only single drive */
419 return disk_stat;
420}
421
422/*-----------------------------------------------------------------------*/
423/* Read Sector(s) */
424/*-----------------------------------------------------------------------*/
425
426DRESULT disk_read (
427 BYTE drv, /* Physical drive nmuber (0) */
428 BYTE *buff, /* Pointer to the data buffer to store read data */
429 DWORD sector, /* Start sector number (LBA) */
430 UINT count /* Sector count (1..255) */
431)
432{
433 BYTE cmd;
434
435 if (drv || !count) return RES_PARERR;
436 if (disk_stat & STA_NOINIT) return RES_NOTRDY;
437
438 if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
439
440 cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
441 if (send_cmd(cmd, sector) == 0) {
442 do {
443 if (!rcvr_datablock(buff, 512))
444 break;
445 buff += 512;
446 } while (--count);
447 if (cmd == CMD18)
448 send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
449 }
450 deselect();
451
452 return count ? RES_ERROR : RES_OK;
453}
454
455/*-----------------------------------------------------------------------*/
456/* Write Sector(s) */
457/*-----------------------------------------------------------------------*/
458
459#if _USE_WRITE
460DRESULT disk_write (
461 BYTE drv, /* Physical drive nmuber (0) */
462 const BYTE *buff, /* Pointer to the data to be written */
463 DWORD sector, /* Start sector number (LBA) */
464 UINT count /* Sector count (1..255) */
465)
466{
467 if (drv || !count) return RES_PARERR;
468 if (disk_stat & STA_NOINIT) return RES_NOTRDY;
469 if (disk_stat & STA_PROTECT) return RES_WRPRT;
470
471 if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
472
473 if (count == 1) { /* Single block write */
474 if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
475 && xmit_datablock(buff, 0xFE))
476 count = 0;
477 }
478 else { /* Multiple block write */
479 if (CardType & CT_SDC) send_cmd(ACMD23, count);
480 if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
481 do {
482 if (!xmit_datablock(buff, 0xFC)) break;
483 buff += 512;
484 }while (--count);
485 if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
486 count = 1;
487 }
488 }
489 deselect();
490
491 return count ? RES_ERROR : RES_OK;
492}
493#endif /* _USE_WRITE */
494
495/*-----------------------------------------------------------------------*/
496/* Miscellaneous Functions */
497/*-----------------------------------------------------------------------*/
498
499#if _USE_IOCTL
500DRESULT disk_ioctl (
501 BYTE drv, /* Physical drive nmuber (0) */
502 BYTE cmd, /* Control code */
503 void *buff /* Buffer to send/receive control data */
504)
505{
506 DRESULT res;
507 BYTE n, csd[16], *ptr = buff;
508 DWORD csize;
509
510 if (drv)
511 return RES_PARERR;
512
513 res = RES_ERROR;
514
515 if (disk_stat & STA_NOINIT) return RES_NOTRDY;
516
517 switch (cmd) {
518 case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
519 if (select())
520 res = RES_OK;
521 break;
522
523 case GET_SECTOR_COUNT: /* Get number of sectors on the disk (DWORD) */
524 if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
525 if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
526 csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
527 *(DWORD*)buff = csize << 10;
528 } else { /* SDC ver 1.XX or MMC*/
529 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
530 csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
531 *(DWORD*)buff = csize << (n - 9);
532 }
533 res = RES_OK;
534 }
535 break;
536
537 case GET_BLOCK_SIZE: /* Get erase block size in unit of sector (DWORD) */
538 if (CardType & CT_SD2) { /* SDv2? */
539 if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
540 spi_rcvr();
541 if (rcvr_datablock(csd, 16)) { /* Read partial block */
542 for (n = 64 - 16; n; n--)
543 spi_rcvr(); /* Purge trailing data */
544 *(DWORD*) buff = 16UL << (csd[10] >> 4);
545 res = RES_OK;
546 }
547 }
548 } else { /* SDv1 or MMCv3 */
549 if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
550 if (CardType & CT_SD1) { /* SDv1 */
551 *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
552 } else { /* MMCv3 */
553 *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
554 }
555 res = RES_OK;
556 }
557 }
558 break;
559
560 /* Following commands are never used by FatFs module */
561
562 case MMC_GET_TYPE: /* Get card type flags (1 byte) */
563 *ptr = CardType;
564 res = RES_OK;
565 break;
566
567 case MMC_GET_CSD: /* Receive CSD as a data block (16 bytes) */
568 if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
569 && rcvr_datablock(ptr, 16))
570 res = RES_OK;
571 break;
572
573 case MMC_GET_CID: /* Receive CID as a data block (16 bytes) */
574 if (send_cmd(CMD10, 0) == 0 /* READ_CID */
575 && rcvr_datablock(ptr, 16))
576 res = RES_OK;
577 break;
578
579 case MMC_GET_OCR: /* Receive OCR as an R3 resp (4 bytes) */
580 if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
581 for (n = 4; n; n--)
582 *ptr++ = spi_rcvr();
583 res = RES_OK;
584 }
585 break;
586
587 case MMC_GET_SDSTAT: /* Receive SD status as a data block (64 bytes) */
588 if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
589 spi_rcvr();
590 if (rcvr_datablock(ptr, 64))
591 res = RES_OK;
592 }
593 break;
594
595 case CTRL_POWER_OFF : /* Power off */
596 power_off();
597 disk_stat |= STA_NOINIT;
598 res = RES_OK;
599 break;
600
601 default:
602 res = RES_PARERR;
603 }
604
605 deselect();
606
607 return res;
608}
609#endif /* _USE_IOCTL */
610
611/*-----------------------------------------------------------------------*/
612/* Device Timer Interrupt Procedure (Platform dependent) */
613/*-----------------------------------------------------------------------*/
614/* This function must be called in period of 10ms */
615
616void disk_timerproc (void)
617{
618 BYTE s;
619
620 s = disk_stat;
621
622#ifdef SD_WP_PIN
623 if (sd_wp()) /* Write protected */
624 s |= STA_PROTECT;
625 else /* Write enabled */
626 s &= ~STA_PROTECT;
627#endif
628
629#ifdef SD_CD_PIN
630 if (sd_cd()) /* Card inserted */
631 s &= ~STA_NODISK;
632 else /* Socket empty */
633 s |= (STA_NODISK | STA_NOINIT);
634#endif
635
636 disk_stat = s; /* Update MMC status */
637}