No change from original version.

Dependencies:   FATFileSystem

Dependents:   SDFile_Logger

Fork of SDFileSystem by Neil Thiessen

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SDFileSystem.cpp Source File

SDFileSystem.cpp

00001 /* SD/MMC File System Library
00002  * Copyright (c) 2016 Neil Thiessen
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "SDFileSystem.h"
00018 #include "diskio.h"
00019 #include "pinmap.h"
00020 #include "SDCRC.h"
00021 
00022 SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, PinName cd, SwitchType cdtype, int hz)
00023     : FATFileSystem(name),
00024       m_Spi(mosi, miso, sclk),
00025       m_Cs(cs, 1),
00026       m_Cd(cd),
00027       m_FREQ(hz)
00028 {
00029     //Initialize the member variables
00030     m_CardType = CARD_NONE;
00031     m_Crc = true;
00032     m_LargeFrames = false;
00033     m_WriteValidation = true;
00034     m_Status = STA_NOINIT;
00035 
00036     //Enable the internal pull-up resistor on MISO
00037     pin_mode(miso, PullUp);
00038 
00039     //Configure the SPI bus
00040     m_Spi.format(8, 0);
00041 
00042     //Configure the card detect pin
00043     if (cdtype == SWITCH_POS_NO) {
00044         m_Cd.mode(PullDown);
00045         m_CdAssert = 1;
00046         m_Cd.fall(this, &SDFileSystem::onCardRemoval);
00047     } else if (cdtype == SWITCH_POS_NC) {
00048         m_Cd.mode(PullDown);
00049         m_CdAssert = 0;
00050         m_Cd.rise(this, &SDFileSystem::onCardRemoval);
00051     } else if (cdtype == SWITCH_NEG_NO) {
00052         m_Cd.mode(PullUp);
00053         m_CdAssert = 0;
00054         m_Cd.rise(this, &SDFileSystem::onCardRemoval);
00055     } else if (cdtype == SWITCH_NEG_NC) {
00056         m_Cd.mode(PullUp);
00057         m_CdAssert = 1;
00058         m_Cd.fall(this, &SDFileSystem::onCardRemoval);
00059     } else {
00060         m_CdAssert = -1;
00061     }
00062 }
00063 
00064 bool SDFileSystem::card_present()
00065 {
00066     //Check the card socket
00067     checkSocket();
00068 
00069     //Return whether or not a card is present
00070     return !(m_Status & STA_NODISK);
00071 }
00072 
00073 SDFileSystem::CardType SDFileSystem::card_type()
00074 {
00075     //Check the card socket
00076     checkSocket();
00077 
00078     //Return the card type
00079     return m_CardType;
00080 }
00081 
00082 bool SDFileSystem::crc()
00083 {
00084     //Return whether or not CRC is enabled
00085     return m_Crc;
00086 }
00087 
00088 void SDFileSystem::crc(bool enabled)
00089 {
00090     //Check the card socket
00091     checkSocket();
00092 
00093     //Just update the member variable if the card isn't initialized
00094     if (m_Status & STA_NOINIT) {
00095         m_Crc = enabled;
00096         return;
00097     }
00098 
00099     //Enable or disable CRC
00100     if (enabled && !m_Crc) {
00101         //Send CMD59(0x00000001) to enable CRC
00102         m_Crc = true;
00103         commandTransaction(CMD59, 0x00000001);
00104     } else if (!enabled && m_Crc) {
00105         //Send CMD59(0x00000000) to disable CRC
00106         commandTransaction(CMD59, 0x00000000);
00107         m_Crc = false;
00108     }
00109 }
00110 
00111 bool SDFileSystem::large_frames()
00112 {
00113     //Return whether or not 16-bit frames are enabled
00114     return m_LargeFrames;
00115 }
00116 
00117 void SDFileSystem::large_frames(bool enabled)
00118 {
00119     //Set whether or not 16-bit frames are enabled
00120     m_LargeFrames = enabled;
00121 }
00122 
00123 bool SDFileSystem::write_validation()
00124 {
00125     //Return whether or not write validation is enabled
00126     return m_WriteValidation;
00127 }
00128 
00129 void SDFileSystem::write_validation(bool enabled)
00130 {
00131     //Set whether or not write validation is enabled
00132     m_WriteValidation = enabled;
00133 }
00134 
00135 int SDFileSystem::unmount()
00136 {
00137     //Unmount the filesystem
00138     FATFileSystem::unmount();
00139 
00140     //Change the status to not initialized, and the card type to unknown
00141     m_Status |= STA_NOINIT;
00142     m_CardType = CARD_UNKNOWN;
00143 
00144     //Always succeeds
00145     return 0;
00146 }
00147 
00148 int SDFileSystem::disk_initialize()
00149 {
00150     char token;
00151     unsigned int resp;
00152     Timer timer;
00153 
00154     //Make sure there's a card in the socket before proceeding
00155     checkSocket();
00156     if (m_Status & STA_NODISK)
00157         return m_Status;
00158 
00159     //Make sure we're not already initialized before proceeding
00160     if (!(m_Status & STA_NOINIT))
00161         return m_Status;
00162 
00163     //Set the SPI frequency to 400kHz for initialization
00164     m_Spi.frequency(400000);
00165 
00166     //Try to reset the card up to 3 times
00167     for (int f = 0; f < 3; f++) {
00168         //Send 80 dummy clocks with /CS deasserted and DI held high
00169         m_Cs = 1;
00170         for (int i = 0; i < 10; i++) {
00171             m_Spi.write(0xFF);
00172         }
00173 
00174         //Send CMD0(0x00000000) to reset the card
00175         token = commandTransaction(CMD0, 0x00000000);
00176         if (token == 0x01) {
00177             break;
00178         }
00179     }
00180 
00181     //Check if the card reset
00182     if (token != 0x01) {
00183         //Initialization failed
00184         m_CardType = CARD_UNKNOWN;
00185         return m_Status;
00186     }
00187 
00188     //Send CMD59(0x00000001) to enable CRC if necessary
00189     if (m_Crc) {
00190         if (commandTransaction(CMD59, 0x00000001) != 0x01) {
00191             //Initialization failed
00192             m_CardType = CARD_UNKNOWN;
00193             return m_Status;
00194         }
00195     }
00196 
00197     //Send CMD8(0x000001AA) to see if this is an SDCv2 card
00198     if (commandTransaction(CMD8, 0x000001AA, &resp) == 0x01) {
00199         //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern
00200         if ((resp & 0xFFF) != 0x1AA) {
00201             //Initialization failed
00202             m_CardType = CARD_UNKNOWN;
00203             return m_Status;
00204         }
00205 
00206         //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
00207         if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
00208             //Initialization failed
00209             m_CardType = CARD_UNKNOWN;
00210             return m_Status;
00211         }
00212 
00213         //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
00214         timer.start();
00215         do {
00216             token = commandTransaction(ACMD41, 0x40100000);
00217         } while (token == 0x01 && timer.read_ms() < 2000);
00218         timer.stop();
00219         timer.reset();
00220 
00221         //Check if the card initialized
00222         if (token != 0x00) {
00223             //Initialization failed
00224             m_CardType = CARD_UNKNOWN;
00225             return m_Status;
00226         }
00227 
00228         //Send CMD58(0x00000000) to read the OCR
00229         if (commandTransaction(CMD58, 0x00000000, &resp) == 0x00) {
00230             //Check the CCS bit to determine if this is a high capacity card
00231             if (resp & (1 << 30))
00232                 m_CardType = CARD_SDHC;
00233             else
00234                 m_CardType = CARD_SD;
00235 
00236             //Increase the SPI frequency to full speed (up to 50MHz for SDCv2)
00237             if (m_FREQ > 25000000) {
00238                 if (enableHighSpeedMode()) {
00239                     if (m_FREQ > 50000000) {
00240                         m_Spi.frequency(50000000);
00241                     } else {
00242                         m_Spi.frequency(m_FREQ);
00243                     }
00244                 } else {
00245                     m_Spi.frequency(25000000);
00246                 }
00247             } else {
00248                 m_Spi.frequency(m_FREQ);
00249             }
00250         } else {
00251             //Initialization failed
00252             m_CardType = CARD_UNKNOWN;
00253             return m_Status;
00254         }
00255     } else {
00256         //Didn't respond or illegal command, this is either an SDCv1 or MMC card
00257         //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
00258         if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
00259             //Initialization failed
00260             m_CardType = CARD_UNKNOWN;
00261             return m_Status;
00262         }
00263 
00264         //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
00265         timer.start();
00266         do {
00267             token = commandTransaction(ACMD41, 0x40100000);
00268         } while (token == 0x01 && timer.read_ms() < 2000);
00269         timer.stop();
00270         timer.reset();
00271 
00272         //Check if the card initialized
00273         if (token == 0x00) {
00274             //This is an SDCv1 standard capacity card
00275             m_CardType = CARD_SD;
00276 
00277             //Increase the SPI frequency to full speed (up to 25MHz for SDCv1)
00278             if (m_FREQ > 25000000)
00279                 m_Spi.frequency(25000000);
00280             else
00281                 m_Spi.frequency(m_FREQ);
00282         } else {
00283             //Try to initialize the card using CMD1(0x00100000) for up to 2 seconds
00284             timer.start();
00285             do {
00286                 token = commandTransaction(CMD1, 0x00100000);
00287             } while (token == 0x01 && timer.read_ms() < 2000);
00288             timer.stop();
00289             timer.reset();
00290 
00291             //Check if the card initialized
00292             if (token == 0x00) {
00293                 //This is an MMCv3 card
00294                 m_CardType = CARD_MMC;
00295 
00296                 //Increase the SPI frequency to full speed (up to 20MHz for MMCv3)
00297                 if (m_FREQ > 20000000)
00298                     m_Spi.frequency(20000000);
00299                 else
00300                     m_Spi.frequency(m_FREQ);
00301             } else {
00302                 //Initialization failed
00303                 m_CardType = CARD_UNKNOWN;
00304                 return m_Status;
00305             }
00306         }
00307     }
00308 
00309     //Send ACMD42(0x00000000) to disconnect the internal pull-up resistor on pin 1 if necessary
00310     if (m_CardType != CARD_MMC) {
00311         if (commandTransaction(ACMD42, 0x00000000) != 0x00) {
00312             //Initialization failed
00313             m_CardType = CARD_UNKNOWN;
00314             return m_Status;
00315         }
00316     }
00317 
00318     //Send CMD16(0x00000200) to force the block size to 512B if necessary
00319     if (m_CardType != CARD_SDHC) {
00320         if (commandTransaction(CMD16, 0x00000200) != 0x00) {
00321             //Initialization failed
00322             m_CardType = CARD_UNKNOWN;
00323             return m_Status;
00324         }
00325     }
00326 
00327     //The card is now initialized
00328     m_Status &= ~STA_NOINIT;
00329 
00330     //Return the disk status
00331     return m_Status;
00332 }
00333 
00334 int SDFileSystem::disk_status()
00335 {
00336     //Check the card socket
00337     checkSocket();
00338 
00339     //Return the disk status
00340     return m_Status;
00341 }
00342 
00343 int SDFileSystem::disk_read(uint8_t* buffer, uint32_t sector, uint32_t count)
00344 {
00345     //Make sure the card is initialized before proceeding
00346     if (m_Status & STA_NOINIT)
00347         return RES_NOTRDY;
00348 
00349     //Read a single block, or multiple blocks
00350     if (count > 1) {
00351         return readBlocks((char*)buffer, sector, count) ? RES_OK : RES_ERROR;
00352     } else {
00353         return readBlock((char*)buffer, sector) ? RES_OK : RES_ERROR;
00354     }
00355 }
00356 
00357 int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t sector, uint32_t count)
00358 {
00359     //Make sure the card is initialized before proceeding
00360     if (m_Status & STA_NOINIT)
00361         return RES_NOTRDY;
00362 
00363     //Make sure the card isn't write protected before proceeding
00364     if (m_Status & STA_PROTECT)
00365         return RES_WRPRT;
00366 
00367     //Write a single block, or multiple blocks
00368     if (count > 1) {
00369         return writeBlocks((const char*)buffer, sector, count) ? RES_OK : RES_ERROR;
00370     } else {
00371         return writeBlock((const char*)buffer, sector) ? RES_OK : RES_ERROR;
00372     }
00373 }
00374 
00375 int SDFileSystem::disk_sync()
00376 {
00377     //Select the card so we're forced to wait for the end of any internal write processes
00378     if (select()) {
00379         deselect();
00380         return RES_OK;
00381     } else {
00382         return RES_ERROR;
00383     }
00384 }
00385 
00386 uint32_t SDFileSystem::disk_sectors()
00387 {
00388     //Make sure the card is initialized before proceeding
00389     if (m_Status & STA_NOINIT)
00390         return 0;
00391 
00392     //Try to read the CSD register up to 3 times
00393     for (int f = 0; f < 3; f++) {
00394         //Select the card, and wait for ready
00395         if(!select())
00396             break;
00397 
00398         //Send CMD9(0x00000000) to read the CSD register
00399         if (writeCommand(CMD9, 0x00000000) == 0x00) {
00400             //Read the 16B CSD data block
00401             char csd[16];
00402             bool success = readData(csd, 16);
00403             deselect();
00404             if (success) {
00405                 //Calculate the sector count based on the card type
00406                 if ((csd[0] >> 6) == 0x01) {
00407                     //Calculate the sector count for a high capacity card
00408                     unsigned int size = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1;
00409                     return size << 10;
00410                 } else {
00411                     //Calculate the sector count for a standard capacity card
00412                     unsigned int size = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1;
00413                     size <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2);
00414                     size <<= (csd[5] & 0x0F);
00415                     return size >> 9;
00416                 }
00417             }
00418         } else {
00419             //The command failed, get out
00420             break;
00421         }
00422     }
00423 
00424     //The read operation failed 3 times
00425     deselect();
00426     return 0;
00427 }
00428 
00429 void SDFileSystem::onCardRemoval()
00430 {
00431     //Check the card socket
00432     checkSocket();
00433 }
00434 
00435 inline void SDFileSystem::checkSocket()
00436 {
00437     //Use the card detect switch (if available) to determine if the socket is occupied
00438     if (m_CdAssert != -1) {
00439         if (m_Status & STA_NODISK) {
00440             if (m_Cd == m_CdAssert) {
00441                 //The socket is now occupied
00442                 m_Status &= ~STA_NODISK;
00443                 m_CardType = CARD_UNKNOWN;
00444             }
00445         } else {
00446             if (m_Cd != m_CdAssert) {
00447                 //The socket is now empty
00448                 m_Status |= (STA_NODISK | STA_NOINIT);
00449                 m_CardType = CARD_NONE;
00450             }
00451         }
00452     }
00453 }
00454 
00455 inline bool SDFileSystem::waitReady(int timeout)
00456 {
00457     char resp;
00458 
00459     //Keep sending dummy clocks with DI held high until the card releases the DO line
00460     m_Timer.start();
00461     do {
00462         resp = m_Spi.write(0xFF);
00463     } while (resp == 0x00 && m_Timer.read_ms() < timeout);
00464     m_Timer.stop();
00465     m_Timer.reset();
00466 
00467     //Return success/failure
00468     return (resp > 0x00);
00469 }
00470 
00471 inline bool SDFileSystem::select()
00472 {
00473     //Assert /CS
00474     m_Cs = 0;
00475 
00476     //Send 8 dummy clocks with DI held high to enable DO
00477     m_Spi.write(0xFF);
00478 
00479     //Wait for up to 500ms for the card to become ready
00480     if (waitReady(500)) {
00481         return true;
00482     } else {
00483         //We timed out, deselect and return false
00484         deselect();
00485         return false;
00486     }
00487 }
00488 
00489 inline void SDFileSystem::deselect()
00490 {
00491     //Deassert /CS
00492     m_Cs = 1;
00493 
00494     //Send 8 dummy clocks with DI held high to disable DO
00495     m_Spi.write(0xFF);
00496 }
00497 
00498 inline char SDFileSystem::commandTransaction(char cmd, unsigned int arg, unsigned int* resp)
00499 {
00500     //Select the card, and wait for ready
00501     if(!select())
00502         return 0xFF;
00503 
00504     //Perform the command transaction
00505     char token = writeCommand(cmd, arg, resp);
00506 
00507     //Deselect the card, and return the R1 response token
00508     deselect();
00509     return token;
00510 }
00511 
00512 char SDFileSystem::writeCommand(char cmd, unsigned int arg, unsigned int* resp)
00513 {
00514     char token;
00515 
00516     //Try to send the command up to 3 times
00517     for (int f = 0; f < 3; f++) {
00518         //Send CMD55(0x00000000) prior to an application specific command
00519         if (cmd == ACMD22 || cmd == ACMD23 || cmd == ACMD41 || cmd == ACMD42) {
00520             token = writeCommand(CMD55, 0x00000000);
00521             if (token > 0x01)
00522                 return token;
00523 
00524             //Deselect and reselect the card between CMD55 and an ACMD
00525             deselect();
00526             if(!select())
00527                 return 0xFF;
00528         }
00529 
00530         //Prepare the command packet
00531         char cmdPacket[6];
00532         cmdPacket[0] = cmd;
00533         cmdPacket[1] = arg >> 24;
00534         cmdPacket[2] = arg >> 16;
00535         cmdPacket[3] = arg >> 8;
00536         cmdPacket[4] = arg;
00537         if (m_Crc || cmd == CMD0 || cmd == CMD8)
00538             cmdPacket[5] = (SDCRC::crc7(cmdPacket, 5) << 1) | 0x01;
00539         else
00540             cmdPacket[5] = 0x01;
00541 
00542         //Send the command packet
00543         for (int i = 0; i < 6; i++)
00544             m_Spi.write(cmdPacket[i]);
00545 
00546         //Discard the stuff byte immediately following CMD12
00547         if (cmd == CMD12)
00548             m_Spi.write(0xFF);
00549 
00550         //Allow up to 8 bytes of delay for the R1 response token
00551         for (int i = 0; i < 9; i++) {
00552             token = m_Spi.write(0xFF);
00553             if (!(token & 0x80))
00554                 break;
00555         }
00556 
00557         //Verify the R1 response token
00558         if (token == 0xFF) {
00559             //No data was received, get out early
00560             break;
00561         } else if (token & (1 << 3)) {
00562             //There was a CRC error, try again
00563             continue;
00564         } else if (token > 0x01) {
00565             //An error occured, get out early
00566             break;
00567         }
00568 
00569         //Handle R2 and R3/R7 response tokens
00570         if (cmd == CMD13 && resp != NULL) {
00571             //Read the R2 response value
00572             *resp = m_Spi.write(0xFF);
00573         } else if ((cmd == CMD8 || cmd == CMD58) && resp != NULL) {
00574             //Read the R3/R7 response value
00575             *resp = (m_Spi.write(0xFF) << 24);
00576             *resp |= (m_Spi.write(0xFF) << 16);
00577             *resp |= (m_Spi.write(0xFF) << 8);
00578             *resp |= m_Spi.write(0xFF);
00579         }
00580 
00581         //The command was successful
00582         break;
00583     }
00584 
00585     //Return the R1 response token
00586     return token;
00587 }
00588 
00589 bool SDFileSystem::readData(char* buffer, int length)
00590 {
00591     char token;
00592     unsigned short crc;
00593 
00594     //Wait for up to 500ms for a token to arrive
00595     m_Timer.start();
00596     do {
00597         token = m_Spi.write(0xFF);
00598     } while (token == 0xFF && m_Timer.read_ms() < 500);
00599     m_Timer.stop();
00600     m_Timer.reset();
00601 
00602     //Check if a valid start block token was received
00603     if (token != 0xFE)
00604         return false;
00605 
00606     //Check if large frames are enabled or not
00607     if (m_LargeFrames) {
00608         //Switch to 16-bit frames for better performance
00609         m_Spi.format(16, 0);
00610 
00611         //Read the data block into the buffer
00612         unsigned short dataWord;
00613         for (int i = 0; i < length; i += 2) {
00614             dataWord = m_Spi.write(0xFFFF);
00615             buffer[i] = dataWord >> 8;
00616             buffer[i + 1] = dataWord;
00617         }
00618 
00619         //Read the CRC16 checksum for the data block
00620         crc = m_Spi.write(0xFFFF);
00621 
00622         //Switch back to 8-bit frames
00623         m_Spi.format(8, 0);
00624     } else {
00625         //Read the data into the buffer
00626         for (int i = 0; i < length; i++)
00627             buffer[i] = m_Spi.write(0xFF);
00628 
00629         //Read the CRC16 checksum for the data block
00630         crc = (m_Spi.write(0xFF) << 8);
00631         crc |= m_Spi.write(0xFF);
00632     }
00633 
00634     //Return the validity of the CRC16 checksum (if enabled)
00635     return (!m_Crc || crc == SDCRC::crc16(buffer, length));
00636 }
00637 
00638 char SDFileSystem::writeData(const char* buffer, char token)
00639 {
00640     //Calculate the CRC16 checksum for the data block (if enabled)
00641     unsigned short crc = (m_Crc) ? SDCRC::crc16(buffer, 512) : 0xFFFF;
00642 
00643     //Wait for up to 500ms for the card to become ready
00644     if (!waitReady(500))
00645         return false;
00646 
00647     //Send the start block token
00648     m_Spi.write(token);
00649 
00650     //Check if large frames are enabled or not
00651     if (m_LargeFrames) {
00652         //Switch to 16-bit frames for better performance
00653         m_Spi.format(16, 0);
00654 
00655         //Write the data block from the buffer
00656         for (int i = 0; i < 512; i += 2)
00657             m_Spi.write((buffer[i] << 8) | buffer[i + 1]);
00658 
00659         //Send the CRC16 checksum for the data block
00660         m_Spi.write(crc);
00661 
00662         //Switch back to 8-bit frames
00663         m_Spi.format(8, 0);
00664     } else {
00665         //Write the data block from the buffer
00666         for (int i = 0; i < 512; i++)
00667             m_Spi.write(buffer[i]);
00668 
00669         //Send the CRC16 checksum for the data block
00670         m_Spi.write(crc >> 8);
00671         m_Spi.write(crc);
00672     }
00673 
00674     //Return the data response token
00675     return (m_Spi.write(0xFF) & 0x1F);
00676 }
00677 
00678 inline bool SDFileSystem::readBlock(char* buffer, unsigned int lba)
00679 {
00680     //Try to read the block up to 3 times
00681     for (int f = 0; f < 3; f++) {
00682         //Select the card, and wait for ready
00683         if(!select())
00684             break;
00685 
00686         //Send CMD17(block) to read a single block
00687         if (writeCommand(CMD17, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
00688             //Try to read the block, and deselect the card
00689             bool success = readData(buffer, 512);
00690             deselect();
00691 
00692             //Return if successful
00693             if (success)
00694                 return true;
00695         } else {
00696             //The command failed, get out
00697             break;
00698         }
00699     }
00700 
00701     //The single block read failed
00702     deselect();
00703     return false;
00704 }
00705 
00706 inline bool SDFileSystem::readBlocks(char* buffer, unsigned int lba, unsigned int count)
00707 {
00708     //Try to read each block up to 3 times
00709     for (int f = 0; f < 3;) {
00710         //Select the card, and wait for ready
00711         if(!select())
00712             break;
00713 
00714         //Send CMD18(block) to read multiple blocks
00715         if (writeCommand(CMD18, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
00716             //Try to read all of the data blocks
00717             do {
00718                 //Read the next block, and break on errors
00719                 if (!readData(buffer, 512)) {
00720                     f++;
00721                     break;
00722                 }
00723 
00724                 //Update the variables
00725                 lba++;
00726                 buffer += 512;
00727                 f = 0;
00728             } while (--count);
00729 
00730             //Send CMD12(0x00000000) to stop the transmission
00731             if (writeCommand(CMD12, 0x00000000) != 0x00) {
00732                 //The command failed, get out
00733                 break;
00734             }
00735 
00736             //Deselect the card, and return if successful
00737             deselect();
00738             if (count == 0)
00739                 return true;
00740         } else {
00741             //The command failed, get out
00742             break;
00743         }
00744     }
00745 
00746     //The multiple block read failed
00747     deselect();
00748     return false;
00749 }
00750 
00751 inline bool SDFileSystem::writeBlock(const char* buffer, unsigned int lba)
00752 {
00753     //Try to write the block up to 3 times
00754     for (int f = 0; f < 3; f++) {
00755         //Select the card, and wait for ready
00756         if(!select())
00757             break;
00758 
00759         //Send CMD24(block) to write a single block
00760         if (writeCommand(CMD24, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
00761             //Try to write the block, and deselect the card
00762             char token = writeData(buffer, 0xFE);
00763             deselect();
00764 
00765             //Check the data response token
00766             if (token == 0x0A) {
00767                 //A CRC error occured, try again
00768                 continue;
00769             } else if (token == 0x0C) {
00770                 //A write error occured, get out
00771                 break;
00772             }
00773 
00774             //Send CMD13(0x00000000) to verify that the programming was successful if enabled
00775             if (m_WriteValidation) {
00776                 unsigned int resp;
00777                 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
00778                     //Some manner of unrecoverable write error occured during programming, get out
00779                     break;
00780                 }
00781             }
00782 
00783             //The data was written successfully
00784             return true;
00785         } else {
00786             //The command failed, get out
00787             break;
00788         }
00789     }
00790 
00791     //The single block write failed
00792     deselect();
00793     return false;
00794 }
00795 
00796 inline bool SDFileSystem::writeBlocks(const char* buffer, unsigned int lba, unsigned int count)
00797 {
00798     char token;
00799     const char* currentBuffer = buffer;
00800     unsigned int currentLba = lba;
00801     int currentCount = count;
00802 
00803     //Try to write each block up to 3 times
00804     for (int f = 0; f < 3;) {
00805         //If this is an SD card, send ACMD23(count) to set the number of blocks to pre-erase
00806         if (m_CardType != CARD_MMC) {
00807             if (commandTransaction(ACMD23, currentCount) != 0x00) {
00808                 //The command failed, get out
00809                 break;
00810             }
00811         }
00812 
00813         //Select the card, and wait for ready
00814         if(!select())
00815             break;
00816 
00817         //Send CMD25(block) to write multiple blocks
00818         if (writeCommand(CMD25, (m_CardType == CARD_SDHC) ? currentLba : currentLba << 9) == 0x00) {
00819             //Try to write all of the data blocks
00820             do {
00821                 //Write the next block and break on errors
00822                 token = writeData(currentBuffer, 0xFC);
00823                 if (token != 0x05) {
00824                     f++;
00825                     break;
00826                 }
00827 
00828                 //Update the variables
00829                 currentBuffer += 512;
00830                 f = 0;
00831             } while (--currentCount);
00832 
00833             //Wait for up to 500ms for the card to finish processing the last block
00834             if (!waitReady(500))
00835                 break;
00836 
00837             //Finalize the transmission
00838             if (currentCount == 0) {
00839                 //Send the stop tran token, and deselect the card
00840                 m_Spi.write(0xFD);
00841                 deselect();
00842 
00843                 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
00844                 if (m_WriteValidation) {
00845                     unsigned int resp;
00846                     if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
00847                         //Some manner of unrecoverable write error occured during programming, get out
00848                         break;
00849                     }
00850                 }
00851 
00852                 //The data was written successfully
00853                 return true;
00854             } else {
00855                 //Send CMD12(0x00000000) to abort the transmission
00856                 if (writeCommand(CMD12, 0x00000000) != 0x00) {
00857                     //The command failed, get out
00858                     break;
00859                 }
00860 
00861                 //Deselect the card
00862                 deselect();
00863 
00864                 //Check the error token
00865                 if (token == 0x0A) {
00866                     //Determine the number of well written blocks if possible
00867                     unsigned int writtenBlocks = 0;
00868                     if (m_CardType != CARD_MMC && select()) {
00869                         //Send ACMD22(0x00000000) to get the number of well written blocks
00870                         if (writeCommand(ACMD22, 0x00000000) == 0x00) {
00871                             //Read the data
00872                             char acmdData[4];
00873                             if (readData(acmdData, 4)) {
00874                                 //Extract the number of well written blocks
00875                                 writtenBlocks = acmdData[0] << 24;
00876                                 writtenBlocks |= acmdData[1] << 16;
00877                                 writtenBlocks |= acmdData[2] << 8;
00878                                 writtenBlocks |= acmdData[3];
00879                             }
00880                         }
00881                         deselect();
00882                     }
00883 
00884                     //Roll back the variables based on the number of well written blocks
00885                     currentBuffer = buffer + (writtenBlocks << 9);
00886                     currentLba = lba + writtenBlocks;
00887                     currentCount = count - writtenBlocks;
00888 
00889                     //Try again
00890                     continue;
00891                 } else {
00892                     //A write error occured, get out
00893                     break;
00894                 }
00895             }
00896         } else {
00897             //The command failed, get out
00898             break;
00899         }
00900     }
00901 
00902     //The multiple block write failed
00903     deselect();
00904     return false;
00905 }
00906 
00907 bool SDFileSystem::enableHighSpeedMode()
00908 {
00909     //Try to issue CMD6 up to 3 times
00910     for (int f = 0; f < 3; f++) {
00911         //Select the card, and wait for ready
00912         if(!select())
00913             break;
00914 
00915         //Send CMD6(0x80FFFFF1) to change the access mode to high speed
00916         if (writeCommand(CMD6, 0x80FFFFF1) == 0x00) {
00917             //Read the 64B status data block
00918             char status[64];
00919             bool success = readData(status, 64);
00920             deselect();
00921             if (success) {
00922                 //Return whether or not the operation was successful
00923                 return ((status[16] & 0x0F) == 0x1);
00924             }
00925         } else {
00926             //The command failed, get out
00927             break;
00928         }
00929     }
00930 
00931     //The operation failed 3 times
00932     deselect();
00933     return false;
00934 }