⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc.c

📁 MP3 Player Source Code
💻 C
字号:
/** \file mmc.c * MMC interface routines for storage.c. */#include "mmc.h"#include "board.h"#include "console.h"#include "buffer.h"//#define MMCDEBUG//#define MMCLONGDEBUG/** Do one MMC command and return the MMC SPI R1 response. * Returns 0xff in case of timeout (relies on weak pull-up on the MISO pin).  * Note that the parameter bytes are  * used for temporary storage after they are written out. */unsigned char MmcCommand(unsigned char c1, 			 unsigned char c2, 			 unsigned char c3, 			 unsigned char c4, 			 unsigned char c5){  xdata char c;  /* Note: c1, c2 are used for temporary variables after use! */    MMC_OFF = NO; //MMC should be powered, but switch power on just-in-case  MMC_XCS = MMC_NOT_SELECTED; //put MMC on-line.  // Provide clock edges before and after asserting MMC CS  SPI8Clocks(8);   MMC_XCS = MMC_SELECTED;  SPI8Clocks(8);   c=0;  // If card still seems to be busy, give it some time...  while ((SPIGetChar()!=0xff) && (c<100)){    ConsolePutChar('.');    c++;  }  // The bus should be stable high now  if (SPI_RESULT_BYTE != 0xff){    ConsoleWrite("\rUnexpected busy signal from MMC. ");    MMC_XCS = MMC_NOT_SELECTED; //drop MMC offline.    return 0x81; //MMC unexpectedly Busy  }#ifdef MMCDEBUG  DebugMessage(" \x1b[7m");  ConsolePutChar('C'); ConsolePutHex8(c1); ConsolePutHex8(c2); ConsolePutHex8(c3);  ConsolePutHex8(c4); ConsolePutHex8(c5); ConsolePutChar('|');#endif  // Send the MMC command  SPIPutCharWithoutWaiting(c1);  SPIPutChar(c2);  SPIPutChar(c3);  SPIPutChar(c4);  SPIPutChar(c5);  SPIPutChar(0x95); 	/* Valid CRC for init, then don't care */  SPIWait();  /* Now ok to use c1..c5 as temporaries (dirty but kool) */  // Wait for R1 style response (bit 7 low) from MMC#ifdef MMCDEBUG   {    c1=100; /* try max. 100 times */    while((c1--)&&((c2=SPIGetChar())&0x80)){ //wait for R1 or timeout      // R1 response not detected, if it's not 0xff, print it for debugging.      if (c2!=0xff){ConsolePutHex8(c2);ConsolePutChar('|');}    }    ConsolePutHex8(c2);    DebugMessage("\x1b[0m ");  }#else   {    c1=100;    while((c1--)&&((c2=SPIGetChar())&0x80)) //wait for R1 or timeout      ;  }#endif  return c2; //return the R1 response}/** 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. */unsigned char MmcWaitForData(){  unsigned char c;  unsigned int i = 32000;    DebugMessage("<t:"); //Token Wait   // Wait until something else than 0xff is read from the bus  do {    c=SPIGetChar();#ifdef MMCDEBUG        if (c!=0xFF) ConsolePutHex8(c); //0xfe token or some erroneus byte#endif  } while ((c == 0xff)&&(--i));  if (!i){ //timeout }        ConsoleWrite("\rTimeout while waiting for block.\r");    MMC_XCS = MMC_NOT_SELECTED;    return 5; //return error  }  // Something was received from the bus? Might it actually be te   // desired 0xFE data start token?   if (c != 0xfe){    // No data start token, read fail. In an OS an error message would display.    // Since we're in an embedded system, it's unclear what we should do now.    // Current approach is to say all ok but make read block return 0xff's.    // It's not disasterous at least as long as we don't WRITE to MMC.    // Flush any data that might be pending from the MMC.#ifdef MMCLONGDEBUG        {      unsigned int i;      ConsoleWrite("\rMMCWaitForData failed. ");      ConsoleWrite("Expected 0xFE token, received: ");      for (i=0;i<550;i++){	ConsolePutHex8(c);	c=SPIGetChar();      }    }#else    SPI8Clocks(200); /* Flush MMC by sending lots of FF's to it */    SPI8Clocks(200);    SPI8Clocks(200);#endif    MMC_XCS = MMC_NOT_SELECTED; //Drop MMC offline now.    DebugMessage("!t>");    return 5; //Return error  }  DebugMessage("t>"); //Exit Token Wait  return 0;}/** Read a Data Block from MMC. * Use shared global pointer dataBufPtr declared in buffer.h.  * Does not affect MMC chip select signal.  * \warning this is not the fastest way to read, use PerformBlockRead to read entire disk block.*/void MmcGetData(unsigned int amountOctets){  DebugMessage("<G");  dataBufPtr = diskSect.raw.buf;  while (amountOctets--){    *dataBufPtr++=SPIGetChar();  }  DebugMessage("G>");}/** Returns MMC Card Identification Register in diskSect */unsigned char GetStorageInformation(){  if (MmcCommand(0x4a,0,0,0,0)&0xfe)    return 4; /* no storage info */  MmcWaitForData();  MmcGetData(30);  ConsoleWrite("\rMMC Manufacturer#: ");  ConsolePutUInt(diskSect.raw.buf[0]);  ConsoleWrite("Product Name: ");  ConsolePutChar(diskSect.raw.buf[3]);  ConsolePutChar(diskSect.raw.buf[4]);  ConsolePutChar(diskSect.raw.buf[5]);  ConsolePutChar(diskSect.raw.buf[6]);  ConsolePutChar(diskSect.raw.buf[7]);  ConsolePutChar(diskSect.raw.buf[8]);  ConsoleWrite(" Production date: ");  ConsolePutUInt(diskSect.raw.buf[14]>>4);  ConsoleWrite("/ ");  ConsolePutUInt((diskSect.raw.buf[14]&0x0f)+1997);  ConsolePutChar('\r');  ConsoleWrite("Media serial number: ");  ConsolePutHex8(diskSect.raw.buf[10]);  ConsolePutHex8(diskSect.raw.buf[11]);  ConsolePutHex8(diskSect.raw.buf[12]);  ConsolePutHex8(diskSect.raw.buf[13]);  ConsolePutChar('\r');    /* print out card ident register  for (c=0; c<30; c++){    if ((c&0x03)==0) ConsolePutChar(' ');    ConsolePutHex8(diskSect.raw.buf[c]);  }  */  return 0; /* All OK return */}/** Try to switch on the MMC */unsigned char RebootMMC(){  unsigned char c;  //Try (indefinitely) to switch on the MMC card  do{    /* MMC Don't use CRC - seems to be required by some MMC cards? */    MmcCommand(0x7B,0,0,0,0);    /* MMC Init, command 0x40 should return 0x01 (idle) if all is ok. */  }while (MmcCommand(0x40,0,0,0,0)!=0x01);  // 0x01(idle) response detected.    ConsoleWrite("Card found, starting... ");  /*Try max 255 times MMC Wake-up call: set to Not Idle (mmc returns 0x00)*/  c=255;  while ((c--)&&(MmcCommand(0x41,0,0,0,16))){    Delay(10);    if (c==1){      //timeout      ConsoleWrite("Failed.\r");      return 2; /* Not able to power up mmc */    }  }  ConsoleWrite("Ok.\r");  return 0;}Public unsigned char InitMMC(){  unsigned char c;  //Switch off the MMC power supply  MMC_OFF = YES;   ConsoleWrite ("Init: MMC\r");  Delay(100);  //Switch on the MMC power supply  MMC_OFF = NO;  Delay(100);  /* Allow MMC some time and clock cycles to reset */  for (c=0; c<200; c++){        SPIPutCharWithoutWaiting(0xff);    SPIWait();  }  Delay(20);  if (RebootMMC()) return 1; //not able to powerup;  //An existing MMC card should be able to respond now.  GetStorageInformation();    /* Set Block Size of 512 bytes (2 == 512 << 8) */  if ((c=MmcCommand(0x50,0,0,2,0))) return c|0x80; /* blocksize error */    ConsoleWrite("Scanning storage... ");  /* Check if MMC supports interrupted data transfer */  /* This does a simple checksum check to see if interrupted and    * non-interrupted read blocks are the same. */  /* This could be a function, so it is in braces for clarity purposes */  {      if (SeekSector(0)) return 2; //Storage powerup failure        if (ReadPhysicalSector()) return 2; //Storage powerup failure    temp.i = diskSect.raw.buf[511];    for (c=0; c<250; c++){      temp.i += diskSect.raw.buf[c];    }        ConsoleWrite("Testing for seek mode...");    if (SeekSector(0)) return 2;//Storage powerup failure        /* Send some extra SPI clocks */    MMC_XCS = MMC_NOT_SELECTED;    SPIPutCharWithoutWaiting(0xff);    for (c=0; c<100; c++){      SPIPutChar(0xff);    }    SPIWait();    if (ReadPhysicalSector()){      ConsoleWrite("Interrupted read failed.\r");      ConsoleWrite("Using compatibility mode.\r");      return 0x0e; //ok but no support for seek-before-read          }else{            //Check if received data was same      temp.i -= diskSect.raw.buf[511];      for (c=0; c<250; c++){	temp.i -= diskSect.raw.buf[c];      }    }        if (temp.i) { /* Checksum does not match */      ConsoleWrite("This MMC has no support for interrupted read. ");      ConsoleWrite("Using compatibility mode.\r");      return 0x0e; //ok but no support for seek-before-read    }        ConsoleWrite("\rInitMMC ok.\r");  }  /* All OK return */  return 0; //ok and MMC supports seek-before-read}/** Perform the actual reading of 512 octets from MMC. * Note: This is the fast routine to read complete disk block */void PerformBlockRead(){#ifdef MMCDEBUG  ConsoleWrite("<R"); //Actual Read#endif  /* Use shared global buffer pointer for speed*/  /* Loop unrolled 16 times for SPEED! :) */  dataBufPtr = diskSect.raw.buf;  while (dataBufPtr < diskSect.raw.buf+512){    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;    SPIPutCharWithoutWaiting(0xff);    SPIWait();    *dataBufPtr++=SPI_RESULT_BYTE;  }#ifdef MMCDEBUG    ConsoleWrite("R>");#endif}/** Print a human-readable R1 response to console */void ConsoleDecipherMMCResponse(unsigned char c){    ConsoleWrite ("\rSeek failed, MMC returns ");    ConsolePutHex8 (c);    ConsoleWrite ("h (");            if (c&128) ConsoleWrite("which is NOT an R1 response!!");    else{      if (c&64) ConsoleWrite("ParameterError ");      if (c&32) ConsoleWrite("AddressError ");      if (c&16) ConsoleWrite("EraseSequenceError ");      if (c&8) ConsoleWrite("CommandCrcError ");      if (c&4) ConsoleWrite("IllegalCommandCode ");      if (c&2) ConsoleWrite("EraseCancelled ");      if (c&1) ConsoleWrite("Idle ");    }        ConsoleWrite (") for sector ");    ConsolePutUInt (sectorAddress.l);    ConsoleWrite(".\rFurther reading data returns: \r");    for (c=0; c<255; c++){      ConsolePutHex8(SPIGetChar());	    }    ConsolePutChar(13);    while (!KEY_BUTTON);}/* Unconditionally (really just do it!) seek MMC at offset sectorN*512 */Public unsigned char SeekSector(unsigned long sectorN){    unsigned char c;  #ifdef MMCDEBUG      ConsoleWrite("{s"); //Seek called#endif  do{    sectorAddress.l = sectorN * 2; //convert to bytes (combined with 8bit shift)    c=MmcCommand(0x51,sectorAddress.b.b2,sectorAddress.b.b1,		 sectorAddress.b.b0, 0);    sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks    //if MMC returs "nothing" (0xff) or 0x81(busy),     //toggle chip select and retry    if ((c==0xff)||(c==0x81)){      c=0xff;      RebootMMC();    }    if (c==0x01){ //MMC says "busy"      c=0xff; //try again    }  }while(c==0xff); //repeat until we get signal from MMC.    if ((c & 0xfe)){ //MMC returns something else than idle or busy signal    ConsoleDecipherMMCResponse(c);    MMC_XCS = MMC_NOT_SELECTED;#ifdef MMCDEBUG    ConsoleWrite("!s}");#endif    return 7; /* failed to execute mmc command */  }    MMC_XCS = MMC_NOT_SELECTED;  #ifdef MMCDEBUG  ConsoleWrite("s}");#endif  return 0; //ok return}/* Wait for data start token and read 512 bytes to global buffer */Public unsigned char ReadPhysicalSector(){  RED_LED = LED_ON; /* Disk Read LED on */  MMC_XCS = MMC_SELECTED;  //ConsoleWrite("<wait>");  MmcWaitForData();    //ConsoleWrite("<read>");  PerformBlockRead();  //ConsoleWrite("<deselect>");  /* generate SPI clock edges to finish up the command */  SPI8Clocks(4); //Send 8*4=32 clocks (4 ff's) to MMC to be nice.  MMC_XCS = MMC_NOT_SELECTED;  SPI8Clocks(4); //Again, give the poor MMC some clocks, it likes them.  RED_LED = LED_OFF; /* Disk Read LED off */  return 0; //ok return}/** Perform MMC block write from diskSect */unsigned char WritePhysicalSector(){  unsigned char c;  #ifdef MMCDEBUG  ConsoleWrite("<W");#endif    RED_LED = LED_ON;  sectorAddress.l = sectorAddress.l * 2; //convert to bytes (combined with 8bit shift)  c=MmcCommand(24 | 0x40 ,sectorAddress.b.b2,sectorAddress.b.b1,	       sectorAddress.b.b0, 0);  sectorAddress.l = sectorAddress.l >> 1; //convert back to blocks  MMC_XCS = MMC_SELECTED;   dataBufPtr = diskSect.raw.buf;  SPIPutCharWithoutWaiting(0xFE);  SPIWait();    for (c=0;c<128;c++){    SPIPutCharWithoutWaiting(*dataBufPtr++);       SPIWait();    SPIPutCharWithoutWaiting(*dataBufPtr++);       SPIWait();    SPIPutCharWithoutWaiting(*dataBufPtr++);       SPIWait();    SPIPutCharWithoutWaiting(*dataBufPtr++);       SPIWait();  }  MmcWaitForData(); //Wait for 0xFE token  while (SPIGetChar()==0)     ; // Wait until MMC not busy.     #ifdef MMCDEBUG  ConsoleWrite("W>");#endif      SPI8Clocks(16);  MMC_XCS = MMC_NOT_SELECTED;  SPI8Clocks(16);  RED_LED = LED_OFF;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -