aaa
Dependencies: FATFileSystem
Dependents: AutoFlight2017_now2 AutoFlight2018_Control sbus_test_2018 Autoflight2018_sbusread ... more
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 Mon Jul 18 2022 02:22:08 by 1.7.2