SD Card Interface class. Log raw data bytes to memory addresses of your choice, or format the card and use the FAT file system to write files.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SDCard.cpp Source File

SDCard.cpp

00001 //mbed Microcontroller Library
00002 //SDCard Interface
00003 //Copyright 2010
00004 //Thomas Hamilton
00005 
00006 #include "SDCard.h"
00007 
00008 SDCard::SDCard(PinName mosi, PinName miso, PinName sck, PinName cs,
00009     const char* DiskName) :
00010     FATFileSystem(DiskName), DataLines(mosi, miso, sck), ChipSelect(cs),
00011     t(0), Timeout(1024), CRCMode(1), Capacity(0), Version(0), Status(0x00)
00012     //card always starts uninitialized and in CRC mode; version 1 low-capacity
00013     //card protocols are backwards-compatible with all other card protocols
00014 {
00015     DataLines.frequency(100000);
00016         //set universal speed
00017     ChipSelect.write(1);
00018         //deselect the chip
00019     GenerateCRCTable(1, 137, CommandCRCTable);
00020         //generate the CRC7 lookup table; polynomial x^7 + x^3 + 1 converts to
00021         //decimal 137
00022     GenerateCRCTable(2, 69665, DataCRCTable);
00023         //generate the crc16 lookup table; polynomial x^16 + x^12 + x^5 + 1
00024         //converts to decimal 69665
00025     Initialize();
00026         //run setup operations
00027 }
00028 
00029 SDCard::~SDCard()
00030     //delete all tables and card data registers
00031 {
00032     delete[] CommandCRCTable;
00033     delete[] DataCRCTable;
00034     delete[] OCR;
00035     delete[] CSD;
00036     delete[] FSR;
00037     delete this;
00038 }
00039 
00040 unsigned char SDCard::disk_initialize()
00041     //give the FAT module access to the card setup routine
00042 {
00043     if (Status == 0x01)
00044     {
00045         return Initialize();
00046     }
00047     else
00048     {
00049         return Status;
00050     }
00051 }
00052 unsigned char SDCard::disk_status()
00053     //return card initialization and availability status
00054 { return Status; }
00055 unsigned char SDCard::disk_read(
00056     unsigned char* buff, unsigned long sector, unsigned char count)
00057     //give the FAT module access to the multiple-sector reading function
00058 { return Read((unsigned int)sector, count, buff); }
00059 unsigned char SDCard::disk_write(
00060     const unsigned char* buff, unsigned long sector, unsigned char count)
00061     //give the FAT module access to the multiple-sector writing function
00062 { return Write((unsigned int)sector, count, (unsigned char*)buff); }
00063 unsigned char SDCard::disk_sync()
00064     //the disk is always synchronized, so return "disk ready"
00065 { return 0x00; }
00066 unsigned long SDCard::disk_sector_count()
00067     //calculate and return the number of sectors on the card from the CSD
00068 {
00069     switch (CSD[0] & 0xC0)
00070     {
00071         case 0x00:
00072             //calculate sector count as specified for version 1 cards
00073             return ((((CSD[6] & 0x03) << 10) | (CSD[7] << 2)
00074                 | ((CSD[8] & 0xC0) >> 6)) + 1)
00075                 * (1 << ((((CSD[9] & 0x03) << 1)
00076                 | ((CSD[10] & 0x80) >> 7)) + 2));
00077         case 0x40:
00078             //calculate sector count as specified for version 2 cards
00079             return ((((CSD[7] & 0x3F) << 16)
00080                 | (CSD[8] << 8) | CSD[9]) + 1) * 1024;
00081         default:
00082             return 0;
00083     }
00084 }
00085 unsigned short SDCard::disk_sector_size()
00086     //fix the sector size to 512 bytes for all cards versions
00087 { return 512; }
00088 unsigned long SDCard::disk_block_size()
00089     //calculate and return the number of sectors in an erase block from the CSD
00090 {
00091     if (Version)
00092         //the erase sector size is the allocation unit for version 2 cards
00093     {
00094         return 1;
00095     }
00096     else
00097         //calculate the erase sector size for version 1 cards
00098     {
00099         return (CSD[10] << 1) | (CSD[11] >> 7) + 1;
00100     }
00101 }
00102 
00103 unsigned char SDCard::Format(unsigned int AllocationUnit)
00104     //call the FAT module formatting function
00105 {
00106     if (format(AllocationUnit))
00107     {
00108         return 0x01;
00109     }
00110     else
00111     {
00112         return 0x00;
00113     }
00114 }
00115 
00116 unsigned char SDCard::Log(unsigned char Control, unsigned char Data)
00117 {
00118     static unsigned char Workspace;
00119         //work area for card commands and data transactions
00120     static unsigned short Index = 0;
00121         //store last written byte number of current memory block
00122     static unsigned char Mode = 0x00;
00123         //store previous operating mode to determine current behavior
00124 
00125     SelectCRCMode(0);
00126         //CRC's are not used in raw data mode
00127 
00128     switch (Control)
00129     {
00130         case 0x00:
00131             //control code 0x00 synchronizes the card
00132             if (Mode)
00133                 //if the card is in read or write mode, synchronize the card
00134             {
00135                 ChipSelect.write(0);
00136                 for (; Index < 512; Index++)
00137                     //get through the left over space, filling with 0xFF
00138                 {
00139                     DataLines.write(0xFF);
00140                 }
00141                 DataLines.write(0xFF);
00142                 DataLines.write(0xFF);
00143                     //get through the CRC
00144                 ChipSelect.write(1);
00145                 if (Mode == 0x01)
00146                     //if the card is in write mode, finish the current sector
00147                     //and finalize the writing operation
00148                 {
00149                     ChipSelect.write(0);
00150                     t = 0;
00151                     do
00152                     {
00153                         t++;
00154                     } while (((DataLines.write(0xFF) & 0x11) != 0x01)
00155                         && (t < Timeout));
00156                         //get through the data response token
00157                     while (!DataLines.write(0xFF));
00158                         //get through the busy signal
00159                     DataLines.write(0xFD);
00160                     DataLines.write(0xFF);
00161                         //send the stop transmission token
00162                     while (!DataLines.write(0xFF));
00163                         //get through the busy signal
00164                     ChipSelect.write(1);
00165                     DataLines.write(0xFF);
00166                 }
00167                 else
00168                     //if the card is in read mode, finish the current sector
00169                     //and finalize the reading operation
00170                 {
00171                     Command(12, 0, &Workspace);
00172                         //send the stop transmission command
00173                     ChipSelect.write(0);
00174                     while (!DataLines.write(0xFF));
00175                         //get through the busy signal
00176                     ChipSelect.write(1);
00177                     DataLines.write(0xFF);
00178                 }
00179                 Index = 0;
00180                 Mode = 0x00;
00181                     //reset the index to the start and switch the mode to
00182                     //synchronized mode
00183             }
00184             return 0xFF;
00185 
00186         case 0x01:
00187                 //control code 1 writes a byte
00188             if (Mode != 0x01)
00189                 //if the previous call was not a write operation, synchronize
00190                 //the card, start a new write block, and set the function to
00191                 //write mode
00192             {
00193                 Log(0, 0);
00194                 Command(25, 0, &Workspace);
00195                 Mode = 0x01;
00196             }
00197             if (Index == 0)
00198                 //if the index is at the start, send the start block token
00199                 //before the byte
00200             {
00201                 ChipSelect.write(0);
00202                 DataLines.write(0xFC);
00203                 DataLines.write(Data);
00204                 ChipSelect.write(1);
00205                 Index++;
00206             }
00207             else if (Index < 511)
00208                 //if the index is between the boundaries, write the byte
00209             {
00210                 ChipSelect.write(0);
00211                 DataLines.write(Data);
00212                 ChipSelect.write(1);
00213                 Index++;
00214             }
00215             else
00216                 //if the index is at the last address, get through the CRC,
00217                 //data response token, and busy signal and reset the index
00218             {
00219                 ChipSelect.write(0);
00220                 DataLines.write(Data);
00221                 DataLines.write(0xFF);
00222                 DataLines.write(0xFF);
00223                 t = 0;
00224                 do
00225                 {
00226                     t++;
00227                 } while (((DataLines.write(0xFF) & 0x11) != 0x01)
00228                     && (t < Timeout));
00229                 while (!DataLines.write(0xFF));
00230                 ChipSelect.write(1);
00231                 Index = 0;
00232             }
00233             return 0xFF;
00234 
00235         case 0x02:
00236             //control code 2 reads a byte
00237             if (Mode != 0x02)
00238                 //if the previous call was not a read operation, synchronise
00239                 //the card, start a new read block, and set the function to
00240                 //read mode
00241             {
00242                 Log(0, 0);
00243                 Command(18, 0, &Workspace);
00244                 Mode = 0x02;
00245             }
00246             if (Index == 0)
00247                 //if the index is at the start, get the start block token
00248                 //and read the first byte
00249             {
00250                 ChipSelect.write(0);
00251                 t = 0;
00252                 do
00253                 {
00254                     t++;
00255                 } while ((DataLines.write(0xFF) != 0xFE)
00256                     && (t < Timeout));
00257                 Workspace = DataLines.write(0xFF);
00258                 ChipSelect.write(1);
00259                 Index++;
00260                 return Workspace;
00261             }
00262             else if (Index < 511)
00263                 //if the index is between the boundaries, read the byte
00264             {
00265                 ChipSelect.write(0);
00266                 Workspace = DataLines.write(0xFF);
00267                 ChipSelect.write(1);
00268                 Index++;
00269                 return Workspace;
00270             }
00271             else
00272                 //if the index is at the last address, get through the CRC and
00273                 //reset the index
00274             {
00275                 ChipSelect.write(0);
00276                 Workspace = DataLines.write(0xFF);
00277                 DataLines.write(0xFF);
00278                 DataLines.write(0xFF);
00279                 ChipSelect.write(1);
00280                 Index = 0;
00281                 return Workspace;
00282             }
00283 
00284         default:
00285             //undefined control codes will only return stuff bits
00286             return 0xFF;
00287     }
00288 }
00289 
00290 unsigned char SDCard::Write(unsigned int Address, unsigned char* Data)
00291 {
00292     unsigned char Workspace[2];
00293         //work area for card commands and data transactions
00294     
00295     if (Capacity)
00296         //send the single-block write command addressed for high-capacity cards
00297     {
00298         Command(24, Address, Workspace);
00299     }
00300     else
00301         //send the single-block write command addressed for low-capacity cards
00302     {
00303         Command(24, Address * 512, Workspace);
00304     }
00305     if (Workspace[0])
00306         //if a command error occurs, return "parameter error"
00307     { return 0x04; }
00308     DataCRC(512, Data, Workspace);
00309         //calculate the CRC16
00310     ChipSelect.write(0);
00311     DataLines.write(0xFE);
00312         //write start block token
00313     for (unsigned short i = 0; i < 512; i++)
00314         //write the data to the addressed card sector
00315     {
00316         DataLines.write(Data[i]);
00317     }
00318     DataLines.write(Workspace[0]);
00319     DataLines.write(Workspace[1]);
00320         //write the data CRC16
00321     t = 0;
00322     do
00323     {
00324         Workspace[0] = DataLines.write(0xFF);
00325         t++;
00326     } while (((Workspace[0] & 0x11) != 0x01) && (t < Timeout));
00327         //gather the data block response token
00328     while (!DataLines.write(0xFF));
00329         //get through the busy signal
00330     ChipSelect.write(1);
00331     DataLines.write(0xFF);
00332     if (((Workspace[0] & 0x1F) != 0x05) || (t == Timeout))
00333         //if the data response token indicates error, return write error
00334     { return 0x01; }
00335     else
00336     { return 0x00; }
00337 }
00338 unsigned char SDCard::Write(
00339     unsigned int Address, unsigned char SectorCount, unsigned char* Data)
00340 {
00341     unsigned char Workspace[5];
00342         //work area for card commands and data transactions
00343     static unsigned char CurrentSectorCount = 1;
00344         //store the last write sector count
00345 
00346     if (SectorCount != CurrentSectorCount)
00347         //set the expected number of write blocks if its different from
00348         //previous multiple-block write operations
00349     {
00350         Command(55, 0, Workspace);
00351         Command(23, SectorCount, Workspace);
00352         if (Workspace[0])
00353         { return 0x04; }
00354         CurrentSectorCount = SectorCount;
00355     }
00356     if (Capacity)
00357         //send the multiple-block write command addressed for high-capacity
00358         //cards
00359     {
00360         Command(25, Address, Workspace);
00361     }
00362     else
00363         //send the multiple-block write command addressed for low-capacity
00364         //cards
00365     {
00366         Command(25, Address * 512, Workspace);
00367     }
00368     if (Workspace[0])
00369         //if a command error occurs, return "parameter error"
00370     { return 0x04; }
00371     Workspace[4] = 0x00;
00372         //initialize the error detection variable
00373     for (unsigned char i = 0; i < SectorCount; i++)
00374         //write each data sector
00375     {
00376         DataCRC(512, &Data[i * 512], Workspace);
00377             //calculate the CRC16
00378         ChipSelect.write(0);
00379         DataLines.write(0xFC);
00380             //send multiple write block start token
00381         for (unsigned int j = i * 512; j < (i + 1) * 512; j++)
00382             //write each data block
00383         {
00384             DataLines.write(Data[j]);
00385         }
00386         DataLines.write(Workspace[0]);
00387         DataLines.write(Workspace[1]);
00388             //write the CRC16
00389         t = 0;
00390         do
00391         {
00392             Workspace[0] = DataLines.write(0xFF);
00393             t++;
00394         } while (((Workspace[0] & 0x11) != 0x01) && (t < Timeout));
00395             //gather the data block response token
00396         while (!DataLines.write(0xFF));
00397             //get through the busy signal
00398         ChipSelect.write(1);
00399         Workspace[4] |= Workspace[0];
00400             //record if any write errors that are detected in the data response
00401             //tokens
00402         if (t == Timeout)
00403             //if a block write operation times out, stop operations
00404         { break; }
00405     }
00406     ChipSelect.write(0);
00407     DataLines.write(0xFD);
00408     DataLines.write(0xFF);
00409         //send the stop transmission token
00410     while (!DataLines.write(0xFF));
00411         //get through the busy signal
00412     ChipSelect.write(1);
00413     DataLines.write(0xFF);
00414     if (((Workspace[4] & 0x1F) != 0x05) || (t == Timeout))
00415         //if a data response token indicated an error, return "write error"
00416     { return 0x01; }
00417     else
00418     { return 0x00; }
00419 }
00420 
00421 unsigned char SDCard::Read(unsigned int Address, unsigned char* Data)
00422 {
00423     unsigned char Workspace[4];
00424         //work area for card commands and data transactions
00425     
00426     if (Capacity)
00427         //send the single-block read command addressed for high-capacity cards
00428     {
00429         Command(17, Address, Workspace);
00430     }
00431     else
00432         //send the single-block read command addressed for low-capacity cards
00433     {
00434         Command(17, Address * 512, Workspace);
00435     }
00436     if (Workspace[0])
00437         //if a command error occurs, return "parameter error"
00438     { return 0x04; }
00439     ChipSelect.write(0);
00440     t = 0;
00441     do
00442     {
00443         t++;
00444     } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
00445         //get to the start block token
00446     if (t == Timeout) {
00447         ChipSelect.write(1); DataLines.write(0xFF); return 0x01; }
00448     for (unsigned short i = 0; i < 512; i++)
00449     {
00450         Data[i] = DataLines.write(0xFF);
00451     }
00452         //read the data from the addressed card sector
00453     Workspace[2] = DataLines.write(0xFF);
00454     Workspace[3] = DataLines.write(0xFF);
00455         //read the CRC16
00456     ChipSelect.write(1);
00457     DataLines.write(0xFF);
00458     DataCRC(512, Data, Workspace);
00459         //calculate the CRC16
00460     if (CRCMode && ((Workspace[0] != Workspace[2])
00461         || (Workspace[1] != Workspace[3])))
00462         //if the CRC is invalid, return "read error"
00463     { return 0x01; }
00464     else
00465     { return 0x00; }
00466 }
00467 unsigned char SDCard::Read(
00468     unsigned int Address, unsigned char SectorCount, unsigned char* Data)
00469 {
00470     unsigned char Workspace[5];
00471         //work area for card commands and data transactions
00472     
00473     if (Capacity)
00474         //send the multiple-block read command addressed for high-capacity
00475         //cards
00476     {
00477         Command(18, Address, Workspace);
00478     }
00479     else
00480         //send the multiple-block read command addressed for low-capacity
00481         //cards
00482     {
00483         Command(18, Address * 512, Workspace);
00484     }
00485     if (Workspace[0])
00486         //if a command error occurs, return "parameter error"
00487     { return 0; }
00488     Workspace[4] = 0x00;
00489         //initialize error detection variable
00490     for (unsigned char i = 0; i < SectorCount; i++)
00491         //read each data sector
00492     {
00493         ChipSelect.write(0);
00494         t = 0;
00495         do
00496         {
00497             t++;
00498         } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
00499             //get to the data block start token
00500         if (t == Timeout)
00501         {
00502             break;
00503         }
00504             //if a block read operation times out, stop operations
00505         for (unsigned int j = i * 512; j < (i + 1) * 512; j++)
00506         {
00507             Data[j] = DataLines.write(0xFF);
00508         }
00509             //read the data block
00510         Workspace[2] = DataLines.write(0xFF);
00511         Workspace[3] = DataLines.write(0xFF);
00512             //read the data CRC from the card
00513         ChipSelect.write(1);
00514         DataCRC(512, &Data[i * 512], Workspace);
00515             //calculate the CRC16 for each read data block
00516         Workspace[4] |= (CRCMode && ((Workspace[0] != Workspace[2])
00517             || (Workspace[1] != Workspace[3])));
00518             //record if any invalid CRCs are detected during the
00519             //transaction
00520     }
00521     Command(12, 0, Workspace);
00522         //send the stop transmission command
00523     ChipSelect.write(0);
00524     while (!DataLines.write(0xFF));
00525         //get through the busy signal
00526     ChipSelect.write(1);
00527     DataLines.write(0xFF);
00528     if ((Workspace[4]) || (t == Timeout))
00529         //if an invalid CRC was detected, return "read error"
00530     { return 0x01; }
00531     else
00532     { return 0x00; }
00533 }
00534 
00535 unsigned char SDCard::SelectCRCMode(bool Mode)
00536 {
00537     unsigned char Response;
00538     
00539     if (CRCMode != Mode)
00540         //only send command if CRCMode has been changed
00541     {
00542         t = 0;
00543         do
00544         {
00545             Command(59, Mode, &Response);
00546                 //send the set CRC mode command
00547             t++;
00548         } while (Response && (t < Timeout));
00549         CRCMode = Mode;
00550     }
00551     if (t == Timeout)
00552         //if the command times out, return "error"
00553     { return 0x01; }
00554     else
00555     { return 0x00; }
00556 }
00557 
00558 void SDCard::SetTimeout(unsigned int Retries)
00559 {
00560     Timeout = Retries;
00561         //Set the global number of times for operations to be retried
00562 }
00563 
00564 unsigned char SDCard::Initialize()
00565 {
00566     unsigned char Workspace[5];
00567         //work area for card commands and data transactions
00568     
00569     for (unsigned char i = 0; i < 16; i++)
00570         //clock card at least 74 times to power up
00571     {
00572         DataLines.write(0xFF);
00573     }
00574 
00575     t = 0;
00576     do
00577     {
00578         Command(0, 0, Workspace);
00579             //send the reset command to put the card into SPI mode
00580         t++;
00581     } while ((Workspace[0] != 0x01) && (t < Timeout));
00582         //check for command acceptance
00583     if (t == Timeout) { Status = 0x01; return Status; }
00584 
00585     t = 0;
00586     do
00587     {
00588         Command(59, 1, Workspace);
00589             //turn on CRCs
00590         t++;
00591     } while ((Workspace[0] != 0x01) && (Workspace[0] != 0x05)
00592         && (t < Timeout));
00593         //the set CRC mode command is not valid for all cards in idle state
00594     if (t == Timeout) { Status = 0x01; return Status; }
00595 
00596     t = 0;
00597     do
00598     {
00599         Command(8, 426, Workspace);
00600             //the voltage bits are 0x01 for 2.7V - 3.6V, the check pattern is
00601             //0xAA, 0x000001AA converts to decimal 426
00602         t++;
00603     } while (((Workspace[0] != 0x01) || ((Workspace[3] & 0x0F) != 0x01) ||
00604         (Workspace[4] != 0xAA)) && (Workspace[0] != 0x05) && (t < Timeout));
00605         //check the version, voltage acceptance, and check pattern
00606     if (t == Timeout) { Status = 0x01; return Status; }
00607     Version = Workspace[0] != 0x05;
00608         //store the card version
00609 
00610     if (!Version)
00611     {
00612         t = 0;
00613         do
00614         {
00615             Command(16, 512, Workspace);
00616                 //set the data-block length to 512 bytes
00617             t++;
00618         } while (Workspace[0] && (t < Timeout));
00619         if (t == Timeout) { Status = 0x01; return Status; }
00620     }
00621 
00622     t = 0;
00623     do
00624     {
00625         Command(58, 0, Workspace);
00626             //check the OCR
00627         t++;
00628     } while (((Workspace[0] != 0x01) ||
00629         !((Workspace[2] & 0x20) || (Workspace[2] & 0x10))) && (t < Timeout));
00630         //check for the correct operating voltage, 3.3V
00631     if (t == Timeout) { Status = 0x01; return Status; }
00632 
00633     t = 0;
00634     do
00635     {
00636         Command(55, 0, Workspace);
00637             //initialize card command is application-specific
00638         Command(41, 1073741824, Workspace);
00639             //specify host supports high capacity cards, 0x40000000 converts to
00640             //decimal 1073741824d
00641         t++;
00642     } while (Workspace[0] && (t < Timeout));
00643         //check if the card is ready
00644     if (t == Timeout) { Status = 0x01; return Status; }
00645 
00646     if (SelectCRCMode(1))
00647         //turn on CRCs for all cards
00648     { Status = 0x01; return Status; }
00649 
00650     t = 0;
00651     do
00652     {
00653         Command(58, 0, Workspace);
00654             //check the OCR again
00655         t++;
00656     } while ((Workspace[0] || !(Workspace[1] & 0x80)) && (t < Timeout));
00657         //check the power up status
00658     if (t == Timeout) { Status = 0x01; return Status; }
00659     for (unsigned char i = 0; i < 4; i++)
00660         //record the OCR
00661     {
00662         OCR[i] = Workspace[i + 1];
00663     }
00664     Capacity = (OCR[0] & 0x40) == 0x40;
00665         //record the capacity
00666 
00667     t = 0;
00668     do
00669     {
00670         do
00671         {
00672             Command(9, 0, Workspace);
00673                 //read the CSD
00674             t++;
00675         } while (Workspace[0] && (t < Timeout));
00676         if (t == Timeout) { Status = 0x01; return Status; }
00677         ChipSelect.write(0);
00678         do
00679         {
00680             t++;
00681         } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
00682             //get to the start data block token
00683         if (t == Timeout) { ChipSelect.write(1); DataLines.write(0xFF);
00684             Status = 0x01; return Status; }
00685         for (unsigned char i = 0; i < 16; i++)
00686             //record the CSD
00687         {
00688             CSD[i] = DataLines.write(0xFF);
00689         }
00690         Workspace[2] = DataLines.write(0xFF);
00691         Workspace[3] = DataLines.write(0xFF);
00692             //save the CSD CRC16
00693         ChipSelect.write(1);
00694         DataLines.write(0xFF);
00695         DataCRC(16, CSD, Workspace);
00696             //calculate the CSD CRC16
00697         Workspace[4] = 0;
00698         for (unsigned char i = 0; i < 15; i++)
00699         {
00700             Workspace[4] = CommandCRCTable[Workspace[4]] ^ CSD[i];
00701         }
00702         Workspace[4] = CommandCRCTable[Workspace[4]] | 0x01;
00703             //calculate the CSD CRC7
00704         t++;
00705     } while (((Workspace[0] != Workspace[2]) || (Workspace[1] != Workspace[3])
00706         || (Workspace[4] != CSD[15])) && (t < Timeout));
00707         //perform all CSD CRCs
00708     if (t == Timeout) { Status = 0x01; return Status; }
00709 
00710     if (((CSD[3] & 0x07) > 0x02) ||
00711         (((CSD[3] & 0x78) > 0x30) && ((CSD[3] & 0x07) > 0x01)))
00712         //read the CSD card speed bits and speed up card operations
00713     {
00714         DataLines.frequency(25000000);
00715             //maximum frequency is 25MHz
00716     }
00717     else
00718     {
00719         Workspace[0] = 1;
00720         for (unsigned char i = 0; i < (CSD[3] & 0x07); i++)
00721         {
00722             Workspace[0] *= 10;
00723                 //the first three bits are a power of ten multiplier for speed
00724         }
00725         switch (CSD[3] & 0x78)
00726         {
00727             case 0x08: DataLines.frequency(Workspace[0] * 100000); break;
00728             case 0x10: DataLines.frequency(Workspace[0] * 120000); break;
00729             case 0x18: DataLines.frequency(Workspace[0] * 140000); break;
00730             case 0x20: DataLines.frequency(Workspace[0] * 150000); break;
00731             case 0x28: DataLines.frequency(Workspace[0] * 200000); break;
00732             case 0x30: DataLines.frequency(Workspace[0] * 250000); break;
00733             case 0x38: DataLines.frequency(Workspace[0] * 300000); break;
00734             case 0x40: DataLines.frequency(Workspace[0] * 350000); break;
00735             case 0x48: DataLines.frequency(Workspace[0] * 400000); break;
00736             case 0x50: DataLines.frequency(Workspace[0] * 450000); break;
00737             case 0x58: DataLines.frequency(Workspace[0] * 500000); break;
00738             case 0x60: DataLines.frequency(Workspace[0] * 550000); break;
00739             case 0x68: DataLines.frequency(Workspace[0] * 600000); break;
00740             case 0x70: DataLines.frequency(Workspace[0] * 700000); break;
00741             case 0x78: DataLines.frequency(Workspace[0] * 800000); break;
00742             default: break;
00743         }
00744     }
00745 
00746     if (CSD[4] & 0x40)
00747         //check for switch command class support
00748     {
00749         t = 0;
00750         do
00751         {
00752             Command(6, 2147483649, Workspace);
00753                 //switch to high-speed mode (SDR25, 50MHz)
00754             t++;
00755         } while (Workspace[0] && (Workspace[0] != 0x04) && (t < Timeout));
00756             //some cards that support switch class commands respond with
00757             //"illegal command"
00758         if (t == Timeout) { Status = 0x01; return Status; }
00759         if (!Workspace[0])
00760         {
00761             do
00762             {
00763                 ChipSelect.write(0);
00764                 do
00765                 {
00766                     t++;
00767                 } while ((DataLines.write(0xFF) != 0xFE) && (t < Timeout));
00768                     //get to the start data block token
00769                 if (t == Timeout) { ChipSelect.write(1);
00770                     DataLines.write(0xFF); Status = 0x01; return Status; }
00771                 for (unsigned char i = 0; i < 64; i++)
00772                     //gather the function status register
00773                 {
00774                     FSR[i] = DataLines.write(0xFF);
00775                 }
00776                 Workspace[2] = DataLines.write(0xFF);
00777                 Workspace[3] = DataLines.write(0xFF);
00778                     //record the CRC16
00779                 ChipSelect.write(1);
00780                 DataLines.write(0xFF);
00781                 DataCRC(64, FSR, Workspace);
00782                     //calculate the CRC16
00783                 t++;
00784             } while (((Workspace[0] != Workspace[2])
00785                 || (Workspace[1] != Workspace[3])) && (t < Timeout));
00786                 //perform the CRC
00787             if (t == Timeout) { Status = 0x01; return Status; }
00788             if ((FSR[13] & 0x02) && ((FSR[16] & 0x0F) == 0x01))
00789             {
00790                 DataLines.frequency(50000000);
00791                     //increase the speed if the function switch was successful
00792             }
00793         }
00794     }
00795 
00796     if (SelectCRCMode(0))
00797     { Status = 0x01; return Status; }
00798         //turn off CRCs
00799 
00800     Status = 0x00;
00801     return Status;
00802 }
00803 
00804 void SDCard::Command(
00805     unsigned char Index, unsigned int Argument, unsigned char* Response)
00806 {
00807     CommandCRC(&Index, &Argument, Response);
00808         //calculate the CRC7
00809     ChipSelect.write(0);
00810         //assert chip select low to synchronize the command
00811     DataLines.write(0x40 | Index);
00812         //the index is assumed valid, commands start with bits 01
00813     DataLines.write(((char*)&Argument)[3]);
00814     DataLines.write(((char*)&Argument)[2]);
00815     DataLines.write(((char*)&Argument)[1]);
00816     DataLines.write(((char*)&Argument)[0]);
00817         //send the argument bytes in order from MSB to LSB
00818     DataLines.write(*Response);
00819         //send the CRC7
00820     t = 0;
00821     do
00822     {
00823         Response[0] = DataLines.write(0xFF);
00824             //clock the card high to let it run operations, the first byte
00825             //will be busy (all high), the response will be sent later
00826         t++;
00827     } while ((Response[0] & 0x80) && (t < Timeout));
00828         //check for a response by testing if the first bit is low
00829     if ((Index == 8) || (Index == 13) || (Index == 58))
00830         //if the command returns a larger response, get the rest of it
00831     {
00832         for (unsigned char i = 1; i < 5; i++)
00833         {
00834             Response[i] = DataLines.write(0xFF);
00835         }
00836     }
00837     ChipSelect.write(1);
00838         //assert chip select high to synchronize command
00839     DataLines.write(0xFF);
00840         //clock the deselected card high to complete processing for some cards
00841 }
00842 
00843 void SDCard::CommandCRC(
00844     unsigned char* IndexPtr, unsigned int* ArgumentPtr, unsigned char* Result)
00845 {
00846     if (CRCMode)
00847         //only calculate if data-checks are desired
00848     {
00849         Result[0] =
00850             CommandCRCTable[
00851                 CommandCRCTable[
00852                     CommandCRCTable[
00853                         CommandCRCTable[
00854                             CommandCRCTable[
00855                                 *IndexPtr | 0x40
00856                             ] ^ ((char*)ArgumentPtr)[3]
00857                         ] ^ ((char*)ArgumentPtr)[2]
00858                     ] ^ ((char*)ArgumentPtr)[1]
00859                 ] ^ ((char*)ArgumentPtr)[0]
00860             ] | 0x01;
00861             //calculate the CRC7, SD protocol requires the last bit to be high
00862     }
00863     else
00864         //if no data-checking is desired, the return bits are not used
00865     {
00866         Result[0] = 0xFF;
00867     }
00868 }
00869 
00870 void SDCard::DataCRC(
00871     unsigned short Length, unsigned char* Data, unsigned char* Result)
00872 {
00873     if (CRCMode)
00874         //only calculate if data-checks are desired
00875     {
00876         unsigned char Reference;
00877             //store the current CRC16 lookup value
00878         Result[0] = 0x00;
00879         Result[1] = 0x00;
00880             //initialize the result carrier
00881         for (unsigned short i = 0; i < Length; i++)
00882             //step through each byte of the data to be checked
00883         {
00884             Reference = Result[0];
00885                 //record the current CRC16 lookup for both bytes
00886             Result[0] = DataCRCTable[2 * Reference] ^ Result[1];
00887                 //the first byte result is XORed with the old second byte
00888             Result[1] = DataCRCTable[(2 * Reference) + 1] ^ Data[i];
00889                 //the second byte result is XORed with the new data byte
00890         }
00891         for (unsigned char i = 0; i < 2; i++)
00892             //the final result must be XORed with two 0x00 bytes
00893         {
00894             Reference = Result[0];
00895             Result[0] = DataCRCTable[2 * Reference] ^ Result[1];
00896             Result[1] = DataCRCTable[(2 * Reference) + 1];
00897         }
00898     }
00899     else
00900         //if no data-checking is desired, the return bits are not used
00901     {
00902         Result[0] = 0xFF;
00903         Result[1] = 0xFF;
00904     }
00905 }
00906 
00907 void SDCard::GenerateCRCTable(unsigned char Size,
00908     unsigned long long Generator, unsigned char* Table)
00909 {
00910     unsigned char Index[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
00911         //this will hold information from the generator; the position indicates
00912         //the order of the encountered 1, the value indicates its position in
00913         //the generator, the 9th entry indicates the number of 1's encountered
00914     
00915     for (unsigned char i = 0; i < 64; i++)
00916         //shift generator left until the first bit is high
00917     {
00918         if (((char*)&Generator)[7] & 0x80)
00919         { break; }
00920         Generator = Generator << 1;
00921     }
00922     for (unsigned char i = 0; i < Size; i++)
00923         //initialize table
00924     {
00925         Table[i] = 0x00;
00926     }
00927     for (unsigned char i = 0; i < 8; i++)
00928         //increment through each generator bit
00929     {
00930         if ((0x80 >> i) & ((unsigned char*)&Generator)[7])
00931             //if a 1 is encountered in the generator, record its order and
00932             //location and increment the counter
00933         {
00934             Index[Index[8]] = i;
00935             Index[8]++;
00936         }
00937         for (unsigned char j = 0; j < (0x01 << i); j++)
00938             //each bit doubles the number of XOR operations
00939         {
00940             for (unsigned char k = 0; k < Size; k++)
00941                 //we need to precalculate each byte in the CRC table
00942             {
00943                 Table[(Size * ((0x01 << i) + j)) + k]
00944                     = Table[(Size * j) + k];
00945                     //each power of two is equal to all previous entries with
00946                     //an added XOR with the generator on the leftmost bit and
00947                     //on each succeeding 1 in the generator
00948                 for (unsigned char l = 0; l < Index[8]; l++)
00949                     //increment through the encountered generator 1s
00950                 {
00951                     Table[(Size * ((0x01 << i) + j)) + k] ^=
00952                         (((unsigned char*)&Generator)[7-k]
00953                         << (i + 1 - Index[l]));
00954                     Table[(Size * ((0x01 << i) + j)) + k] ^=
00955                         (((unsigned char*)&Generator)[6-k]
00956                         >> (7 - i + Index[l]));
00957                         //XOR the new bit and the new generator 1s
00958                 }
00959             }
00960         }
00961     }
00962 }