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) 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 14 2022 07:47:09 by
