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.h File Reference

MMC interface routines for storage.c. More...

This graph shows which files directly or indirectly include this file:

Included by dependency graph

Go to the source code of this file.

Functions

unsigned char InitMMC ()
 Start-up the MMC card.
unsigned char SeekSector (unsigned long sectorN)
 Perform MMC Seek Command for offset sectorN*512.
unsigned char ReadPhysicalSector ()
 Perform block read of previously sought sector to diskSect.
unsigned char WritePhysicalSector ()
 Perform MMC block write from *dataBufPtr to sector sectorAddress.l.
unsigned char MmcWaitForData ()
 MMC Wait For Data start token 0xfe.
void PerformBlockRead ()
 Perform the actual reading of 512 octets from MMC.

Variables

xdata unsigned char storageFlags


Detailed Description

MMC interface routines for storage.c.

Definition in file mmc.h.


Function Documentation

unsigned char InitMMC  ) 
 

Start-up the MMC card.

  • Returns 0 when successful and supports seek-before-read
  • Returns 0x0e when successful but no support for seek-before-read
  • Returns 1 when MMC card is not found
  • Returns 2 when MMC card seems to be present but can't be read from.

Definition at line 246 of file mmc.c.

References DiskBlock::Raw::buf, ConsoleWrite, Delay(), diskSect, GetStorageInformation(), Temp::i, MmcCommand(), MMCDeselect, MMCSelect, Public, DiskBlock::raw, ReadPhysicalSector(), RebootMMC(), SeekSector(), SPIPutChar, SPIPutCharWithoutWaiting, SPIWait, and temp.

Referenced by InitStorage().

00246                               {
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 }

Here is the call graph for this function:

unsigned char MmcWaitForData  ) 
 

MMC Wait For Data start token 0xfe.

First any 0xFF's are read off the mmc. The first non-ff octet is examined. If it's the 0xfe data start token, everything is fine. If not, then some error has occurred. Since we're in an embedded system, it's unclear what we should do then. Current approach is to say all ok but make read block return 0xff's by dropping the MMC card offline. Before that we read "lots" of octets from the MMC to flush any pending data. Finally we return "ALL OK". It's not disasterous at least as long as we don't WRITE to MMC. 12/2005: Well, now we do write to mmc...

Definition at line 105 of file mmc.c.

References ConsolePutHex8, ConsoleWrite, DebugMessage, MMCDeselect, SPI8Clocks(), and SPIGetChar().

Referenced by GetStorageInformation(), ReadPhysicalSector(), TransferSectorSCI(), and TransferSectorSDI().

00105                               {
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 }

Here is the call graph for this function:

void PerformBlockRead  ) 
 

Perform the actual reading of 512 octets from MMC.

Note: This is the fast routine to read complete disk block If you have DMA, write this to use it!

Definition at line 325 of file mmc.c.

References DiskBlock::Raw::buf, ConsoleWrite, dataBufPtr, diskSect, DiskBlock::raw, SPIPutCharWithoutWaiting, and SPIWait.

Referenced by ReadPhysicalSector(), TransferSectorSCI(), and TransferSectorSDI().

00325                        {
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 }

unsigned char ReadPhysicalSector  ) 
 

Perform block read of previously sought sector to diskSect.

Definition at line 587 of file mmc.c.

References MMCDeselect, MMCSelect, MmcWaitForData(), PerformBlockRead(), Public, and SPI8Clocks().

Referenced by InitMMC(), and ReadDiskSector().

00587                                          {
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 }

Here is the call graph for this function:

unsigned char SeekSector unsigned long  sectorN  ) 
 

Perform MMC Seek Command for offset sectorN*512.

In English: Send the Read Sector command to MMC

Definition at line 555 of file mmc.c.

References Address::b, Address::B::b0, Address::B::b1, Address::B::b2, Address::l, MmcCommand(), MMCDeselect, Public, RebootMMC(), and sectorAddress.

Referenced by InitMMC(), ReadDiskSector(), TransferSectorSCI(), and TransferSectorSDI().

00555                                                       {
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 }

Here is the call graph for this function:

unsigned char WritePhysicalSector  ) 
 

Perform MMC block write from *dataBufPtr to sector sectorAddress.l.

Definition at line 609 of file mmc.c.

References Address::b, Address::B::b0, Address::B::b1, Address::B::b2, ConsoleWrite, dataBufPtr, Address::l, MmcCommand(), MMCDeselect, sectorAddress, SPI8Clocks(), SPIGetChar(), SPIPutCharWithoutWaiting, and SPIWait.

Referenced by WriteDiskSector().

00609                                    {
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 }

Here is the call graph for this function:


Variable Documentation

xdata unsigned char storageFlags
 


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.