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