Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of SDFileSystem by
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 }
Generated on Wed Jul 13 2022 11:53:38 by
1.7.2
