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