spinal cord / PokittoLib

Dependents:   Sensitive

Fork of PokittoLib by Jonne Valola

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mmc.cpp Source File

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 #include "PokittoDisk.h "
00011 
00012 /* Definitions for MMC/SDC command */
00013 #define CMD0    (0x40+0)    /* GO_IDLE_STATE */
00014 #define CMD1    (0x40+1)    /* SEND_OP_COND (MMC) */
00015 #define    ACMD41    (0xC0+41)    /* SEND_OP_COND (SDC) */
00016 #define CMD8    (0x40+8)    /* SEND_IF_COND */
00017 #define CMD16    (0x40+16)    /* SET_BLOCKLEN */
00018 #define CMD17    (0x40+17)    /* READ_SINGLE_BLOCK */
00019 #define CMD24    (0x40+24)    /* WRITE_BLOCK */
00020 #define CMD55    (0x40+55)    /* APP_CMD */
00021 #define CMD58    (0x40+58)    /* READ_OCR */
00022 
00023 
00024 
00025 /* Port Controls (Platform dependent) */
00026 #define SELECT()    CLR_SD_CS //mmccs.write(0)        /* MMC CS = L */
00027 #define    DESELECT()    SET_SD_CS // mmccs.write(1)        /* MMC CS = H */
00028 #define    MMC_SEL        !GET_SD_CS // !mmccs.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 //__attribute__((section(".SD_Code")))
00117 DSTATUS disk_initialize (void) {
00118     BYTE n, cmd, ty, ocr[4];
00119     WORD tmr;
00120 
00121     DESELECT();
00122     device.frequency(SPI_FREQ);
00123     device.format(8);
00124     // device.frequency(SPI_FREQ); // hangs if this is after format
00125 
00126 #if _WRITE_FUNC
00127     if (MMC_SEL) disk_writep(0, 0);        /* Finalize write process if it is in progress */
00128 #endif
00129     for (n = 100; n; n--) rcv_spi();    /* Dummy clocks */
00130 
00131     ty = 0;
00132     if (send_cmd(CMD0, 0) == 1) {            /* Enter Idle state */
00133         if (send_cmd(CMD8, 0x1AA) == 1) {    /* SDv2 */
00134             for (n = 0; n < 4; n++) ocr[n] = rcv_spi();        /* Get trailing return value of R7 resp */
00135             if (ocr[2] == 0x01 && ocr[3] == 0xAA) {                /* The card can work at vdd range of 2.7-3.6V */
00136                 for (tmr = 12000; tmr && send_cmd(ACMD41, 1UL << 30); tmr--) ;    /* Wait for leaving idle state (ACMD41 with HCS bit) */
00137                 if (tmr && send_cmd(CMD58, 0) == 0) {        /* Check CCS bit in the OCR */
00138                     for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
00139                     ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;    /* SDv2 (HC or SC) */
00140                 }
00141             }
00142         } else {                            /* SDv1 or MMCv3 */
00143             if (send_cmd(ACMD41, 0) <= 1)     {
00144                 ty = CT_SD1;
00145                 cmd = ACMD41;    /* SDv1 */
00146             } else {
00147                 ty = CT_MMC;
00148                 cmd = CMD1;    /* MMCv3 */
00149             }
00150             for (tmr = 25000; tmr && send_cmd(cmd, 0); tmr--) ;    /* Wait for leaving idle state */
00151             if (!tmr || send_cmd(CMD16, 512) != 0)            /* Set R/W block length to 512 */
00152                 ty = 0;
00153         }
00154     }
00155     CardType = ty;
00156     release_spi();
00157 
00158     return ty ? 0 : STA_NOINIT;
00159 }
00160 
00161 
00162 
00163 /*-----------------------------------------------------------------------*/
00164 /* Read partial sector                                                   */
00165 /*-----------------------------------------------------------------------*/
00166 
00167 DRESULT disk_readp (
00168     BYTE *buff,        /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
00169     DWORD lba,        /* Sector number (LBA) */
00170     WORD ofs,        /* Byte offset to read from (0..511) */
00171     WORD cnt        /* Number of bytes to read (ofs + cnt mus be <= 512) */
00172 ) {
00173     DRESULT res;
00174     BYTE rc;
00175     WORD bc;
00176 
00177 
00178     if (!(CardType & CT_BLOCK)) lba *= 512;        /* Convert to byte address if needed */
00179 
00180     res = RES_ERROR;
00181     if (send_cmd(CMD17, lba) == 0) {        /* READ_SINGLE_BLOCK */
00182 
00183         bc = 30000;
00184         do {                            /* Wait for data packet in timeout of 100ms */
00185             rc = rcv_spi();
00186         } while (rc == 0xFF && --bc);
00187 
00188         if (rc == 0xFE) {                /* A data packet arrived */
00189             bc = 514 - ofs - cnt;
00190 
00191             /* Skip leading bytes */
00192             if (ofs) {
00193                 do {
00194                     rcv_spi();
00195                 } while (--ofs);
00196             }
00197 
00198             /* Receive a part of the sector */
00199             if (buff) {    /* Store data to the memory */
00200                 do {
00201                     *buff++ = rcv_spi();
00202                 } while (--cnt);
00203             } else {    /* Forward data to the outgoing stream (depends on the project) */
00204                 do {
00205                     rcv_spi();
00206                 } while (--cnt);
00207             }
00208 
00209             /* Skip trailing bytes and CRC */
00210             do rcv_spi();
00211             while (--bc);
00212 
00213             res = RES_OK;
00214         }
00215     }
00216 
00217     release_spi();
00218 
00219     return res;
00220 }
00221 
00222 
00223 
00224 /*-----------------------------------------------------------------------*/
00225 /* Write partial sector                                                  */
00226 /*-----------------------------------------------------------------------*/
00227 #if _WRITE_FUNC
00228 
00229 DRESULT disk_writep (
00230     const BYTE *buff,    /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
00231     DWORD sa            /* Number of bytes to send, Sector number (LBA) or zero */
00232 ) {
00233     DRESULT res;
00234     WORD bc;
00235     static WORD wc;
00236 
00237 
00238     res = RES_ERROR;
00239 
00240     if (buff) {        /* Send data bytes */
00241         bc = (WORD)sa;
00242         while (bc && wc) {        /* Send data bytes to the card */
00243             xmit_spi(*buff++);
00244             wc--;
00245             bc--;
00246         }
00247         res = RES_OK;
00248     } else {
00249         if (sa) {    /* Initiate sector write process */
00250             if (!(CardType & CT_BLOCK)) sa *= 512;    /* Convert to byte address if needed */
00251             if (send_cmd(CMD24, sa) == 0) {            /* WRITE_SINGLE_BLOCK */
00252                 xmit_spi(0xFF);
00253                 xmit_spi(0xFE);        /* Data block header */
00254                 wc = 512;                            /* Set byte counter */
00255                 res = RES_OK;
00256             }
00257         } else {    /* Finalize sector write process */
00258             bc = wc + 2;
00259             while (bc--) xmit_spi(0);    /* Fill left bytes and CRC with zeros */
00260             if ((rcv_spi() & 0x1F) == 0x05) {    /* Receive data resp and wait for end of write process in timeout of 300ms */
00261                 for (bc = 65000; rcv_spi() != 0xFF && bc; bc--) ;    /* Wait ready */
00262                 if (bc) res = RES_OK;
00263             }
00264             release_spi();
00265         }
00266     }
00267 
00268     return res;
00269 }
00270 #endif
00271