VLSI Solution Oy VLSI Solution Oy Evaluation MP3 Player Source Code Documentation

Main Page | Class List | File List | Class Members | File Members | Related Pages

mmc.c

Go to the documentation of this file.
00001 00005 #include "mmc.h" 00006 #include "board.h" 00007 #include "storage.h" //for reporting back the serial number 00008 #include "console.h" 00009 #include "buffer.h" 00010 00011 //#define MMCDEBUG 00012 //#define MMCLONGDEBUG 00013 00014 00019 unsigned char MmcCommand(unsigned char c1, 00020 unsigned char c2, 00021 unsigned char c3, 00022 unsigned char c4, 00023 unsigned char c5){ 00024 00025 00026 unsigned int i; 00027 00028 00029 /* Note: c1, c2 are used for temporary variables after use! */ 00030 00031 // MMC_OFF = NO; //MMC should be powered, but switch power on just-in-case 00032 // MMCDeselect(); //put MMC on-line. 00033 // Provide clock edges before and after asserting MMC CS 00034 00035 MMCDeselect(); 00036 SPI8Clocks(8); 00037 MMCSelect(); 00038 SPI8Clocks(8); 00039 00040 i=0; 00041 // If card still seems to be busy, give it some time... 00042 // changed 12/2005 to give quite a lot of time. 00043 while ((SPIGetChar()!=0xff) && (++i<60000)); 00044 ; 00045 00046 // The bus should be stable high now 00047 if ((i=SPI_RESULT_BYTE) != 0xff){ 00048 ConsoleWrite("\rUnexpected busy signal from MMC. "); 00049 ConsolePutHex16(i); 00050 MMCDeselect(); 00051 Delay(1000); 00052 return 0x81; //MMC unexpectedly Busy 00053 } 00054 00055 #ifdef MMCDEBUG 00056 DebugMessage(" \x1b[7m"); 00057 ConsolePutChar('C'); ConsolePutHex8(c1); ConsolePutHex8(c2); ConsolePutHex8(c3); 00058 ConsolePutHex8(c4); ConsolePutHex8(c5); ConsolePutChar('|'); 00059 #endif 00060 00061 // Send the MMC command 00062 SPIPutCharWithoutWaiting(c1); 00063 SPIPutChar(c2); 00064 SPIPutChar(c3); 00065 SPIPutChar(c4); 00066 SPIPutChar(c5); 00067 SPIPutChar(0x95); /* Valid CRC for init, then don't care */ 00068 SPIWait(); 00069 /* Now ok to use c1..c5 as temporaries (dirty but kool) */ 00070 00071 // Wait for R1 style response (bit 7 low) from MMC 00072 #ifdef MMCDEBUG 00073 { 00074 c1=100; /* try max. 100 times */ 00075 while((c1--)&&((c2=SPIGetChar())&0x80)){ //wait for R1 or timeout 00076 // R1 response not detected, if it's not 0xff, print it for debugging. 00077 if (c2!=0xff){ConsolePutHex8(c2);ConsolePutChar('|');} 00078 } 00079 ConsolePutHex8(c2); 00080 DebugMessage("\x1b[0m "); 00081 } 00082 #else 00083 { 00084 c1=100; 00085 while((c1--)&&((c2=SPIGetChar())&0x80)) //wait for R1 or timeout 00086 ; 00087 } 00088 #endif 00089 00090 return c2; //return the R1 response 00091 } 00092 00093 00105 unsigned char MmcWaitForData(){ 00106 00107 unsigned char c; 00108 unsigned int i; 00109 00110 DebugMessage("<t:"); //Token Wait 00111 00112 i = 60000; //try max. 60000 bus cycles 00113 // Wait until something else than 0xff is read from the bus 00114 do { 00115 c=SPIGetChar(); 00116 --i; 00117 } while ((c == 0xff) && (i)); 00118 00119 // Something was received from the bus? Might it actually be te 00120 // desired 0xFE data start token? 00121 if (c != 0xfe){ 00122 // No data start token, read fail. In an OS an error message would display. 00123 // Since we're in an embedded system, it's unclear what we should do now. 00124 // Current approach is to say all ok but make read block return 0xff's. 00125 // It's not disasterous at least as long as we don't WRITE to MMC. 00126 00127 // Flush any data that might be pending from the MMC. 00128 #ifdef MMCLONGDEBUG 00129 { 00130 unsigned int i; 00131 ConsoleWrite("\rMMCWaitForData failed. "); 00132 ConsoleWrite("Expected 0xFE token, received: "); 00133 for (i=0;i<550;i++){ 00134 ConsolePutHex8(c); 00135 c=SPIGetChar(); 00136 } 00137 } 00138 #else 00139 ConsoleWrite(" NoData "); 00140 SPI8Clocks(200); /* Flush MMC by sending lots of FF's to it */ 00141 SPI8Clocks(200); 00142 SPI8Clocks(200); 00143 #endif 00144 00145 MMCDeselect(); 00146 DebugMessage("!t>"); 00147 return 5; //Return error 00148 } 00149 DebugMessage("t>"); //Exit Token Wait 00150 return 0; 00151 } 00152 00153 00159 void MmcGetData(unsigned int amountOctets){ 00160 DebugMessage("<G"); 00161 00162 dataBufPtr = diskSect.raw.buf; 00163 while (amountOctets--){ 00164 *dataBufPtr++=SPIGetChar(); 00165 } 00166 DebugMessage("G>"); 00167 } 00168 00169 00171 unsigned char GetStorageInformation(){ 00172 if (MmcCommand(0x4a,0,0,0,0)&0xfe) 00173 return 4; /* no storage info */ 00174 MmcWaitForData(); 00175 MmcGetData(30); 00176 00177 ConsoleWrite("\rMMC Manufacturer#: "); 00178 ConsolePutUInt(diskSect.raw.buf[0]); 00179 ConsoleWrite("Product Name: "); 00180 ConsolePutChar(diskSect.raw.buf[3]); 00181 ConsolePutChar(diskSect.raw.buf[4]); 00182 ConsolePutChar(diskSect.raw.buf[5]); 00183 ConsolePutChar(diskSect.raw.buf[6]); 00184 ConsolePutChar(diskSect.raw.buf[7]); 00185 ConsolePutChar(diskSect.raw.buf[8]); 00186 ConsoleWrite(" Production date: "); 00187 ConsolePutUInt(diskSect.raw.buf[14]>>4); 00188 ConsoleWrite("/ "); 00189 ConsolePutUInt((diskSect.raw.buf[14]&0x0f)+1997); 00190 ConsolePutChar('\r'); 00191 ConsoleWrite("Media serial number: "); 00192 ConsolePutHex8(diskSect.raw.buf[10]); 00193 ConsolePutHex8(diskSect.raw.buf[11]); 00194 ConsolePutHex8(diskSect.raw.buf[12]); 00195 ConsolePutHex8(diskSect.raw.buf[13]); 00196 00197 //mediaSerialNumber[0] = diskSect.raw.buf[10]; 00198 //mediaSerialNumber[1] = diskSect.raw.buf[11]; 00199 //mediaSerialNumber[2] = diskSect.raw.buf[12]; 00200 //mediaSerialNumber[3] = diskSect.raw.buf[13]; 00201 00202 ConsolePutChar('\r'); 00203 00204 /* print out card ident register 00205 for (c=0; c<30; c++){ 00206 if ((c&0x03)==0) ConsolePutChar(' '); 00207 ConsolePutHex8(diskSect.raw.buf[c]); 00208 } 00209 */ 00210 00211 return 0; /* All OK return */ 00212 } 00213 00214 00215 00217 unsigned char RebootMMC(){ 00218 unsigned char c; 00219 00220 //Try (indefinitely) to switch on the MMC card 00221 do{ 00222 SPI8Clocks(8); 00223 /* MMC Don't use CRC - seems to be required by some MMC cards? */ 00224 MmcCommand(0x7B,0,0,0,0); 00225 /* MMC Init, command 0x40 should return 0x01 (idle) if all is ok. */ 00226 }while (MmcCommand(0x40,0,0,0,0)!=0x01); 00227 // 0x01(idle) response detected. 00228 00229 ConsoleWrite("Card found, starting... "); 00230 /*Try max 255 times MMC Wake-up call: set to Not Idle (mmc returns 0x00)*/ 00231 c=255; 00232 while ((c--)&&(MmcCommand(0x41,0,0,0,16))){ 00233 Delay(10); 00234 if (c==1){ 00235 //timeout 00236 ConsoleWrite("Failed.\r"); 00237 return 2; /* Not able to power up mmc */ 00238 } 00239 } 00240 00241 ConsoleWrite("Ok.\r"); 00242 return 0; 00243 } 00244 00245 00246 Public unsigned char InitMMC(){ 00247 unsigned char c; 00248 00249 //Switch off the MMC power supply 00250 MMC_OFF = YES; 00251 00252 ConsoleWrite ("Init: MMC\r"); 00253 Delay(100); 00254 00255 //Switch on the MMC power supply 00256 MMC_OFF = NO; 00257 Delay(100); 00258 00259 MMCSelect(); 00260 /* Allow MMC some time and clock cycles to reset */ 00261 for (c=0; c<200; c++){ 00262 SPIPutCharWithoutWaiting(0xff); 00263 SPIWait(); 00264 } 00265 Delay(20); 00266 00267 if (RebootMMC()) return 1; //not able to powerup; 00268 //An existing MMC card should be able to respond now. 00269 00270 GetStorageInformation(); 00271 00272 /* Set Block Size of 512 bytes (2 == 512 << 8) */ 00273 if ((c=MmcCommand(0x50,0,0,2,0))) return c|0x80; /* blocksize error */ 00274 00275 /* Check if MMC supports interrupted data transfer */ 00276 /* This does a simple checksum check to see if interrupted and 00277 * non-interrupted read blocks are the same. */ 00278 /* This could be a function, so it is in braces for clarity purposes */ 00279 { 00280 if (SeekSector(0)) return 2; //Storage powerup failure 00281 if (ReadPhysicalSector()) return 2; //Storage powerup failure 00282 00283 temp.i = diskSect.raw.buf[511]; 00284 for (c=0; c<250; c++){ 00285 temp.i += diskSect.raw.buf[c]; 00286 } 00287 00288 if (SeekSector(0)) return 2;//Storage powerup failure 00289 00290 /* Send some extra SPI clocks */ 00291 MMCDeselect(); 00292 SPIPutCharWithoutWaiting(0xff); 00293 for (c=0; c<100; c++){ 00294 SPIPutChar(0xff); 00295 } 00296 SPIWait(); 00297 00298 if (ReadPhysicalSector()){ 00299 ConsoleWrite("Interrupted read failed.\r"); 00300 ConsoleWrite("Using compatibility mode.\r"); 00301 return 0x0e; //ok but no support for seek-before-read 00302 00303 }else{ 00304 //Check if received data was same 00305 temp.i -= diskSect.raw.buf[511]; 00306 for (c=0; c<250; c++){ 00307 temp.i -= diskSect.raw.buf[c]; 00308 } 00309 } 00310 00311 if (temp.i) { /* Checksum does not match */ 00312 ConsoleWrite("This MMC has no support for interrupted read. "); 00313 ConsoleWrite("Using compatibility mode.\r"); 00314 return 0x0e; //ok but no support for seek-before-read 00315 } 00316 00317 ConsoleWrite("\rInitMMC ok.\r"); 00318 } 00319 00320 /* All OK return */ 00321 return 0; //ok and MMC supports seek-before-read 00322 00323 } 00324 00325 00330 void PerformBlockRead(){ 00331 00332 #ifdef MMCDEBUG 00333 ConsoleWrite("<R"); //Actual Read 00334 #endif 00335 00336 /* Use shared global buffer pointer for speed*/ 00337 /* Loop unrolled 16 times for SPEED! :) */ 00338 dataBufPtr = diskSect.raw.buf; 00339 while (dataBufPtr < diskSect.raw.buf+512){ 00340 SPIPutCharWithoutWaiting(0xff); 00341 SPIWait(); 00342 *dataBufPtr++=SPI_RESULT_BYTE; 00343 SPIPutCharWithoutWaiting(0xff); 00344 SPIWait(); 00345 *dataBufPtr++=SPI_RESULT_BYTE; 00346 SPIPutCharWithoutWaiting(0xff); 00347 SPIWait(); 00348 *dataBufPtr++=SPI_RESULT_BYTE; 00349 SPIPutCharWithoutWaiting(0xff); 00350 SPIWait(); 00351 *dataBufPtr++=SPI_RESULT_BYTE; 00352 SPIPutCharWithoutWaiting(0xff); 00353 SPIWait(); 00354 *dataBufPtr++=SPI_RESULT_BYTE; 00355 SPIPutCharWithoutWaiting(0xff); 00356 SPIWait(); 00357 *dataBufPtr++=SPI_RESULT_BYTE; 00358 SPIPutCharWithoutWaiting(0xff); 00359 SPIWait(); 00360 *dataBufPtr++=SPI_RESULT_BYTE; 00361 SPIPutCharWithoutWaiting(0xff); 00362 SPIWait(); 00363 *dataBufPtr++=SPI_RESULT_BYTE; 00364 SPIPutCharWithoutWaiting(0xff); 00365 SPIWait(); 00366 *dataBufPtr++=SPI_RESULT_BYTE; 00367 SPIPutCharWithoutWaiting(0xff); 00368 SPIWait(); 00369 *dataBufPtr++=SPI_RESULT_BYTE; 00370 SPIPutCharWithoutWaiting(0xff); 00371 SPIWait(); 00372 *dataBufPtr++=SPI_RESULT_BYTE; 00373 SPIPutCharWithoutWaiting(0xff); 00374 SPIWait(); 00375 *dataBufPtr++=SPI_RESULT_BYTE; 00376 SPIPutCharWithoutWaiting(0xff); 00377 SPIWait(); 00378 *dataBufPtr++=SPI_RESULT_BYTE; 00379 SPIPutCharWithoutWaiting(0xff); 00380 SPIWait(); 00381 *dataBufPtr++=SPI_RESULT_BYTE; 00382 SPIPutCharWithoutWaiting(0xff); 00383 SPIWait(); 00384 *dataBufPtr++=SPI_RESULT_BYTE; 00385 SPIPutCharWithoutWaiting(0xff); 00386 SPIWait(); 00387 *dataBufPtr++=SPI_RESULT_BYTE; 00388 } 00389 00390 #ifdef MMCDEBUG 00391 ConsoleWrite("R>"); 00392 #endif 00393 00394 } 00395 00397 void ConsoleDecipherMMCResponse(unsigned char c){ 00398 00399 ConsoleWrite ("\rSeek failed, MMC returns "); 00400 ConsolePutHex8 (c); 00401 ConsoleWrite ("h ("); 00402 00403 if (c&128) ConsoleWrite("which is NOT an R1 response!!"); 00404 else{ 00405 if (c&64) ConsoleWrite("ParameterError "); 00406 if (c&32) ConsoleWrite("AddressError "); 00407 if (c&16) ConsoleWrite("EraseSequenceError "); 00408 if (c&8) ConsoleWrite("CommandCrcError "); 00409 if (c&4) ConsoleWrite("IllegalCommandCode "); 00410 if (c&2) ConsoleWrite("EraseCancelled "); 00411 if (c&1) ConsoleWrite("Idle "); 00412 } 00413 00414 ConsoleWrite (") for sector "); 00415 ConsolePutUInt (sectorAddress.l); 00416 ConsoleWrite(".\rFurther reading data returns: \r"); 00417 for (c=0; c<255; c++){ 00418 ConsolePutHex8(SPIGetChar()); 00419 } 00420 ConsolePutChar(13); 00421 while (!KEY_BUTTON); 00422 00423 00424 } 00425 00426 00427 00431 Public unsigned char SeekSector(unsigned long sectorN){ 00432 unsigned char c, retries; 00433 00434 retries = 0; 00435 do{ 00436 retries++; 00437 sectorAddress.l = sectorN * 2; //convert to bytes (combined with 8bit shift) 00438 c=MmcCommand(0x51,sectorAddress.b.b2,sectorAddress.b.b1, 00439 sectorAddress.b.b0, 0); 00440 sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks 00441 00442 // If MMC works properly, it returns Busy (== Not idle) at this stage. 00443 if (c!=0x00){ 00444 if (c != 0xff){ 00445 //MMC returns something else than Busy or "Idle Bus", print what it is 00446 ConsoleDecipherMMCResponse(c); 00447 } 00448 // Something is wrong, take the standard action... 00449 RebootMMC(); 00450 if (retries > 10){ 00451 return 7; /* failed to execute mmc command */ 00452 } 00453 } 00454 }while(c!=0x00); //repeat until we get busy signal from MMC. 00455 00456 MMCDeselect(); 00457 00458 return 0; //ok return 00459 } 00460 00461 00462 /* Wait for data start token and read 512 bytes to global buffer */ 00463 Public unsigned char ReadPhysicalSector(){ 00464 00465 // RED_LED = LED_ON; /* Disk Read LED on */ 00466 00467 MMCSelect(); 00468 MmcWaitForData(); 00469 PerformBlockRead(); 00470 00471 /* generate SPI clock edges to finish up the command */ 00472 00473 SPI8Clocks(4); //Send 8*4=32 clocks (4 ff's) to MMC to be nice. 00474 MMCDeselect(); 00475 SPI8Clocks(4); //Again, give the poor MMC some clocks, it likes them. 00476 00477 //RED_LED = LED_OFF; /* Disk Read LED off */ 00478 00479 return 0; //ok return 00480 } 00481 00482 00484 unsigned char WritePhysicalSector(){ 00485 unsigned char c; 00486 00487 #ifdef MMCDEBUG 00488 ConsoleWrite("<W"); 00489 #endif 00490 00491 00492 //RED_LED = LED_ON; 00493 sectorAddress.l = sectorAddress.l * 2; //convert to bytes (combined with 8bit shift) 00494 c=MmcCommand(0x40 | 24, sectorAddress.b.b2, sectorAddress.b.b1, 00495 sectorAddress.b.b0, 0); 00496 sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks 00497 00498 //ConsolePutChar('w'); 00499 //ConsolePutHex8(c); 00500 00501 if (c!=0x00) return (c); //Error - MMC did not go to write mode 00502 00503 /* 00504 while (c!=0x00) { //wait for BUSY token, if you get 0x01(idle), it's an ERROR! 00505 c = SPIGetChar(); 00506 ConsolePutHex8(c); 00507 } 00508 */ 00509 dataBufPtr = diskSect.raw.buf; 00510 SPIPutCharWithoutWaiting(0xFE); 00511 SPIWait(); 00512 00513 for (c=0;c<128;c++){ 00514 SPIPutCharWithoutWaiting(*dataBufPtr++); 00515 SPIWait(); 00516 SPIPutCharWithoutWaiting(*dataBufPtr++); 00517 SPIWait(); 00518 SPIPutCharWithoutWaiting(*dataBufPtr++); 00519 SPIWait(); 00520 SPIPutCharWithoutWaiting(*dataBufPtr++); 00521 SPIWait(); 00522 } 00523 //ConsolePutChar('-'); 00524 00525 c = SPIGetChar(); //crc 1st byte (sends 0xff) 00526 c = SPIGetChar(); //crc 2nd byte (sends 0xff) 00527 c = SPIGetChar(); 00528 //ConsolePutHex8(c); //This prints xxx00101, (usually e5) when data ok 00529 00530 // while (SPIGetChar()!=0xff) //busy wait moved to mmcCommand 00531 // ; // Wait until MMC not busy. 00532 00533 #ifdef MMCDEBUG 00534 ConsoleWrite("W>"); 00535 #endif 00536 00537 00538 SPI8Clocks(16); 00539 MMCDeselect(); 00540 SPI8Clocks(16); 00541 00542 //RED_LED = LED_OFF; 00543 00544 return 0; 00545 } 00546 00547

All software copyright 2000-2004 VLSI Solution OY. Redistribution of these software modules are limited to promotional use only and only with the VS1011 / VS1002 / VS1003 MP3-Evakit evaluation boards. Free or commercial use of these software modules in MP3 players is ok if the product includes MP3 decoder chip(s) from VLSI. You can request the complete (compilable) package from mp3@vlsi.fi