Lightweight SD card FAT file system. Originaled by chan http://elm-chan.org/fsw/ff/00index_p.html
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Wed Jul 13 2022 23:03:59 by 1.7.2