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