PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)

Dependents:   YATTT sd_map_test cPong SnowDemo ... more

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