Lightweight SD card FAT file system. Originaled by chan http://elm-chan.org/fsw/ff/00index_p.html

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mmc.cpp Source File

mmc.cpp

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