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