VLSI Solution Oy VS1103 VLSI Solution Karaoke, MIDI and ADPCM 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 
00250   ConsoleWrite ("Init: MMC\r");
00251   MMCSelect();
00252   /* Allow MMC some time and clock cycles to reset */
00253   for (c=0; c<200; c++){    
00254     SPIPutCharWithoutWaiting(0xff);
00255     SPIWait();
00256   }
00257   Delay(20);
00258 
00259   if (RebootMMC()) return 1; //not able to powerup;
00260   //An existing MMC card should be able to respond now.
00261 
00262   GetStorageInformation();
00263   
00264   /* Set Block Size of 512 bytes (2 == 512 << 8) */
00265   if ((c=MmcCommand(0x50,0,0,2,0))) return c|0x80; /* blocksize error */
00266   
00267   /* Check if MMC supports interrupted data transfer */
00268   /* This does a simple checksum check to see if interrupted and 
00269    * non-interrupted read blocks are the same. */
00270   /* This could be a function, so it is in braces for clarity purposes */
00271   {  
00272     if (SeekSector(0)) return 2; //Storage powerup failure    
00273     if (ReadPhysicalSector()) return 2; //Storage powerup failure
00274 
00275     temp.i = diskSect.raw.buf[511];
00276     for (c=0; c<250; c++){
00277       temp.i += diskSect.raw.buf[c];
00278     }
00279     
00280     if (SeekSector(0)) return 2;//Storage powerup failure
00281     
00282     /* Send some extra SPI clocks */
00283     MMCDeselect();
00284     SPIPutCharWithoutWaiting(0xff);
00285     for (c=0; c<100; c++){
00286       SPIPutChar(0xff);
00287     }
00288     SPIWait();
00289     
00290     if (ReadPhysicalSector()){
00291       ConsoleWrite("Interrupted read failed.\r");
00292       ConsoleWrite("Using compatibility mode.\r");
00293       return 0x0e; //ok but no support for seek-before-read
00294       
00295     }else{
00296       //Check if received data was same
00297       temp.i -= diskSect.raw.buf[511];
00298       for (c=0; c<250; c++){
00299         temp.i -= diskSect.raw.buf[c];
00300       }
00301     }
00302     
00303     if (temp.i) { /* Checksum does not match */
00304       ConsoleWrite("This MMC has no support for interrupted read. ");
00305       ConsoleWrite("Using compatibility mode.\r");
00306       return 0x0e; //ok but no support for seek-before-read
00307     }
00308     
00309     ConsoleWrite("\rInitMMC ok.\r");
00310   }
00311 
00312   /* All OK return */
00313   return 0; //ok and MMC supports seek-before-read
00314 
00315 }
00316 
00317 
00318 
00319 #define USE_C_CODE_INSTEAD_OF_ASM 0
00320 
00325 void PerformBlockRead(){
00326 
00327 #ifdef MMCDEBUG
00328   ConsoleWrite("<R"); //Actual Read
00329 #endif
00330 
00331   // LED1 = LED_ON;
00332 
00333   /* Use shared global buffer pointer for speed*/
00334   /* Loop unrolled 16 times for SPEED! :) */
00335   dataBufPtr = diskSect.raw.buf;
00336 
00337 
00338 
00339 #if USE_C_CODE_INSTEAD_OF_ASM
00340 
00341   while (dataBufPtr < diskSect.raw.buf+512){
00342     SPIPutCharWithoutWaiting(0xff);
00343     SPIWait();
00344     *dataBufPtr++=SPI_RESULT_BYTE;
00345     SPIPutCharWithoutWaiting(0xff);
00346     SPIWait();
00347     *dataBufPtr++=SPI_RESULT_BYTE;
00348     SPIPutCharWithoutWaiting(0xff);
00349     SPIWait();
00350     *dataBufPtr++=SPI_RESULT_BYTE;
00351     SPIPutCharWithoutWaiting(0xff);
00352     SPIWait();
00353     *dataBufPtr++=SPI_RESULT_BYTE;
00354     SPIPutCharWithoutWaiting(0xff);
00355     SPIWait();
00356     *dataBufPtr++=SPI_RESULT_BYTE;
00357     SPIPutCharWithoutWaiting(0xff);
00358     SPIWait();
00359     *dataBufPtr++=SPI_RESULT_BYTE;
00360     SPIPutCharWithoutWaiting(0xff);
00361     SPIWait();
00362     *dataBufPtr++=SPI_RESULT_BYTE;
00363     SPIPutCharWithoutWaiting(0xff);
00364     SPIWait();
00365     *dataBufPtr++=SPI_RESULT_BYTE;
00366     SPIPutCharWithoutWaiting(0xff);
00367     SPIWait();
00368     *dataBufPtr++=SPI_RESULT_BYTE;
00369     SPIPutCharWithoutWaiting(0xff);
00370     SPIWait();
00371     *dataBufPtr++=SPI_RESULT_BYTE;
00372     SPIPutCharWithoutWaiting(0xff);
00373     SPIWait();
00374     *dataBufPtr++=SPI_RESULT_BYTE;
00375     SPIPutCharWithoutWaiting(0xff);
00376     SPIWait();
00377     *dataBufPtr++=SPI_RESULT_BYTE;
00378     SPIPutCharWithoutWaiting(0xff);
00379     SPIWait();
00380     *dataBufPtr++=SPI_RESULT_BYTE;
00381     SPIPutCharWithoutWaiting(0xff);
00382     SPIWait();
00383     *dataBufPtr++=SPI_RESULT_BYTE;
00384     SPIPutCharWithoutWaiting(0xff);
00385     SPIWait();
00386     *dataBufPtr++=SPI_RESULT_BYTE;
00387     SPIPutCharWithoutWaiting(0xff);
00388     SPIWait();
00389     *dataBufPtr++=SPI_RESULT_BYTE;
00390   }
00391 
00392 #else
00393 
00394    // BlockRead in Assembler
00395 
00396    _asm
00397         //asm prologue start
00398         push    psw
00399         push    acc
00400         mov     a,r2
00401         push    acc
00402         push    dpl
00403         push    dph
00404         //prologue end
00405      
00406         mov     dpl,_dataBufPtr
00407         mov     dph,(_dataBufPtr + 1)
00408 2106$:
00409         clr     c
00410         mov     a,_dataBufPtr
00411         subb    a,#(_diskSect + 0x0200)
00412         mov     a,(_dataBufPtr + 1)
00413         subb    a,#((_diskSect + 0x0200) >> 8)
00414         jc     2122$
00415         ljmp   2108$
00416 2122$:
00417         mov     _SPDAT,#0xFF
00418         mov     dpl,_dataBufPtr
00419         mov     dph,(_dataBufPtr + 1)
00420 
00421         mov     a,_SPSTA
00422         mov     a,_SPDAT
00423         mov     _SPDAT,#0xFF
00424         movx    @dptr,a
00425         inc     dptr
00426 
00427         mov     a,_SPSTA
00428         mov     a,_SPDAT
00429         mov     _SPDAT,#0xFF
00430         movx    @dptr,a
00431         inc     dptr
00432 
00433         mov     a,_SPSTA
00434         mov     a,_SPDAT
00435         mov     _SPDAT,#0xFF
00436         movx    @dptr,a
00437         inc     dptr
00438 
00439         mov     a,_SPSTA
00440         mov     a,_SPDAT
00441         mov     _SPDAT,#0xFF
00442         movx    @dptr,a
00443         inc     dptr
00444 
00445         mov     a,_SPSTA
00446         mov     a,_SPDAT
00447         mov     _SPDAT,#0xFF
00448         movx    @dptr,a
00449         inc     dptr
00450 
00451         mov     a,_SPSTA
00452         mov     a,_SPDAT
00453         mov     _SPDAT,#0xFF
00454         movx    @dptr,a
00455         inc     dptr
00456 
00457         mov     a,_SPSTA
00458         mov     a,_SPDAT
00459         mov     _SPDAT,#0xFF
00460         movx    @dptr,a
00461         inc     dptr
00462 
00463         mov     a,_SPSTA
00464         mov     a,_SPDAT
00465         mov     _SPDAT,#0xFF
00466         movx    @dptr,a
00467         inc     dptr
00468 
00469         mov     a,_SPSTA
00470         mov     a,_SPDAT
00471         mov     _SPDAT,#0xFF
00472         movx    @dptr,a
00473         inc     dptr
00474 
00475         mov     a,_SPSTA
00476         mov     a,_SPDAT
00477         mov     _SPDAT,#0xFF
00478         movx    @dptr,a
00479         inc     dptr
00480 
00481         mov     a,_SPSTA
00482         mov     a,_SPDAT
00483         mov     _SPDAT,#0xFF
00484         movx    @dptr,a
00485         inc     dptr
00486 
00487         mov     a,_SPSTA
00488         mov     a,_SPDAT
00489         mov     _SPDAT,#0xFF
00490         movx    @dptr,a
00491         inc     dptr
00492 
00493         mov     a,_SPSTA
00494         mov     a,_SPDAT
00495         mov     _SPDAT,#0xFF
00496         movx    @dptr,a
00497         inc     dptr
00498 
00499         mov     a,_SPSTA
00500         mov     a,_SPDAT
00501         mov     _SPDAT,#0xFF
00502         movx    @dptr,a
00503         inc     dptr
00504 
00505         mov     a,_SPSTA
00506         mov     a,_SPDAT
00507         mov     _SPDAT,#0xFF
00508         movx    @dptr,a
00509         inc     dptr
00510 
00511         mov     a,_SPSTA
00512         mov     a,_SPDAT
00513         movx    @dptr,a
00514         inc     dptr
00515 
00516 
00517         mov     a, dph
00518         mov     (_dataBufPtr + 1),a
00519         mov     a, dpl
00520         mov     _dataBufPtr,a
00521 
00522         ljmp    2106$
00523 2108$:        
00524         //asm epilogue start
00525         pop     dph
00526         pop     dpl
00527         pop     acc
00528         mov     r2,a
00529         pop     acc
00530         pop     psw     
00531         //epilogue end
00532    _endasm;
00533 
00534 
00535 
00536 
00537 #endif
00538 
00539 
00540 
00541 
00542 #ifdef MMCDEBUG
00543     ConsoleWrite("R>");
00544 #endif
00545 
00546     //  LED1 = LED_OFF;
00547 
00548 }
00549 
00550 
00551 
00555 Public unsigned char SeekSector(unsigned long sectorN){
00556   unsigned char c, retries;
00557 
00558   retries = 0;
00559   do{
00560     retries++;
00561     sectorAddress.l = sectorN * 2; //convert to bytes (combined with 8bit shift)
00562     c=MmcCommand(0x51,sectorAddress.b.b2,sectorAddress.b.b1,
00563                  sectorAddress.b.b0, 0);
00564     sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks
00565 
00566     // If MMC works properly, it returns Busy (== Not idle) at this stage.    
00567     if (c!=0x00){
00568       if (c != 0xff){ 
00569         //MMC returns something else than Busy or "Idle Bus", print what it is
00570         //ConsoleDecipherMMCResponse(c);
00571       }
00572       // Something is wrong, take the standard action...
00573       RebootMMC();
00574       if (retries > 10){  
00575         return 7; /* failed to execute mmc command */
00576       }
00577     }
00578   }while(c!=0x00); //repeat until we get busy signal from MMC.
00579     
00580   MMCDeselect();
00581   
00582   return 0; //ok return
00583 }
00584 
00585 
00586 /* Wait for data start token and read 512 bytes to global buffer */
00587 Public unsigned char ReadPhysicalSector(){
00588 
00589   // RED_LED = LED_ON; /* Disk Read LED on */
00590 
00591   MMCSelect();
00592   MmcWaitForData();
00593   PerformBlockRead();
00594 
00595   /* generate SPI clock edges to finish up the command */
00596 
00597   SPI8Clocks(4); //Send 8*4=32 clocks (4 ff's) to MMC to be nice.
00598   MMCDeselect();
00599   SPI8Clocks(4); //Again, give the poor MMC some clocks, it likes them.
00600 
00601   //RED_LED = LED_OFF; /* Disk Read LED off */
00602 
00603   return 0; //ok return
00604 }
00605 
00606 
00607 
00609 unsigned char WritePhysicalSector(){
00610   unsigned char c;  
00611 
00612 #ifdef MMCDEBUG
00613   ConsoleWrite("<W");
00614 #endif  
00615 
00616 
00617   //RED_LED = LED_ON;
00618   sectorAddress.l = sectorAddress.l * 2; //convert to bytes (combined with 8bit shift)
00619   c=MmcCommand(0x40 | 24, sectorAddress.b.b2, sectorAddress.b.b1,
00620                sectorAddress.b.b0, 0);
00621   sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks
00622 
00623   //ConsolePutChar('w');
00624   //ConsolePutHex8(c);
00625   
00626   if (c!=0x00) return (c); //Error - MMC did not go to write mode
00627   
00628 /*
00629   while (c!=0x00) { //wait for BUSY token, if you get 0x01(idle), it's an ERROR!
00630     c = SPIGetChar();
00631     ConsolePutHex8(c);
00632   }      
00633 */  
00634   //dataBufPtr = diskSect.raw.buf;//already set!
00635   SPIPutCharWithoutWaiting(0xFE);
00636   SPIWait();
00637   
00638   for (c=0;c<32;c++){
00639     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00640     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00641     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00642     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00643     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00644     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00645     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00646     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00647     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00648     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00649     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00650     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00651     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00652     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00653     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00654     SPIPutCharWithoutWaiting(*dataBufPtr++);   
00655   }
00656   //ConsolePutChar('-');
00657 
00658   c = SPIGetChar();  //crc 1st byte (sends 0xff)
00659   c = SPIGetChar(); //crc 2nd byte (sends 0xff)
00660   c = SPIGetChar();
00661   //ConsolePutHex8(c); //This prints xxx00101, (usually e5) when data ok
00662   
00663 //  while (SPIGetChar()!=0xff)      //busy wait moved to mmcCommand
00664 //    ; // Wait until MMC not busy.     
00665 
00666 #ifdef MMCDEBUG
00667   ConsoleWrite("W>");
00668 #endif  
00669 
00670   
00671   SPI8Clocks(16);
00672   MMCDeselect();
00673   SPI8Clocks(16);
00674 
00675   //RED_LED = LED_OFF;
00676 
00677   return 0;
00678 }
00679 
00680 
00681 
00682 
00683 

All software copyright 2000-2004 VLSI Solution OY. Redistribution of these software modules is limited to VLSI Solution Oy chip promotional use only. Free or commercial use of these software modules in MP3 players is ok if the product includes chip(s) from VLSI. You can request the complete (compilable) package from mp3@vlsi.fi. This exampe code is provided with good faith to assist You in code development, but under no circumstances will VLSI offer any guarantees on the usability or functionality of any example software or its fitness for any purpose.