SDFileSystem

Dependencies:   FATFileSystem

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(50000000)
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     //Send 80 dummy clocks with /CS deasserted and DI held high
00167     m_Cs = 1;
00168     for (int i = 0; i < 10; i++)
00169         m_Spi.write(0xFF);
00170 
00171     //Send CMD0(0x00000000) to reset the card
00172     if (commandTransaction(CMD0, 0x00000000) != 0x01) {
00173         //Initialization failed
00174         m_CardType = CARD_UNKNOWN;
00175         return m_Status;
00176     }
00177 
00178     //Send CMD59(0x00000001) to enable CRC if necessary
00179     if (m_Crc) {
00180         if (commandTransaction(CMD59, 0x00000001) != 0x01) {
00181             //Initialization failed
00182             m_CardType = CARD_UNKNOWN;
00183             return m_Status;
00184         }
00185     }
00186 
00187     //Send CMD8(0x000001AA) to see if this is an SDCv2 card
00188     if (commandTransaction(CMD8, 0x000001AA, &resp) == 0x01) {
00189         //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern
00190         if ((resp & 0xFFF) != 0x1AA) {
00191             //Initialization failed
00192             m_CardType = CARD_UNKNOWN;
00193             return m_Status;
00194         }
00195 
00196         //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
00197         if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
00198             //Initialization failed
00199             m_CardType = CARD_UNKNOWN;
00200             return m_Status;
00201         }
00202 
00203         //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
00204         timer.start();
00205         do {
00206             token = commandTransaction(ACMD41, 0x40100000);
00207         } while (token == 0x01 && timer.read_ms() < 2000);
00208         timer.stop();
00209         timer.reset();
00210 
00211         //Check if the card initialized
00212         if (token != 0x00) {
00213             //Initialization failed
00214             m_CardType = CARD_UNKNOWN;
00215             return m_Status;
00216         }
00217 
00218         //Send CMD58(0x00000000) to read the OCR
00219         if (commandTransaction(CMD58, 0x00000000, &resp) == 0x00) {
00220             //Check the CCS bit to determine if this is a high capacity card
00221             if (resp & (1 << 30))
00222                 m_CardType = CARD_SDHC;
00223             else
00224                 m_CardType = CARD_SD;
00225 
00226             //Increase the SPI frequency to full speed (up to 50MHz for SDCv2)
00227             if (m_FREQ > 25000000) {
00228                 if (enableHighSpeedMode()) {
00229                     if (m_FREQ > 50000000) {
00230                         m_Spi.frequency(50000000);
00231                     } else {
00232                         m_Spi.frequency(m_FREQ);
00233                     }
00234                 } else {
00235                     m_Spi.frequency(25000000);
00236                 }
00237             } else {
00238                 m_Spi.frequency(m_FREQ);
00239             }
00240         } else {
00241             //Initialization failed
00242             m_CardType = CARD_UNKNOWN;
00243             return m_Status;
00244         }
00245     } else {
00246         //Didn't respond or illegal command, this is either an SDCv1 or MMC card
00247         //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
00248         if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
00249             //Initialization failed
00250             m_CardType = CARD_UNKNOWN;
00251             return m_Status;
00252         }
00253 
00254         //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
00255         timer.start();
00256         do {
00257             token = commandTransaction(ACMD41, 0x40100000);
00258         } while (token == 0x01 && timer.read_ms() < 2000);
00259         timer.stop();
00260         timer.reset();
00261 
00262         //Check if the card initialized
00263         if (token == 0x00) {
00264             //This is an SDCv1 standard capacity card
00265             m_CardType = CARD_SD;
00266 
00267             //Increase the SPI frequency to full speed (up to 25MHz for SDCv1)
00268             if (m_FREQ > 25000000)
00269                 m_Spi.frequency(25000000);
00270             else
00271                 m_Spi.frequency(m_FREQ);
00272         } else {
00273             //Try to initialize the card using CMD1(0x00100000) for up to 2 seconds
00274             timer.start();
00275             do {
00276                 token = commandTransaction(CMD1, 0x00100000);
00277             } while (token == 0x01 && timer.read_ms() < 2000);
00278             timer.stop();
00279             timer.reset();
00280 
00281             //Check if the card initialized
00282             if (token == 0x00) {
00283                 //This is an MMCv3 card
00284                 m_CardType = CARD_MMC;
00285 
00286                 //Increase the SPI frequency to full speed (up to 20MHz for MMCv3)
00287                 if (m_FREQ > 20000000)
00288                     m_Spi.frequency(20000000);
00289                 else
00290                     m_Spi.frequency(m_FREQ);
00291             } else {
00292                 //Initialization failed
00293                 m_CardType = CARD_UNKNOWN;
00294                 return m_Status;
00295             }
00296         }
00297     }
00298 
00299     //Send ACMD42(0x00000000) to disconnect the internal pull-up resistor on pin 1 if necessary
00300     if (m_CardType != CARD_MMC) {
00301         if (commandTransaction(ACMD42, 0x00000000) != 0x00) {
00302             //Initialization failed
00303             m_CardType = CARD_UNKNOWN;
00304             return m_Status;
00305         }
00306     }
00307 
00308     //Send CMD16(0x00000200) to force the block size to 512B if necessary
00309     if (m_CardType != CARD_SDHC) {
00310         if (commandTransaction(CMD16, 0x00000200) != 0x00) {
00311             //Initialization failed
00312             m_CardType = CARD_UNKNOWN;
00313             return m_Status;
00314         }
00315     }
00316 
00317     //The card is now initialized
00318     m_Status &= ~STA_NOINIT;
00319 
00320     //Return the disk status
00321     return m_Status;
00322 }
00323 
00324 int SDFileSystem::disk_status()
00325 {
00326     //Check the card socket
00327     checkSocket();
00328 
00329     //Return the disk status
00330     return m_Status;
00331 }
00332 
00333 int SDFileSystem::disk_read(uint8_t* buffer, uint32_t sector, uint32_t count)
00334 {
00335     //Make sure the card is initialized before proceeding
00336     if (m_Status & STA_NOINIT)
00337         return RES_NOTRDY;
00338 
00339     //Read a single block, or multiple blocks
00340     if (count > 1) {
00341         return readBlocks((char*)buffer, sector, count) ? RES_OK : RES_ERROR;
00342     } else {
00343         return readBlock((char*)buffer, sector) ? RES_OK : RES_ERROR;
00344     }
00345 }
00346 
00347 int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t sector, uint32_t count)
00348 {
00349     //Make sure the card is initialized before proceeding
00350     if (m_Status & STA_NOINIT)
00351         return RES_NOTRDY;
00352 
00353     //Make sure the card isn't write protected before proceeding
00354     if (m_Status & STA_PROTECT)
00355         return RES_WRPRT;
00356 
00357     //Write a single block, or multiple blocks
00358     if (count > 1) {
00359         return writeBlocks((const char*)buffer, sector, count) ? RES_OK : RES_ERROR;
00360     } else {
00361         return writeBlock((const char*)buffer, sector) ? RES_OK : RES_ERROR;
00362     }
00363 }
00364 
00365 int SDFileSystem::disk_sync()
00366 {
00367     //Select the card so we're forced to wait for the end of any internal write processes
00368     if (select()) {
00369         deselect();
00370         return RES_OK;
00371     } else {
00372         return RES_ERROR;
00373     }
00374 }
00375 
00376 uint32_t SDFileSystem::disk_sectors()
00377 {
00378     //Make sure the card is initialized before proceeding
00379     if (m_Status & STA_NOINIT)
00380         return 0;
00381 
00382     //Try to read the CSD register up to 3 times
00383     for (int f = 0; f < 3; f++) {
00384         //Select the card, and wait for ready
00385         if(!select())
00386             break;
00387 
00388         //Send CMD9(0x00000000) to read the CSD register
00389         if (writeCommand(CMD9, 0x00000000) == 0x00) {
00390             //Read the 16B CSD data block
00391             char csd[16];
00392             bool success = readData(csd, 16);
00393             deselect();
00394             if (success) {
00395                 //Calculate the sector count based on the card type
00396                 if ((csd[0] >> 6) == 0x01) {
00397                     //Calculate the sector count for a high capacity card
00398                     unsigned int size = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1;
00399                     return size << 10;
00400                 } else {
00401                     //Calculate the sector count for a standard capacity card
00402                     unsigned int size = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1;
00403                     size <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2);
00404                     size <<= (csd[5] & 0x0F);
00405                     return size >> 9;
00406                 }
00407             }
00408         } else {
00409             //The command failed, get out
00410             break;
00411         }
00412     }
00413 
00414     //The read operation failed 3 times
00415     deselect();
00416     return 0;
00417 }
00418 
00419 void SDFileSystem::onCardRemoval()
00420 {
00421     //Check the card socket
00422     checkSocket();
00423 }
00424 
00425 inline void SDFileSystem::checkSocket()
00426 {
00427     //Use the card detect switch (if available) to determine if the socket is occupied
00428     if (m_CdAssert != -1) {
00429         if (m_Status & STA_NODISK) {
00430             if (m_Cd == m_CdAssert) {
00431                 //The socket is now occupied
00432                 m_Status &= ~STA_NODISK;
00433                 m_CardType = CARD_UNKNOWN;
00434             }
00435         } else {
00436             if (m_Cd != m_CdAssert) {
00437                 //The socket is now empty
00438                 m_Status |= (STA_NODISK | STA_NOINIT);
00439                 m_CardType = CARD_NONE;
00440             }
00441         }
00442     }
00443 }
00444 
00445 inline bool SDFileSystem::waitReady(int timeout)
00446 {
00447     char resp;
00448 
00449     //Keep sending dummy clocks with DI held high until the card releases the DO line
00450     m_Timer.start();
00451     do {
00452         resp = m_Spi.write(0xFF);
00453     } while (resp == 0x00 && m_Timer.read_ms() < timeout);
00454     m_Timer.stop();
00455     m_Timer.reset();
00456 
00457     //Return success/failure
00458     return (resp > 0x00);
00459 }
00460 
00461 inline bool SDFileSystem::select()
00462 {
00463     //Assert /CS
00464     m_Cs = 0;
00465 
00466     //Send 8 dummy clocks with DI held high to enable DO
00467     m_Spi.write(0xFF);
00468 
00469     //Wait for up to 500ms for the card to become ready
00470     if (waitReady(500)) {
00471         return true;
00472     } else {
00473         //We timed out, deselect and return false
00474         deselect();
00475         return false;
00476     }
00477 }
00478 
00479 inline void SDFileSystem::deselect()
00480 {
00481     //Deassert /CS
00482     m_Cs = 1;
00483 
00484     //Send 8 dummy clocks with DI held high to disable DO
00485     m_Spi.write(0xFF);
00486 }
00487 
00488 inline char SDFileSystem::commandTransaction(char cmd, unsigned int arg, unsigned int* resp)
00489 {
00490     //Select the card, and wait for ready
00491     if(!select())
00492         return 0xFF;
00493 
00494     //Perform the command transaction
00495     char token = writeCommand(cmd, arg, resp);
00496 
00497     //Deselect the card, and return the R1 response token
00498     deselect();
00499     return token;
00500 }
00501 
00502 char SDFileSystem::writeCommand(char cmd, unsigned int arg, unsigned int* resp)
00503 {
00504     char token;
00505 
00506     //Try to send the command up to 3 times
00507     for (int f = 0; f < 3; f++) {
00508         //Send CMD55(0x00000000) prior to an application specific command
00509         if (cmd == ACMD22 || cmd == ACMD23 || cmd == ACMD41 || cmd == ACMD42) {
00510             token = writeCommand(CMD55, 0x00000000);
00511             if (token > 0x01)
00512                 return token;
00513 
00514             //Deselect and reselect the card between CMD55 and an ACMD
00515             deselect();
00516             if(!select())
00517                 return 0xFF;
00518         }
00519 
00520         //Prepare the command packet
00521         char cmdPacket[6];
00522         cmdPacket[0] = cmd;
00523         cmdPacket[1] = arg >> 24;
00524         cmdPacket[2] = arg >> 16;
00525         cmdPacket[3] = arg >> 8;
00526         cmdPacket[4] = arg;
00527         if (m_Crc || cmd == CMD0 || cmd == CMD8)
00528             cmdPacket[5] = (SDCRC::crc7(cmdPacket, 5) << 1) | 0x01;
00529         else
00530             cmdPacket[5] = 0x01;
00531 
00532         //Send the command packet
00533         for (int i = 0; i < 6; i++)
00534             m_Spi.write(cmdPacket[i]);
00535 
00536         //Discard the stuff byte immediately following CMD12
00537         if (cmd == CMD12)
00538             m_Spi.write(0xFF);
00539 
00540         //Allow up to 8 bytes of delay for the R1 response token
00541         for (int i = 0; i < 9; i++) {
00542             token = m_Spi.write(0xFF);
00543             if (!(token & 0x80))
00544                 break;
00545         }
00546 
00547         //Verify the R1 response token
00548         if (token == 0xFF) {
00549             //No data was received, get out early
00550             break;
00551         } else if (token & (1 << 3)) {
00552             //There was a CRC error, try again
00553             continue;
00554         } else if (token > 0x01) {
00555             //An error occured, get out early
00556             break;
00557         }
00558 
00559         //Handle R2 and R3/R7 response tokens
00560         if (cmd == CMD13 && resp != NULL) {
00561             //Read the R2 response value
00562             *resp = m_Spi.write(0xFF);
00563         } else if ((cmd == CMD8 || cmd == CMD58) && resp != NULL) {
00564             //Read the R3/R7 response value
00565             *resp = (m_Spi.write(0xFF) << 24);
00566             *resp |= (m_Spi.write(0xFF) << 16);
00567             *resp |= (m_Spi.write(0xFF) << 8);
00568             *resp |= m_Spi.write(0xFF);
00569         }
00570 
00571         //The command was successful
00572         break;
00573     }
00574 
00575     //Return the R1 response token
00576     return token;
00577 }
00578 
00579 bool SDFileSystem::readData(char* buffer, int length)
00580 {
00581     char token;
00582     unsigned short crc;
00583 
00584     //Wait for up to 500ms for a token to arrive
00585     m_Timer.start();
00586     do {
00587         token = m_Spi.write(0xFF);
00588     } while (token == 0xFF && m_Timer.read_ms() < 500);
00589     m_Timer.stop();
00590     m_Timer.reset();
00591 
00592     //Check if a valid start block token was received
00593     if (token != 0xFE)
00594         return false;
00595 
00596     //Check if large frames are enabled or not
00597     if (m_LargeFrames) {
00598         //Switch to 16-bit frames for better performance
00599         m_Spi.format(16, 0);
00600 
00601         //Read the data block into the buffer
00602         unsigned short dataWord;
00603         for (int i = 0; i < length; i += 2) {
00604             dataWord = m_Spi.write(0xFFFF);
00605             buffer[i] = dataWord >> 8;
00606             buffer[i + 1] = dataWord;
00607         }
00608 
00609         //Read the CRC16 checksum for the data block
00610         crc = m_Spi.write(0xFFFF);
00611 
00612         //Switch back to 8-bit frames
00613         m_Spi.format(8, 0);
00614     } else {
00615         //Read the data into the buffer
00616         for (int i = 0; i < length; i++)
00617             buffer[i] = m_Spi.write(0xFF);
00618 
00619         //Read the CRC16 checksum for the data block
00620         crc = (m_Spi.write(0xFF) << 8);
00621         crc |= m_Spi.write(0xFF);
00622     }
00623 
00624     //Return the validity of the CRC16 checksum (if enabled)
00625     return (!m_Crc || crc == SDCRC::crc16(buffer, length));
00626 }
00627 
00628 char SDFileSystem::writeData(const char* buffer, char token)
00629 {
00630     //Calculate the CRC16 checksum for the data block (if enabled)
00631     unsigned short crc = (m_Crc) ? SDCRC::crc16(buffer, 512) : 0xFFFF;
00632 
00633     //Wait for up to 500ms for the card to become ready
00634     if (!waitReady(500))
00635         return false;
00636 
00637     //Send the start block token
00638     m_Spi.write(token);
00639 
00640     //Check if large frames are enabled or not
00641     if (m_LargeFrames) {
00642         //Switch to 16-bit frames for better performance
00643         m_Spi.format(16, 0);
00644 
00645         //Write the data block from the buffer
00646         for (int i = 0; i < 512; i += 2)
00647             m_Spi.write((buffer[i] << 8) | buffer[i + 1]);
00648 
00649         //Send the CRC16 checksum for the data block
00650         m_Spi.write(crc);
00651 
00652         //Switch back to 8-bit frames
00653         m_Spi.format(8, 0);
00654     } else {
00655         //Write the data block from the buffer
00656         for (int i = 0; i < 512; i++)
00657             m_Spi.write(buffer[i]);
00658 
00659         //Send the CRC16 checksum for the data block
00660         m_Spi.write(crc >> 8);
00661         m_Spi.write(crc);
00662     }
00663 
00664     //Return the data response token
00665     return (m_Spi.write(0xFF) & 0x1F);
00666 }
00667 
00668 inline bool SDFileSystem::readBlock(char* buffer, unsigned int lba)
00669 {
00670     //Try to read the block up to 3 times
00671     for (int f = 0; f < 3; f++) {
00672         //Select the card, and wait for ready
00673         if(!select())
00674             break;
00675 
00676         //Send CMD17(block) to read a single block
00677         if (writeCommand(CMD17, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
00678             //Try to read the block, and deselect the card
00679             bool success = readData(buffer, 512);
00680             deselect();
00681 
00682             //Return if successful
00683             if (success)
00684                 return true;
00685         } else {
00686             //The command failed, get out
00687             break;
00688         }
00689     }
00690 
00691     //The single block read failed
00692     deselect();
00693     return false;
00694 }
00695 
00696 inline bool SDFileSystem::readBlocks(char* buffer, unsigned int lba, unsigned int count)
00697 {
00698     //Try to read each block up to 3 times
00699     for (int f = 0; f < 3;) {
00700         //Select the card, and wait for ready
00701         if(!select())
00702             break;
00703 
00704         //Send CMD18(block) to read multiple blocks
00705         if (writeCommand(CMD18, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
00706             //Try to read all of the data blocks
00707             do {
00708                 //Read the next block, and break on errors
00709                 if (!readData(buffer, 512)) {
00710                     f++;
00711                     break;
00712                 }
00713 
00714                 //Update the variables
00715                 lba++;
00716                 buffer += 512;
00717                 f = 0;
00718             } while (--count);
00719 
00720             //Send CMD12(0x00000000) to stop the transmission
00721             if (writeCommand(CMD12, 0x00000000) != 0x00) {
00722                 //The command failed, get out
00723                 break;
00724             }
00725 
00726             //Deselect the card, and return if successful
00727             deselect();
00728             if (count == 0)
00729                 return true;
00730         } else {
00731             //The command failed, get out
00732             break;
00733         }
00734     }
00735 
00736     //The multiple block read failed
00737     deselect();
00738     return false;
00739 }
00740 
00741 inline bool SDFileSystem::writeBlock(const char* buffer, unsigned int lba)
00742 {
00743     //Try to write the block up to 3 times
00744     for (int f = 0; f < 3; f++) {
00745         //Select the card, and wait for ready
00746         if(!select())
00747             break;
00748 
00749         //Send CMD24(block) to write a single block
00750         if (writeCommand(CMD24, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
00751             //Try to write the block, and deselect the card
00752             char token = writeData(buffer, 0xFE);
00753             deselect();
00754 
00755             //Check the data response token
00756             if (token == 0x0A) {
00757                 //A CRC error occured, try again
00758                 continue;
00759             } else if (token == 0x0C) {
00760                 //A write error occured, get out
00761                 break;
00762             }
00763 
00764             //Send CMD13(0x00000000) to verify that the programming was successful if enabled
00765             if (m_WriteValidation) {
00766                 unsigned int resp;
00767                 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
00768                     //Some manner of unrecoverable write error occured during programming, get out
00769                     break;
00770                 }
00771             }
00772 
00773             //The data was written successfully
00774             return true;
00775         } else {
00776             //The command failed, get out
00777             break;
00778         }
00779     }
00780 
00781     //The single block write failed
00782     deselect();
00783     return false;
00784 }
00785 
00786 inline bool SDFileSystem::writeBlocks(const char* buffer, unsigned int lba, unsigned int count)
00787 {
00788     char token;
00789     const char* currentBuffer = buffer;
00790     unsigned int currentLba = lba;
00791     int currentCount = count;
00792 
00793     //Try to write each block up to 3 times
00794     for (int f = 0; f < 3;) {
00795         //If this is an SD card, send ACMD23(count) to set the number of blocks to pre-erase
00796         if (m_CardType != CARD_MMC) {
00797             if (commandTransaction(ACMD23, currentCount) != 0x00) {
00798                 //The command failed, get out
00799                 break;
00800             }
00801         }
00802 
00803         //Select the card, and wait for ready
00804         if(!select())
00805             break;
00806 
00807         //Send CMD25(block) to write multiple blocks
00808         if (writeCommand(CMD25, (m_CardType == CARD_SDHC) ? currentLba : currentLba << 9) == 0x00) {
00809             //Try to write all of the data blocks
00810             do {
00811                 //Write the next block and break on errors
00812                 token = writeData(currentBuffer, 0xFC);
00813                 if (token != 0x05) {
00814                     f++;
00815                     break;
00816                 }
00817 
00818                 //Update the variables
00819                 currentBuffer += 512;
00820                 f = 0;
00821             } while (--currentCount);
00822 
00823             //Wait for up to 500ms for the card to finish processing the last block
00824             if (!waitReady(500))
00825                 break;
00826 
00827             //Finalize the transmission
00828             if (currentCount == 0) {
00829                 //Send the stop tran token, and deselect the card
00830                 m_Spi.write(0xFD);
00831                 deselect();
00832 
00833                 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
00834                 if (m_WriteValidation) {
00835                     unsigned int resp;
00836                     if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
00837                         //Some manner of unrecoverable write error occured during programming, get out
00838                         break;
00839                     }
00840                 }
00841 
00842                 //The data was written successfully
00843                 return true;
00844             } else {
00845                 //Send CMD12(0x00000000) to abort the transmission
00846                 if (writeCommand(CMD12, 0x00000000) != 0x00) {
00847                     //The command failed, get out
00848                     break;
00849                 }
00850 
00851                 //Deselect the card
00852                 deselect();
00853 
00854                 //Check the error token
00855                 if (token == 0x0A) {
00856                     //Determine the number of well written blocks if possible
00857                     unsigned int writtenBlocks = 0;
00858                     if (m_CardType != CARD_MMC && select()) {
00859                         //Send ACMD22(0x00000000) to get the number of well written blocks
00860                         if (writeCommand(ACMD22, 0x00000000) == 0x00) {
00861                             //Read the data
00862                             char acmdData[4];
00863                             if (readData(acmdData, 4)) {
00864                                 //Extract the number of well written blocks
00865                                 writtenBlocks = acmdData[0] << 24;
00866                                 writtenBlocks |= acmdData[1] << 16;
00867                                 writtenBlocks |= acmdData[2] << 8;
00868                                 writtenBlocks |= acmdData[3];
00869                             }
00870                         }
00871                         deselect();
00872                     }
00873 
00874                     //Roll back the variables based on the number of well written blocks
00875                     currentBuffer = buffer + (writtenBlocks << 9);
00876                     currentLba = lba + writtenBlocks;
00877                     currentCount = count - writtenBlocks;
00878 
00879                     //Try again
00880                     continue;
00881                 } else {
00882                     //A write error occured, get out
00883                     break;
00884                 }
00885             }
00886         } else {
00887             //The command failed, get out
00888             break;
00889         }
00890     }
00891 
00892     //The multiple block write failed
00893     deselect();
00894     return false;
00895 }
00896 
00897 bool SDFileSystem::enableHighSpeedMode()
00898 {
00899     //Try to issue CMD6 up to 3 times
00900     for (int f = 0; f < 3; f++) {
00901         //Select the card, and wait for ready
00902         if(!select())
00903             break;
00904 
00905         //Send CMD6(0x80FFFFF1) to change the access mode to high speed
00906         if (writeCommand(CMD6, 0x80FFFFF1) == 0x00) {
00907             //Read the 64B status data block
00908             char status[64];
00909             bool success = readData(status, 64);
00910             deselect();
00911             if (success) {
00912                 //Return whether or not the operation was successful
00913                 return ((status[16] & 0x0F) == 0x1);
00914             }
00915         } else {
00916             //The command failed, get out
00917             break;
00918         }
00919     }
00920 
00921     //The operation failed 3 times
00922     deselect();
00923     return false;
00924 }