Shinichiro Nakamura / Mbed 2 deprecated SDCARD_PFF_CPP

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers diskio_mmc.cpp Source File

diskio_mmc.cpp

00001 /*-----------------------------------------------------------------------*/
00002 /* PFF - Low level disk control module for ATtiny85     (C)ChaN, 2009    */
00003 /*-----------------------------------------------------------------------*/
00004 
00005 #define _WRITE_FUNC    1
00006 
00007 #include "diskio.h"
00008 #include "mbed.h"
00009 #include "connect.h"
00010 
00011 /* Definitions for MMC/SDC command */
00012 #define CMD0    (0x40+0)    /* GO_IDLE_STATE */
00013 #define CMD1    (0x40+1)    /* SEND_OP_COND (MMC) */
00014 #define    ACMD41    (0xC0+41)    /* SEND_OP_COND (SDC) */
00015 #define CMD8    (0x40+8)    /* SEND_IF_COND */
00016 #define CMD16    (0x40+16)    /* SET_BLOCKLEN */
00017 #define CMD17    (0x40+17)    /* READ_SINGLE_BLOCK */
00018 #define CMD24    (0x40+24)    /* WRITE_BLOCK */
00019 #define CMD55    (0x40+55)    /* APP_CMD */
00020 #define CMD58    (0x40+58)    /* READ_OCR */
00021 
00022 SPI device(CONNECT_MOSI,CONNECT_MISO,CONNECT_SCK);
00023 DigitalOut cs(CONNECT_CS);
00024 
00025 /* Port Controls (Platform dependent) */
00026 #define SELECT()    cs.write(0)        /* MMC CS = L */
00027 #define    DESELECT()    cs.write(1)        /* MMC CS = H */
00028 #define    MMC_SEL        !cs.read()    /* MMC CS status (true:selected) */
00029 
00030 void xmit_spi (BYTE c) {
00031     device.write(c);    /* Send a byte */
00032 }
00033 
00034 BYTE rcv_spi (void) {
00035     return device.write(0xff);
00036 }
00037 
00038 /*--------------------------------------------------------------------------
00039 
00040    Module Private Functions
00041 
00042 ---------------------------------------------------------------------------*/
00043 
00044 static
00045 BYTE CardType;
00046 
00047 
00048 /*-----------------------------------------------------------------------*/
00049 /* Deselect the card and release SPI bus                                 */
00050 /*-----------------------------------------------------------------------*/
00051 
00052 static
00053 void release_spi (void) {
00054     DESELECT();
00055     rcv_spi();
00056 }
00057 
00058 
00059 /*-----------------------------------------------------------------------*/
00060 /* Send a command packet to MMC                                          */
00061 /*-----------------------------------------------------------------------*/
00062 
00063 static
00064 BYTE send_cmd (
00065     BYTE cmd,        /* Command byte */
00066     DWORD arg        /* Argument */
00067 ) {
00068     BYTE n, res;
00069 
00070 
00071     if (cmd & 0x80) {    /* ACMD<n> is the command sequense of CMD55-CMD<n> */
00072         cmd &= 0x7F;
00073         res = send_cmd(CMD55, 0);
00074         if (res > 1) return res;
00075     }
00076 
00077     /* Select the card */
00078     DESELECT();
00079     rcv_spi();
00080     SELECT();
00081     rcv_spi();
00082 
00083     /* Send a command packet */
00084     xmit_spi(cmd);                        /* Start + Command index */
00085     xmit_spi((BYTE)(arg >> 24));        /* Argument[31..24] */
00086     xmit_spi((BYTE)(arg >> 16));        /* Argument[23..16] */
00087     xmit_spi((BYTE)(arg >> 8));            /* Argument[15..8] */
00088     xmit_spi((BYTE)arg);                /* Argument[7..0] */
00089     n = 0x01;                            /* Dummy CRC + Stop */
00090     if (cmd == CMD0) n = 0x95;            /* Valid CRC for CMD0(0) */
00091     if (cmd == CMD8) n = 0x87;            /* Valid CRC for CMD8(0x1AA) */
00092     xmit_spi(n);
00093 
00094     /* Receive a command response */
00095     n = 10;                                /* Wait for a valid response in timeout of 10 attempts */
00096     do {
00097         res = rcv_spi();
00098     } while ((res & 0x80) && --n);
00099 
00100     return res;            /* Return with the response value */
00101 }
00102 
00103 
00104 
00105 /*--------------------------------------------------------------------------
00106 
00107    Public Functions
00108 
00109 ---------------------------------------------------------------------------*/
00110 
00111 
00112 /*-----------------------------------------------------------------------*/
00113 /* Initialize Disk Drive                                                 */
00114 /*-----------------------------------------------------------------------*/
00115 
00116 DSTATUS disk_initialize (void) {
00117     BYTE n, cmd, ty, ocr[4];
00118     WORD tmr;
00119 
00120     DESELECT();
00121     device.format(8);
00122     device.frequency(SPI_FREQ);
00123 
00124 #if _WRITE_FUNC
00125     if (MMC_SEL) disk_writep(0, 0);        /* Finalize write process if it is in progress */
00126 #endif
00127     for (n = 100; n; n--) rcv_spi();    /* Dummy clocks */
00128 
00129     ty = 0;
00130     if (send_cmd(CMD0, 0) == 1) {            /* Enter Idle state */
00131         if (send_cmd(CMD8, 0x1AA) == 1) {    /* SDv2 */
00132             for (n = 0; n < 4; n++) ocr[n] = rcv_spi();        /* Get trailing return value of R7 resp */
00133             if (ocr[2] == 0x01 && ocr[3] == 0xAA) {                /* The card can work at vdd range of 2.7-3.6V */
00134                 for (tmr = 12000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) ;    /* Wait for leaving idle state (ACMD41 with HCS bit) */
00135                 if (tmr && send_cmd(CMD58, 0) == 0) {        /* Check CCS bit in the OCR */
00136                     for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
00137                     ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;    /* SDv2 (HC or SC) */
00138                 }
00139             }
00140         } else {                            /* SDv1 or MMCv3 */
00141             if (send_cmd(ACMD41, 0) <= 1)     {
00142                 ty = CT_SD1;
00143                 cmd = ACMD41;    /* SDv1 */
00144             } else {
00145                 ty = CT_MMC;
00146                 cmd = CMD1;    /* MMCv3 */
00147             }
00148             for (tmr = 25000; tmr && send_cmd(cmd, 0); tmr--) ;    /* Wait for leaving idle state */
00149             if (!tmr || send_cmd(CMD16, 512) != 0)            /* Set R/W block length to 512 */
00150                 ty = 0;
00151         }
00152     }
00153     CardType = ty;
00154     release_spi();
00155 
00156     return ty ? 0 : STA_NOINIT;
00157 }
00158 
00159 
00160 
00161 /*-----------------------------------------------------------------------*/
00162 /* Read partial sector                                                   */
00163 /*-----------------------------------------------------------------------*/
00164 
00165 DRESULT disk_readp (
00166     BYTE *buff,        /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
00167     DWORD lba,        /* Sector number (LBA) */
00168     WORD ofs,        /* Byte offset to read from (0..511) */
00169     WORD cnt        /* Number of bytes to read (ofs + cnt mus be <= 512) */
00170 ) {
00171     DRESULT res;
00172     BYTE rc;
00173     WORD bc;
00174 
00175 
00176     if (!(CardType & CT_BLOCK)) lba *= 512;        /* Convert to byte address if needed */
00177 
00178     res = RES_ERROR;
00179     if (send_cmd(CMD17, lba) == 0) {        /* READ_SINGLE_BLOCK */
00180 
00181         bc = 30000;
00182         do {                            /* Wait for data packet in timeout of 100ms */
00183             rc = rcv_spi();
00184         } while (rc == 0xFF && --bc);
00185 
00186         if (rc == 0xFE) {                /* A data packet arrived */
00187             bc = 514 - ofs - cnt;
00188 
00189             /* Skip leading bytes */
00190             if (ofs) {
00191                 do {
00192                     rcv_spi();
00193                 } while (--ofs);
00194             }
00195 
00196             /* Receive a part of the sector */
00197             if (buff) {    /* Store data to the memory */
00198                 do {
00199                     *buff++ = rcv_spi();
00200                 } while (--cnt);
00201             } else {    /* Forward data to the outgoing stream (depends on the project) */
00202                 do {
00203                     rcv_spi();
00204                 } while (--cnt);
00205             }
00206 
00207             /* Skip trailing bytes and CRC */
00208             do rcv_spi();
00209             while (--bc);
00210 
00211             res = RES_OK;
00212         }
00213     }
00214 
00215     release_spi();
00216 
00217     return res;
00218 }
00219 
00220 
00221 
00222 /*-----------------------------------------------------------------------*/
00223 /* Write partial sector                                                  */
00224 /*-----------------------------------------------------------------------*/
00225 #if _WRITE_FUNC
00226 
00227 DRESULT disk_writep (
00228     const BYTE *buff,    /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
00229     DWORD sa            /* Number of bytes to send, Sector number (LBA) or zero */
00230 ) {
00231     DRESULT res;
00232     WORD bc;
00233     static WORD wc;
00234 
00235 
00236     res = RES_ERROR;
00237 
00238     if (buff) {        /* Send data bytes */
00239         bc = (WORD)sa;
00240         while (bc && wc) {        /* Send data bytes to the card */
00241             xmit_spi(*buff++);
00242             wc--;
00243             bc--;
00244         }
00245         res = RES_OK;
00246     } else {
00247         if (sa) {    /* Initiate sector write process */
00248             if (!(CardType & CT_BLOCK)) sa *= 512;    /* Convert to byte address if needed */
00249             if (send_cmd(CMD24, sa) == 0) {            /* WRITE_SINGLE_BLOCK */
00250                 xmit_spi(0xFF);
00251                 xmit_spi(0xFE);        /* Data block header */
00252                 wc = 512;                            /* Set byte counter */
00253                 res = RES_OK;
00254             }
00255         } else {    /* Finalize sector write process */
00256             bc = wc + 2;
00257             while (bc--) xmit_spi(0);    /* Fill left bytes and CRC with zeros */
00258             if ((rcv_spi() & 0x1F) == 0x05) {    /* Receive data resp and wait for end of write process in timeout of 300ms */
00259                 for (bc = 65000; rcv_spi() != 0xFF && bc; bc--) ;    /* Wait ready */
00260                 if (bc) res = RES_OK;
00261             }
00262             release_spi();
00263         }
00264     }
00265 
00266     return res;
00267 }
00268 #endif