東北大学学友会準加盟団体 From The Earth の高高度ロケットFTE-06(通称:海豚)にて使用したソフトウェアです.ご自由にお使いください.このプログラムによって生じた損害について当団体は一切責任を負いません.また,各モジュールのライブラリは当団体が作成したものではないので再配布は禁止します.

Dependencies:   mbed FATFileSystem

Fork of FTE-06 by Tetsushi Amano

Committer:
mizuki_akaike
Date:
Mon Aug 14 04:55:38 2017 +0000
Revision:
22:b2e90f18ea55
im920???????

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mizuki_akaike 22:b2e90f18ea55 1 /* SD/MMC File System Library
mizuki_akaike 22:b2e90f18ea55 2 * Copyright (c) 2016 Neil Thiessen
mizuki_akaike 22:b2e90f18ea55 3 *
mizuki_akaike 22:b2e90f18ea55 4 * Licensed under the Apache License, Version 2.0 (the "License");
mizuki_akaike 22:b2e90f18ea55 5 * you may not use this file except in compliance with the License.
mizuki_akaike 22:b2e90f18ea55 6 * You may obtain a copy of the License at
mizuki_akaike 22:b2e90f18ea55 7 *
mizuki_akaike 22:b2e90f18ea55 8 * http://www.apache.org/licenses/LICENSE-2.0
mizuki_akaike 22:b2e90f18ea55 9 *
mizuki_akaike 22:b2e90f18ea55 10 * Unless required by applicable law or agreed to in writing, software
mizuki_akaike 22:b2e90f18ea55 11 * distributed under the License is distributed on an "AS IS" BASIS,
mizuki_akaike 22:b2e90f18ea55 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mizuki_akaike 22:b2e90f18ea55 13 * See the License for the specific language governing permissions and
mizuki_akaike 22:b2e90f18ea55 14 * limitations under the License.
mizuki_akaike 22:b2e90f18ea55 15 */
mizuki_akaike 22:b2e90f18ea55 16
mizuki_akaike 22:b2e90f18ea55 17 #include "SDFileSystem.h"
mizuki_akaike 22:b2e90f18ea55 18 #include "diskio.h"
mizuki_akaike 22:b2e90f18ea55 19 #include "pinmap.h"
mizuki_akaike 22:b2e90f18ea55 20 #include "SDCRC.h"
mizuki_akaike 22:b2e90f18ea55 21
mizuki_akaike 22:b2e90f18ea55 22 SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name, PinName cd, SwitchType cdtype, int hz)
mizuki_akaike 22:b2e90f18ea55 23 : FATFileSystem(name),
mizuki_akaike 22:b2e90f18ea55 24 m_Spi(mosi, miso, sclk),
mizuki_akaike 22:b2e90f18ea55 25 m_Cs(cs, 1),
mizuki_akaike 22:b2e90f18ea55 26 m_Cd(cd),
mizuki_akaike 22:b2e90f18ea55 27 m_FREQ(hz)
mizuki_akaike 22:b2e90f18ea55 28 {
mizuki_akaike 22:b2e90f18ea55 29 //Initialize the member variables
mizuki_akaike 22:b2e90f18ea55 30 m_CardType = CARD_NONE;
mizuki_akaike 22:b2e90f18ea55 31 m_Crc = true;
mizuki_akaike 22:b2e90f18ea55 32 m_LargeFrames = false;
mizuki_akaike 22:b2e90f18ea55 33 m_WriteValidation = true;
mizuki_akaike 22:b2e90f18ea55 34 m_Status = STA_NOINIT;
mizuki_akaike 22:b2e90f18ea55 35
mizuki_akaike 22:b2e90f18ea55 36 //Enable the internal pull-up resistor on MISO
mizuki_akaike 22:b2e90f18ea55 37 pin_mode(miso, PullUp);
mizuki_akaike 22:b2e90f18ea55 38
mizuki_akaike 22:b2e90f18ea55 39 //Configure the SPI bus
mizuki_akaike 22:b2e90f18ea55 40 m_Spi.format(8, 0);
mizuki_akaike 22:b2e90f18ea55 41
mizuki_akaike 22:b2e90f18ea55 42 //Configure the card detect pin
mizuki_akaike 22:b2e90f18ea55 43 if (cdtype == SWITCH_POS_NO) {
mizuki_akaike 22:b2e90f18ea55 44 m_Cd.mode(PullDown);
mizuki_akaike 22:b2e90f18ea55 45 m_CdAssert = 1;
mizuki_akaike 22:b2e90f18ea55 46 m_Cd.fall(this, &SDFileSystem::onCardRemoval);
mizuki_akaike 22:b2e90f18ea55 47 } else if (cdtype == SWITCH_POS_NC) {
mizuki_akaike 22:b2e90f18ea55 48 m_Cd.mode(PullDown);
mizuki_akaike 22:b2e90f18ea55 49 m_CdAssert = 0;
mizuki_akaike 22:b2e90f18ea55 50 m_Cd.rise(this, &SDFileSystem::onCardRemoval);
mizuki_akaike 22:b2e90f18ea55 51 } else if (cdtype == SWITCH_NEG_NO) {
mizuki_akaike 22:b2e90f18ea55 52 m_Cd.mode(PullUp);
mizuki_akaike 22:b2e90f18ea55 53 m_CdAssert = 0;
mizuki_akaike 22:b2e90f18ea55 54 m_Cd.rise(this, &SDFileSystem::onCardRemoval);
mizuki_akaike 22:b2e90f18ea55 55 } else if (cdtype == SWITCH_NEG_NC) {
mizuki_akaike 22:b2e90f18ea55 56 m_Cd.mode(PullUp);
mizuki_akaike 22:b2e90f18ea55 57 m_CdAssert = 1;
mizuki_akaike 22:b2e90f18ea55 58 m_Cd.fall(this, &SDFileSystem::onCardRemoval);
mizuki_akaike 22:b2e90f18ea55 59 } else {
mizuki_akaike 22:b2e90f18ea55 60 m_CdAssert = -1;
mizuki_akaike 22:b2e90f18ea55 61 }
mizuki_akaike 22:b2e90f18ea55 62 }
mizuki_akaike 22:b2e90f18ea55 63
mizuki_akaike 22:b2e90f18ea55 64 bool SDFileSystem::card_present()
mizuki_akaike 22:b2e90f18ea55 65 {
mizuki_akaike 22:b2e90f18ea55 66 //Check the card socket
mizuki_akaike 22:b2e90f18ea55 67 checkSocket();
mizuki_akaike 22:b2e90f18ea55 68
mizuki_akaike 22:b2e90f18ea55 69 //Return whether or not a card is present
mizuki_akaike 22:b2e90f18ea55 70 return !(m_Status & STA_NODISK);
mizuki_akaike 22:b2e90f18ea55 71 }
mizuki_akaike 22:b2e90f18ea55 72
mizuki_akaike 22:b2e90f18ea55 73 SDFileSystem::CardType SDFileSystem::card_type()
mizuki_akaike 22:b2e90f18ea55 74 {
mizuki_akaike 22:b2e90f18ea55 75 //Check the card socket
mizuki_akaike 22:b2e90f18ea55 76 checkSocket();
mizuki_akaike 22:b2e90f18ea55 77
mizuki_akaike 22:b2e90f18ea55 78 //Return the card type
mizuki_akaike 22:b2e90f18ea55 79 return m_CardType;
mizuki_akaike 22:b2e90f18ea55 80 }
mizuki_akaike 22:b2e90f18ea55 81
mizuki_akaike 22:b2e90f18ea55 82 bool SDFileSystem::crc()
mizuki_akaike 22:b2e90f18ea55 83 {
mizuki_akaike 22:b2e90f18ea55 84 //Return whether or not CRC is enabled
mizuki_akaike 22:b2e90f18ea55 85 return m_Crc;
mizuki_akaike 22:b2e90f18ea55 86 }
mizuki_akaike 22:b2e90f18ea55 87
mizuki_akaike 22:b2e90f18ea55 88 void SDFileSystem::crc(bool enabled)
mizuki_akaike 22:b2e90f18ea55 89 {
mizuki_akaike 22:b2e90f18ea55 90 //Check the card socket
mizuki_akaike 22:b2e90f18ea55 91 checkSocket();
mizuki_akaike 22:b2e90f18ea55 92
mizuki_akaike 22:b2e90f18ea55 93 //Just update the member variable if the card isn't initialized
mizuki_akaike 22:b2e90f18ea55 94 if (m_Status & STA_NOINIT) {
mizuki_akaike 22:b2e90f18ea55 95 m_Crc = enabled;
mizuki_akaike 22:b2e90f18ea55 96 return;
mizuki_akaike 22:b2e90f18ea55 97 }
mizuki_akaike 22:b2e90f18ea55 98
mizuki_akaike 22:b2e90f18ea55 99 //Enable or disable CRC
mizuki_akaike 22:b2e90f18ea55 100 if (enabled && !m_Crc) {
mizuki_akaike 22:b2e90f18ea55 101 //Send CMD59(0x00000001) to enable CRC
mizuki_akaike 22:b2e90f18ea55 102 m_Crc = true;
mizuki_akaike 22:b2e90f18ea55 103 commandTransaction(CMD59, 0x00000001);
mizuki_akaike 22:b2e90f18ea55 104 } else if (!enabled && m_Crc) {
mizuki_akaike 22:b2e90f18ea55 105 //Send CMD59(0x00000000) to disable CRC
mizuki_akaike 22:b2e90f18ea55 106 commandTransaction(CMD59, 0x00000000);
mizuki_akaike 22:b2e90f18ea55 107 m_Crc = false;
mizuki_akaike 22:b2e90f18ea55 108 }
mizuki_akaike 22:b2e90f18ea55 109 }
mizuki_akaike 22:b2e90f18ea55 110
mizuki_akaike 22:b2e90f18ea55 111 bool SDFileSystem::large_frames()
mizuki_akaike 22:b2e90f18ea55 112 {
mizuki_akaike 22:b2e90f18ea55 113 //Return whether or not 16-bit frames are enabled
mizuki_akaike 22:b2e90f18ea55 114 return m_LargeFrames;
mizuki_akaike 22:b2e90f18ea55 115 }
mizuki_akaike 22:b2e90f18ea55 116
mizuki_akaike 22:b2e90f18ea55 117 void SDFileSystem::large_frames(bool enabled)
mizuki_akaike 22:b2e90f18ea55 118 {
mizuki_akaike 22:b2e90f18ea55 119 //Set whether or not 16-bit frames are enabled
mizuki_akaike 22:b2e90f18ea55 120 m_LargeFrames = enabled;
mizuki_akaike 22:b2e90f18ea55 121 }
mizuki_akaike 22:b2e90f18ea55 122
mizuki_akaike 22:b2e90f18ea55 123 bool SDFileSystem::write_validation()
mizuki_akaike 22:b2e90f18ea55 124 {
mizuki_akaike 22:b2e90f18ea55 125 //Return whether or not write validation is enabled
mizuki_akaike 22:b2e90f18ea55 126 return m_WriteValidation;
mizuki_akaike 22:b2e90f18ea55 127 }
mizuki_akaike 22:b2e90f18ea55 128
mizuki_akaike 22:b2e90f18ea55 129 void SDFileSystem::write_validation(bool enabled)
mizuki_akaike 22:b2e90f18ea55 130 {
mizuki_akaike 22:b2e90f18ea55 131 //Set whether or not write validation is enabled
mizuki_akaike 22:b2e90f18ea55 132 m_WriteValidation = enabled;
mizuki_akaike 22:b2e90f18ea55 133 }
mizuki_akaike 22:b2e90f18ea55 134
mizuki_akaike 22:b2e90f18ea55 135 int SDFileSystem::unmount()
mizuki_akaike 22:b2e90f18ea55 136 {
mizuki_akaike 22:b2e90f18ea55 137 //Unmount the filesystem
mizuki_akaike 22:b2e90f18ea55 138 FATFileSystem::unmount();
mizuki_akaike 22:b2e90f18ea55 139
mizuki_akaike 22:b2e90f18ea55 140 //Change the status to not initialized, and the card type to unknown
mizuki_akaike 22:b2e90f18ea55 141 m_Status |= STA_NOINIT;
mizuki_akaike 22:b2e90f18ea55 142 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 143
mizuki_akaike 22:b2e90f18ea55 144 //Always succeeds
mizuki_akaike 22:b2e90f18ea55 145 return 0;
mizuki_akaike 22:b2e90f18ea55 146 }
mizuki_akaike 22:b2e90f18ea55 147
mizuki_akaike 22:b2e90f18ea55 148 int SDFileSystem::disk_initialize()
mizuki_akaike 22:b2e90f18ea55 149 {
mizuki_akaike 22:b2e90f18ea55 150 char token;
mizuki_akaike 22:b2e90f18ea55 151 unsigned int resp;
mizuki_akaike 22:b2e90f18ea55 152 Timer timer;
mizuki_akaike 22:b2e90f18ea55 153
mizuki_akaike 22:b2e90f18ea55 154 //Make sure there's a card in the socket before proceeding
mizuki_akaike 22:b2e90f18ea55 155 checkSocket();
mizuki_akaike 22:b2e90f18ea55 156 if (m_Status & STA_NODISK)
mizuki_akaike 22:b2e90f18ea55 157 return m_Status;
mizuki_akaike 22:b2e90f18ea55 158
mizuki_akaike 22:b2e90f18ea55 159 //Make sure we're not already initialized before proceeding
mizuki_akaike 22:b2e90f18ea55 160 if (!(m_Status & STA_NOINIT))
mizuki_akaike 22:b2e90f18ea55 161 return m_Status;
mizuki_akaike 22:b2e90f18ea55 162
mizuki_akaike 22:b2e90f18ea55 163 //Set the SPI frequency to 400kHz for initialization
mizuki_akaike 22:b2e90f18ea55 164 m_Spi.frequency(400000);
mizuki_akaike 22:b2e90f18ea55 165
mizuki_akaike 22:b2e90f18ea55 166 //Try to reset the card up to 3 times
mizuki_akaike 22:b2e90f18ea55 167 for (int f = 0; f < 3; f++) {
mizuki_akaike 22:b2e90f18ea55 168 //Send 80 dummy clocks with /CS deasserted and DI held high
mizuki_akaike 22:b2e90f18ea55 169 m_Cs = 1;
mizuki_akaike 22:b2e90f18ea55 170 for (int i = 0; i < 10; i++) {
mizuki_akaike 22:b2e90f18ea55 171 m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 172 }
mizuki_akaike 22:b2e90f18ea55 173
mizuki_akaike 22:b2e90f18ea55 174 //Send CMD0(0x00000000) to reset the card
mizuki_akaike 22:b2e90f18ea55 175 token = commandTransaction(CMD0, 0x00000000);
mizuki_akaike 22:b2e90f18ea55 176 if (token == 0x01) {
mizuki_akaike 22:b2e90f18ea55 177 break;
mizuki_akaike 22:b2e90f18ea55 178 }
mizuki_akaike 22:b2e90f18ea55 179 }
mizuki_akaike 22:b2e90f18ea55 180
mizuki_akaike 22:b2e90f18ea55 181 //Check if the card reset
mizuki_akaike 22:b2e90f18ea55 182 if (token != 0x01) {
mizuki_akaike 22:b2e90f18ea55 183 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 184 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 185 return m_Status;
mizuki_akaike 22:b2e90f18ea55 186 }
mizuki_akaike 22:b2e90f18ea55 187
mizuki_akaike 22:b2e90f18ea55 188 //Send CMD59(0x00000001) to enable CRC if necessary
mizuki_akaike 22:b2e90f18ea55 189 if (m_Crc) {
mizuki_akaike 22:b2e90f18ea55 190 if (commandTransaction(CMD59, 0x00000001) != 0x01) {
mizuki_akaike 22:b2e90f18ea55 191 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 192 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 193 return m_Status;
mizuki_akaike 22:b2e90f18ea55 194 }
mizuki_akaike 22:b2e90f18ea55 195 }
mizuki_akaike 22:b2e90f18ea55 196
mizuki_akaike 22:b2e90f18ea55 197 //Send CMD8(0x000001AA) to see if this is an SDCv2 card
mizuki_akaike 22:b2e90f18ea55 198 if (commandTransaction(CMD8, 0x000001AA, &resp) == 0x01) {
mizuki_akaike 22:b2e90f18ea55 199 //This is an SDCv2 card, get the 32-bit return value and verify the voltage range/check pattern
mizuki_akaike 22:b2e90f18ea55 200 if ((resp & 0xFFF) != 0x1AA) {
mizuki_akaike 22:b2e90f18ea55 201 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 202 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 203 return m_Status;
mizuki_akaike 22:b2e90f18ea55 204 }
mizuki_akaike 22:b2e90f18ea55 205
mizuki_akaike 22:b2e90f18ea55 206 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
mizuki_akaike 22:b2e90f18ea55 207 if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
mizuki_akaike 22:b2e90f18ea55 208 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 209 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 210 return m_Status;
mizuki_akaike 22:b2e90f18ea55 211 }
mizuki_akaike 22:b2e90f18ea55 212
mizuki_akaike 22:b2e90f18ea55 213 //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
mizuki_akaike 22:b2e90f18ea55 214 timer.start();
mizuki_akaike 22:b2e90f18ea55 215 do {
mizuki_akaike 22:b2e90f18ea55 216 token = commandTransaction(ACMD41, 0x40100000);
mizuki_akaike 22:b2e90f18ea55 217 } while (token == 0x01 && timer.read_ms() < 2000);
mizuki_akaike 22:b2e90f18ea55 218 timer.stop();
mizuki_akaike 22:b2e90f18ea55 219 timer.reset();
mizuki_akaike 22:b2e90f18ea55 220
mizuki_akaike 22:b2e90f18ea55 221 //Check if the card initialized
mizuki_akaike 22:b2e90f18ea55 222 if (token != 0x00) {
mizuki_akaike 22:b2e90f18ea55 223 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 224 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 225 return m_Status;
mizuki_akaike 22:b2e90f18ea55 226 }
mizuki_akaike 22:b2e90f18ea55 227
mizuki_akaike 22:b2e90f18ea55 228 //Send CMD58(0x00000000) to read the OCR
mizuki_akaike 22:b2e90f18ea55 229 if (commandTransaction(CMD58, 0x00000000, &resp) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 230 //Check the CCS bit to determine if this is a high capacity card
mizuki_akaike 22:b2e90f18ea55 231 if (resp & (1 << 30))
mizuki_akaike 22:b2e90f18ea55 232 m_CardType = CARD_SDHC;
mizuki_akaike 22:b2e90f18ea55 233 else
mizuki_akaike 22:b2e90f18ea55 234 m_CardType = CARD_SD;
mizuki_akaike 22:b2e90f18ea55 235
mizuki_akaike 22:b2e90f18ea55 236 //Increase the SPI frequency to full speed (up to 50MHz for SDCv2)
mizuki_akaike 22:b2e90f18ea55 237 if (m_FREQ > 25000000) {
mizuki_akaike 22:b2e90f18ea55 238 if (enableHighSpeedMode()) {
mizuki_akaike 22:b2e90f18ea55 239 if (m_FREQ > 50000000) {
mizuki_akaike 22:b2e90f18ea55 240 m_Spi.frequency(50000000);
mizuki_akaike 22:b2e90f18ea55 241 } else {
mizuki_akaike 22:b2e90f18ea55 242 m_Spi.frequency(m_FREQ);
mizuki_akaike 22:b2e90f18ea55 243 }
mizuki_akaike 22:b2e90f18ea55 244 } else {
mizuki_akaike 22:b2e90f18ea55 245 m_Spi.frequency(25000000);
mizuki_akaike 22:b2e90f18ea55 246 }
mizuki_akaike 22:b2e90f18ea55 247 } else {
mizuki_akaike 22:b2e90f18ea55 248 m_Spi.frequency(m_FREQ);
mizuki_akaike 22:b2e90f18ea55 249 }
mizuki_akaike 22:b2e90f18ea55 250 } else {
mizuki_akaike 22:b2e90f18ea55 251 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 252 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 253 return m_Status;
mizuki_akaike 22:b2e90f18ea55 254 }
mizuki_akaike 22:b2e90f18ea55 255 } else {
mizuki_akaike 22:b2e90f18ea55 256 //Didn't respond or illegal command, this is either an SDCv1 or MMC card
mizuki_akaike 22:b2e90f18ea55 257 //Send CMD58(0x00000000) to read the OCR, and verify that the card supports 3.2-3.3V
mizuki_akaike 22:b2e90f18ea55 258 if (commandTransaction(CMD58, 0x00000000, &resp) != 0x01 || !(resp & (1 << 20))) {
mizuki_akaike 22:b2e90f18ea55 259 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 260 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 261 return m_Status;
mizuki_akaike 22:b2e90f18ea55 262 }
mizuki_akaike 22:b2e90f18ea55 263
mizuki_akaike 22:b2e90f18ea55 264 //Try to initialize the card using ACMD41(0x40100000) for up to 2 seconds
mizuki_akaike 22:b2e90f18ea55 265 timer.start();
mizuki_akaike 22:b2e90f18ea55 266 do {
mizuki_akaike 22:b2e90f18ea55 267 token = commandTransaction(ACMD41, 0x40100000);
mizuki_akaike 22:b2e90f18ea55 268 } while (token == 0x01 && timer.read_ms() < 2000);
mizuki_akaike 22:b2e90f18ea55 269 timer.stop();
mizuki_akaike 22:b2e90f18ea55 270 timer.reset();
mizuki_akaike 22:b2e90f18ea55 271
mizuki_akaike 22:b2e90f18ea55 272 //Check if the card initialized
mizuki_akaike 22:b2e90f18ea55 273 if (token == 0x00) {
mizuki_akaike 22:b2e90f18ea55 274 //This is an SDCv1 standard capacity card
mizuki_akaike 22:b2e90f18ea55 275 m_CardType = CARD_SD;
mizuki_akaike 22:b2e90f18ea55 276
mizuki_akaike 22:b2e90f18ea55 277 //Increase the SPI frequency to full speed (up to 25MHz for SDCv1)
mizuki_akaike 22:b2e90f18ea55 278 if (m_FREQ > 25000000)
mizuki_akaike 22:b2e90f18ea55 279 m_Spi.frequency(25000000);
mizuki_akaike 22:b2e90f18ea55 280 else
mizuki_akaike 22:b2e90f18ea55 281 m_Spi.frequency(m_FREQ);
mizuki_akaike 22:b2e90f18ea55 282 } else {
mizuki_akaike 22:b2e90f18ea55 283 //Try to initialize the card using CMD1(0x00100000) for up to 2 seconds
mizuki_akaike 22:b2e90f18ea55 284 timer.start();
mizuki_akaike 22:b2e90f18ea55 285 do {
mizuki_akaike 22:b2e90f18ea55 286 token = commandTransaction(CMD1, 0x00100000);
mizuki_akaike 22:b2e90f18ea55 287 } while (token == 0x01 && timer.read_ms() < 2000);
mizuki_akaike 22:b2e90f18ea55 288 timer.stop();
mizuki_akaike 22:b2e90f18ea55 289 timer.reset();
mizuki_akaike 22:b2e90f18ea55 290
mizuki_akaike 22:b2e90f18ea55 291 //Check if the card initialized
mizuki_akaike 22:b2e90f18ea55 292 if (token == 0x00) {
mizuki_akaike 22:b2e90f18ea55 293 //This is an MMCv3 card
mizuki_akaike 22:b2e90f18ea55 294 m_CardType = CARD_MMC;
mizuki_akaike 22:b2e90f18ea55 295
mizuki_akaike 22:b2e90f18ea55 296 //Increase the SPI frequency to full speed (up to 20MHz for MMCv3)
mizuki_akaike 22:b2e90f18ea55 297 if (m_FREQ > 20000000)
mizuki_akaike 22:b2e90f18ea55 298 m_Spi.frequency(20000000);
mizuki_akaike 22:b2e90f18ea55 299 else
mizuki_akaike 22:b2e90f18ea55 300 m_Spi.frequency(m_FREQ);
mizuki_akaike 22:b2e90f18ea55 301 } else {
mizuki_akaike 22:b2e90f18ea55 302 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 303 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 304 return m_Status;
mizuki_akaike 22:b2e90f18ea55 305 }
mizuki_akaike 22:b2e90f18ea55 306 }
mizuki_akaike 22:b2e90f18ea55 307 }
mizuki_akaike 22:b2e90f18ea55 308
mizuki_akaike 22:b2e90f18ea55 309 //Send ACMD42(0x00000000) to disconnect the internal pull-up resistor on pin 1 if necessary
mizuki_akaike 22:b2e90f18ea55 310 if (m_CardType != CARD_MMC) {
mizuki_akaike 22:b2e90f18ea55 311 if (commandTransaction(ACMD42, 0x00000000) != 0x00) {
mizuki_akaike 22:b2e90f18ea55 312 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 313 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 314 return m_Status;
mizuki_akaike 22:b2e90f18ea55 315 }
mizuki_akaike 22:b2e90f18ea55 316 }
mizuki_akaike 22:b2e90f18ea55 317
mizuki_akaike 22:b2e90f18ea55 318 //Send CMD16(0x00000200) to force the block size to 512B if necessary
mizuki_akaike 22:b2e90f18ea55 319 if (m_CardType != CARD_SDHC) {
mizuki_akaike 22:b2e90f18ea55 320 if (commandTransaction(CMD16, 0x00000200) != 0x00) {
mizuki_akaike 22:b2e90f18ea55 321 //Initialization failed
mizuki_akaike 22:b2e90f18ea55 322 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 323 return m_Status;
mizuki_akaike 22:b2e90f18ea55 324 }
mizuki_akaike 22:b2e90f18ea55 325 }
mizuki_akaike 22:b2e90f18ea55 326
mizuki_akaike 22:b2e90f18ea55 327 //The card is now initialized
mizuki_akaike 22:b2e90f18ea55 328 m_Status &= ~STA_NOINIT;
mizuki_akaike 22:b2e90f18ea55 329
mizuki_akaike 22:b2e90f18ea55 330 //Return the disk status
mizuki_akaike 22:b2e90f18ea55 331 return m_Status;
mizuki_akaike 22:b2e90f18ea55 332 }
mizuki_akaike 22:b2e90f18ea55 333
mizuki_akaike 22:b2e90f18ea55 334 int SDFileSystem::disk_status()
mizuki_akaike 22:b2e90f18ea55 335 {
mizuki_akaike 22:b2e90f18ea55 336 //Check the card socket
mizuki_akaike 22:b2e90f18ea55 337 checkSocket();
mizuki_akaike 22:b2e90f18ea55 338
mizuki_akaike 22:b2e90f18ea55 339 //Return the disk status
mizuki_akaike 22:b2e90f18ea55 340 return m_Status;
mizuki_akaike 22:b2e90f18ea55 341 }
mizuki_akaike 22:b2e90f18ea55 342
mizuki_akaike 22:b2e90f18ea55 343 int SDFileSystem::disk_read(uint8_t* buffer, uint32_t sector, uint32_t count)
mizuki_akaike 22:b2e90f18ea55 344 {
mizuki_akaike 22:b2e90f18ea55 345 //Make sure the card is initialized before proceeding
mizuki_akaike 22:b2e90f18ea55 346 if (m_Status & STA_NOINIT)
mizuki_akaike 22:b2e90f18ea55 347 return RES_NOTRDY;
mizuki_akaike 22:b2e90f18ea55 348
mizuki_akaike 22:b2e90f18ea55 349 //Read a single block, or multiple blocks
mizuki_akaike 22:b2e90f18ea55 350 if (count > 1) {
mizuki_akaike 22:b2e90f18ea55 351 return readBlocks((char*)buffer, sector, count) ? RES_OK : RES_ERROR;
mizuki_akaike 22:b2e90f18ea55 352 } else {
mizuki_akaike 22:b2e90f18ea55 353 return readBlock((char*)buffer, sector) ? RES_OK : RES_ERROR;
mizuki_akaike 22:b2e90f18ea55 354 }
mizuki_akaike 22:b2e90f18ea55 355 }
mizuki_akaike 22:b2e90f18ea55 356
mizuki_akaike 22:b2e90f18ea55 357 int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t sector, uint32_t count)
mizuki_akaike 22:b2e90f18ea55 358 {
mizuki_akaike 22:b2e90f18ea55 359 //Make sure the card is initialized before proceeding
mizuki_akaike 22:b2e90f18ea55 360 if (m_Status & STA_NOINIT)
mizuki_akaike 22:b2e90f18ea55 361 return RES_NOTRDY;
mizuki_akaike 22:b2e90f18ea55 362
mizuki_akaike 22:b2e90f18ea55 363 //Make sure the card isn't write protected before proceeding
mizuki_akaike 22:b2e90f18ea55 364 if (m_Status & STA_PROTECT)
mizuki_akaike 22:b2e90f18ea55 365 return RES_WRPRT;
mizuki_akaike 22:b2e90f18ea55 366
mizuki_akaike 22:b2e90f18ea55 367 //Write a single block, or multiple blocks
mizuki_akaike 22:b2e90f18ea55 368 if (count > 1) {
mizuki_akaike 22:b2e90f18ea55 369 return writeBlocks((const char*)buffer, sector, count) ? RES_OK : RES_ERROR;
mizuki_akaike 22:b2e90f18ea55 370 } else {
mizuki_akaike 22:b2e90f18ea55 371 return writeBlock((const char*)buffer, sector) ? RES_OK : RES_ERROR;
mizuki_akaike 22:b2e90f18ea55 372 }
mizuki_akaike 22:b2e90f18ea55 373 }
mizuki_akaike 22:b2e90f18ea55 374
mizuki_akaike 22:b2e90f18ea55 375 int SDFileSystem::disk_sync()
mizuki_akaike 22:b2e90f18ea55 376 {
mizuki_akaike 22:b2e90f18ea55 377 //Select the card so we're forced to wait for the end of any internal write processes
mizuki_akaike 22:b2e90f18ea55 378 if (select()) {
mizuki_akaike 22:b2e90f18ea55 379 deselect();
mizuki_akaike 22:b2e90f18ea55 380 return RES_OK;
mizuki_akaike 22:b2e90f18ea55 381 } else {
mizuki_akaike 22:b2e90f18ea55 382 return RES_ERROR;
mizuki_akaike 22:b2e90f18ea55 383 }
mizuki_akaike 22:b2e90f18ea55 384 }
mizuki_akaike 22:b2e90f18ea55 385
mizuki_akaike 22:b2e90f18ea55 386 uint32_t SDFileSystem::disk_sectors()
mizuki_akaike 22:b2e90f18ea55 387 {
mizuki_akaike 22:b2e90f18ea55 388 //Make sure the card is initialized before proceeding
mizuki_akaike 22:b2e90f18ea55 389 if (m_Status & STA_NOINIT)
mizuki_akaike 22:b2e90f18ea55 390 return 0;
mizuki_akaike 22:b2e90f18ea55 391
mizuki_akaike 22:b2e90f18ea55 392 //Try to read the CSD register up to 3 times
mizuki_akaike 22:b2e90f18ea55 393 for (int f = 0; f < 3; f++) {
mizuki_akaike 22:b2e90f18ea55 394 //Select the card, and wait for ready
mizuki_akaike 22:b2e90f18ea55 395 if(!select())
mizuki_akaike 22:b2e90f18ea55 396 break;
mizuki_akaike 22:b2e90f18ea55 397
mizuki_akaike 22:b2e90f18ea55 398 //Send CMD9(0x00000000) to read the CSD register
mizuki_akaike 22:b2e90f18ea55 399 if (writeCommand(CMD9, 0x00000000) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 400 //Read the 16B CSD data block
mizuki_akaike 22:b2e90f18ea55 401 char csd[16];
mizuki_akaike 22:b2e90f18ea55 402 bool success = readData(csd, 16);
mizuki_akaike 22:b2e90f18ea55 403 deselect();
mizuki_akaike 22:b2e90f18ea55 404 if (success) {
mizuki_akaike 22:b2e90f18ea55 405 //Calculate the sector count based on the card type
mizuki_akaike 22:b2e90f18ea55 406 if ((csd[0] >> 6) == 0x01) {
mizuki_akaike 22:b2e90f18ea55 407 //Calculate the sector count for a high capacity card
mizuki_akaike 22:b2e90f18ea55 408 unsigned int size = (((csd[7] & 0x3F) << 16) | (csd[8] << 8) | csd[9]) + 1;
mizuki_akaike 22:b2e90f18ea55 409 return size << 10;
mizuki_akaike 22:b2e90f18ea55 410 } else {
mizuki_akaike 22:b2e90f18ea55 411 //Calculate the sector count for a standard capacity card
mizuki_akaike 22:b2e90f18ea55 412 unsigned int size = (((csd[6] & 0x03) << 10) | (csd[7] << 2) | ((csd[8] & 0xC0) >> 6)) + 1;
mizuki_akaike 22:b2e90f18ea55 413 size <<= ((((csd[9] & 0x03) << 1) | ((csd[10] & 0x80) >> 7)) + 2);
mizuki_akaike 22:b2e90f18ea55 414 size <<= (csd[5] & 0x0F);
mizuki_akaike 22:b2e90f18ea55 415 return size >> 9;
mizuki_akaike 22:b2e90f18ea55 416 }
mizuki_akaike 22:b2e90f18ea55 417 }
mizuki_akaike 22:b2e90f18ea55 418 } else {
mizuki_akaike 22:b2e90f18ea55 419 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 420 break;
mizuki_akaike 22:b2e90f18ea55 421 }
mizuki_akaike 22:b2e90f18ea55 422 }
mizuki_akaike 22:b2e90f18ea55 423
mizuki_akaike 22:b2e90f18ea55 424 //The read operation failed 3 times
mizuki_akaike 22:b2e90f18ea55 425 deselect();
mizuki_akaike 22:b2e90f18ea55 426 return 0;
mizuki_akaike 22:b2e90f18ea55 427 }
mizuki_akaike 22:b2e90f18ea55 428
mizuki_akaike 22:b2e90f18ea55 429 void SDFileSystem::onCardRemoval()
mizuki_akaike 22:b2e90f18ea55 430 {
mizuki_akaike 22:b2e90f18ea55 431 //Check the card socket
mizuki_akaike 22:b2e90f18ea55 432 checkSocket();
mizuki_akaike 22:b2e90f18ea55 433 }
mizuki_akaike 22:b2e90f18ea55 434
mizuki_akaike 22:b2e90f18ea55 435 inline void SDFileSystem::checkSocket()
mizuki_akaike 22:b2e90f18ea55 436 {
mizuki_akaike 22:b2e90f18ea55 437 //Use the card detect switch (if available) to determine if the socket is occupied
mizuki_akaike 22:b2e90f18ea55 438 if (m_CdAssert != -1) {
mizuki_akaike 22:b2e90f18ea55 439 if (m_Status & STA_NODISK) {
mizuki_akaike 22:b2e90f18ea55 440 if (m_Cd == m_CdAssert) {
mizuki_akaike 22:b2e90f18ea55 441 //The socket is now occupied
mizuki_akaike 22:b2e90f18ea55 442 m_Status &= ~STA_NODISK;
mizuki_akaike 22:b2e90f18ea55 443 m_CardType = CARD_UNKNOWN;
mizuki_akaike 22:b2e90f18ea55 444 }
mizuki_akaike 22:b2e90f18ea55 445 } else {
mizuki_akaike 22:b2e90f18ea55 446 if (m_Cd != m_CdAssert) {
mizuki_akaike 22:b2e90f18ea55 447 //The socket is now empty
mizuki_akaike 22:b2e90f18ea55 448 m_Status |= (STA_NODISK | STA_NOINIT);
mizuki_akaike 22:b2e90f18ea55 449 m_CardType = CARD_NONE;
mizuki_akaike 22:b2e90f18ea55 450 }
mizuki_akaike 22:b2e90f18ea55 451 }
mizuki_akaike 22:b2e90f18ea55 452 }
mizuki_akaike 22:b2e90f18ea55 453 }
mizuki_akaike 22:b2e90f18ea55 454
mizuki_akaike 22:b2e90f18ea55 455 inline bool SDFileSystem::waitReady(int timeout)
mizuki_akaike 22:b2e90f18ea55 456 {
mizuki_akaike 22:b2e90f18ea55 457 char resp;
mizuki_akaike 22:b2e90f18ea55 458
mizuki_akaike 22:b2e90f18ea55 459 //Keep sending dummy clocks with DI held high until the card releases the DO line
mizuki_akaike 22:b2e90f18ea55 460 m_Timer.start();
mizuki_akaike 22:b2e90f18ea55 461 do {
mizuki_akaike 22:b2e90f18ea55 462 resp = m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 463 } while (resp == 0x00 && m_Timer.read_ms() < timeout);
mizuki_akaike 22:b2e90f18ea55 464 m_Timer.stop();
mizuki_akaike 22:b2e90f18ea55 465 m_Timer.reset();
mizuki_akaike 22:b2e90f18ea55 466
mizuki_akaike 22:b2e90f18ea55 467 //Return success/failure
mizuki_akaike 22:b2e90f18ea55 468 return (resp > 0x00);
mizuki_akaike 22:b2e90f18ea55 469 }
mizuki_akaike 22:b2e90f18ea55 470
mizuki_akaike 22:b2e90f18ea55 471 inline bool SDFileSystem::select()
mizuki_akaike 22:b2e90f18ea55 472 {
mizuki_akaike 22:b2e90f18ea55 473 //Assert /CS
mizuki_akaike 22:b2e90f18ea55 474 m_Cs = 0;
mizuki_akaike 22:b2e90f18ea55 475
mizuki_akaike 22:b2e90f18ea55 476 //Send 8 dummy clocks with DI held high to enable DO
mizuki_akaike 22:b2e90f18ea55 477 m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 478
mizuki_akaike 22:b2e90f18ea55 479 //Wait for up to 500ms for the card to become ready
mizuki_akaike 22:b2e90f18ea55 480 if (waitReady(500)) {
mizuki_akaike 22:b2e90f18ea55 481 return true;
mizuki_akaike 22:b2e90f18ea55 482 } else {
mizuki_akaike 22:b2e90f18ea55 483 //We timed out, deselect and return false
mizuki_akaike 22:b2e90f18ea55 484 deselect();
mizuki_akaike 22:b2e90f18ea55 485 return false;
mizuki_akaike 22:b2e90f18ea55 486 }
mizuki_akaike 22:b2e90f18ea55 487 }
mizuki_akaike 22:b2e90f18ea55 488
mizuki_akaike 22:b2e90f18ea55 489 inline void SDFileSystem::deselect()
mizuki_akaike 22:b2e90f18ea55 490 {
mizuki_akaike 22:b2e90f18ea55 491 //Deassert /CS
mizuki_akaike 22:b2e90f18ea55 492 m_Cs = 1;
mizuki_akaike 22:b2e90f18ea55 493
mizuki_akaike 22:b2e90f18ea55 494 //Send 8 dummy clocks with DI held high to disable DO
mizuki_akaike 22:b2e90f18ea55 495 m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 496 }
mizuki_akaike 22:b2e90f18ea55 497
mizuki_akaike 22:b2e90f18ea55 498 inline char SDFileSystem::commandTransaction(char cmd, unsigned int arg, unsigned int* resp)
mizuki_akaike 22:b2e90f18ea55 499 {
mizuki_akaike 22:b2e90f18ea55 500 //Select the card, and wait for ready
mizuki_akaike 22:b2e90f18ea55 501 if(!select())
mizuki_akaike 22:b2e90f18ea55 502 return 0xFF;
mizuki_akaike 22:b2e90f18ea55 503
mizuki_akaike 22:b2e90f18ea55 504 //Perform the command transaction
mizuki_akaike 22:b2e90f18ea55 505 char token = writeCommand(cmd, arg, resp);
mizuki_akaike 22:b2e90f18ea55 506
mizuki_akaike 22:b2e90f18ea55 507 //Deselect the card, and return the R1 response token
mizuki_akaike 22:b2e90f18ea55 508 deselect();
mizuki_akaike 22:b2e90f18ea55 509 return token;
mizuki_akaike 22:b2e90f18ea55 510 }
mizuki_akaike 22:b2e90f18ea55 511
mizuki_akaike 22:b2e90f18ea55 512 char SDFileSystem::writeCommand(char cmd, unsigned int arg, unsigned int* resp)
mizuki_akaike 22:b2e90f18ea55 513 {
mizuki_akaike 22:b2e90f18ea55 514 char token;
mizuki_akaike 22:b2e90f18ea55 515
mizuki_akaike 22:b2e90f18ea55 516 //Try to send the command up to 3 times
mizuki_akaike 22:b2e90f18ea55 517 for (int f = 0; f < 3; f++) {
mizuki_akaike 22:b2e90f18ea55 518 //Send CMD55(0x00000000) prior to an application specific command
mizuki_akaike 22:b2e90f18ea55 519 if (cmd == ACMD22 || cmd == ACMD23 || cmd == ACMD41 || cmd == ACMD42) {
mizuki_akaike 22:b2e90f18ea55 520 token = writeCommand(CMD55, 0x00000000);
mizuki_akaike 22:b2e90f18ea55 521 if (token > 0x01)
mizuki_akaike 22:b2e90f18ea55 522 return token;
mizuki_akaike 22:b2e90f18ea55 523
mizuki_akaike 22:b2e90f18ea55 524 //Deselect and reselect the card between CMD55 and an ACMD
mizuki_akaike 22:b2e90f18ea55 525 deselect();
mizuki_akaike 22:b2e90f18ea55 526 if(!select())
mizuki_akaike 22:b2e90f18ea55 527 return 0xFF;
mizuki_akaike 22:b2e90f18ea55 528 }
mizuki_akaike 22:b2e90f18ea55 529
mizuki_akaike 22:b2e90f18ea55 530 //Prepare the command packet
mizuki_akaike 22:b2e90f18ea55 531 char cmdPacket[6];
mizuki_akaike 22:b2e90f18ea55 532 cmdPacket[0] = cmd;
mizuki_akaike 22:b2e90f18ea55 533 cmdPacket[1] = arg >> 24;
mizuki_akaike 22:b2e90f18ea55 534 cmdPacket[2] = arg >> 16;
mizuki_akaike 22:b2e90f18ea55 535 cmdPacket[3] = arg >> 8;
mizuki_akaike 22:b2e90f18ea55 536 cmdPacket[4] = arg;
mizuki_akaike 22:b2e90f18ea55 537 if (m_Crc || cmd == CMD0 || cmd == CMD8)
mizuki_akaike 22:b2e90f18ea55 538 cmdPacket[5] = (SDCRC::crc7(cmdPacket, 5) << 1) | 0x01;
mizuki_akaike 22:b2e90f18ea55 539 else
mizuki_akaike 22:b2e90f18ea55 540 cmdPacket[5] = 0x01;
mizuki_akaike 22:b2e90f18ea55 541
mizuki_akaike 22:b2e90f18ea55 542 //Send the command packet
mizuki_akaike 22:b2e90f18ea55 543 for (int i = 0; i < 6; i++)
mizuki_akaike 22:b2e90f18ea55 544 m_Spi.write(cmdPacket[i]);
mizuki_akaike 22:b2e90f18ea55 545
mizuki_akaike 22:b2e90f18ea55 546 //Discard the stuff byte immediately following CMD12
mizuki_akaike 22:b2e90f18ea55 547 if (cmd == CMD12)
mizuki_akaike 22:b2e90f18ea55 548 m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 549
mizuki_akaike 22:b2e90f18ea55 550 //Allow up to 8 bytes of delay for the R1 response token
mizuki_akaike 22:b2e90f18ea55 551 for (int i = 0; i < 9; i++) {
mizuki_akaike 22:b2e90f18ea55 552 token = m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 553 if (!(token & 0x80))
mizuki_akaike 22:b2e90f18ea55 554 break;
mizuki_akaike 22:b2e90f18ea55 555 }
mizuki_akaike 22:b2e90f18ea55 556
mizuki_akaike 22:b2e90f18ea55 557 //Verify the R1 response token
mizuki_akaike 22:b2e90f18ea55 558 if (token == 0xFF) {
mizuki_akaike 22:b2e90f18ea55 559 //No data was received, get out early
mizuki_akaike 22:b2e90f18ea55 560 break;
mizuki_akaike 22:b2e90f18ea55 561 } else if (token & (1 << 3)) {
mizuki_akaike 22:b2e90f18ea55 562 //There was a CRC error, try again
mizuki_akaike 22:b2e90f18ea55 563 continue;
mizuki_akaike 22:b2e90f18ea55 564 } else if (token > 0x01) {
mizuki_akaike 22:b2e90f18ea55 565 //An error occured, get out early
mizuki_akaike 22:b2e90f18ea55 566 break;
mizuki_akaike 22:b2e90f18ea55 567 }
mizuki_akaike 22:b2e90f18ea55 568
mizuki_akaike 22:b2e90f18ea55 569 //Handle R2 and R3/R7 response tokens
mizuki_akaike 22:b2e90f18ea55 570 if (cmd == CMD13 && resp != NULL) {
mizuki_akaike 22:b2e90f18ea55 571 //Read the R2 response value
mizuki_akaike 22:b2e90f18ea55 572 *resp = m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 573 } else if ((cmd == CMD8 || cmd == CMD58) && resp != NULL) {
mizuki_akaike 22:b2e90f18ea55 574 //Read the R3/R7 response value
mizuki_akaike 22:b2e90f18ea55 575 *resp = (m_Spi.write(0xFF) << 24);
mizuki_akaike 22:b2e90f18ea55 576 *resp |= (m_Spi.write(0xFF) << 16);
mizuki_akaike 22:b2e90f18ea55 577 *resp |= (m_Spi.write(0xFF) << 8);
mizuki_akaike 22:b2e90f18ea55 578 *resp |= m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 579 }
mizuki_akaike 22:b2e90f18ea55 580
mizuki_akaike 22:b2e90f18ea55 581 //The command was successful
mizuki_akaike 22:b2e90f18ea55 582 break;
mizuki_akaike 22:b2e90f18ea55 583 }
mizuki_akaike 22:b2e90f18ea55 584
mizuki_akaike 22:b2e90f18ea55 585 //Return the R1 response token
mizuki_akaike 22:b2e90f18ea55 586 return token;
mizuki_akaike 22:b2e90f18ea55 587 }
mizuki_akaike 22:b2e90f18ea55 588
mizuki_akaike 22:b2e90f18ea55 589 bool SDFileSystem::readData(char* buffer, int length)
mizuki_akaike 22:b2e90f18ea55 590 {
mizuki_akaike 22:b2e90f18ea55 591 char token;
mizuki_akaike 22:b2e90f18ea55 592 unsigned short crc;
mizuki_akaike 22:b2e90f18ea55 593
mizuki_akaike 22:b2e90f18ea55 594 //Wait for up to 500ms for a token to arrive
mizuki_akaike 22:b2e90f18ea55 595 m_Timer.start();
mizuki_akaike 22:b2e90f18ea55 596 do {
mizuki_akaike 22:b2e90f18ea55 597 token = m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 598 } while (token == 0xFF && m_Timer.read_ms() < 500);
mizuki_akaike 22:b2e90f18ea55 599 m_Timer.stop();
mizuki_akaike 22:b2e90f18ea55 600 m_Timer.reset();
mizuki_akaike 22:b2e90f18ea55 601
mizuki_akaike 22:b2e90f18ea55 602 //Check if a valid start block token was received
mizuki_akaike 22:b2e90f18ea55 603 if (token != 0xFE)
mizuki_akaike 22:b2e90f18ea55 604 return false;
mizuki_akaike 22:b2e90f18ea55 605
mizuki_akaike 22:b2e90f18ea55 606 //Check if large frames are enabled or not
mizuki_akaike 22:b2e90f18ea55 607 if (m_LargeFrames) {
mizuki_akaike 22:b2e90f18ea55 608 //Switch to 16-bit frames for better performance
mizuki_akaike 22:b2e90f18ea55 609 m_Spi.format(16, 0);
mizuki_akaike 22:b2e90f18ea55 610
mizuki_akaike 22:b2e90f18ea55 611 //Read the data block into the buffer
mizuki_akaike 22:b2e90f18ea55 612 unsigned short dataWord;
mizuki_akaike 22:b2e90f18ea55 613 for (int i = 0; i < length; i += 2) {
mizuki_akaike 22:b2e90f18ea55 614 dataWord = m_Spi.write(0xFFFF);
mizuki_akaike 22:b2e90f18ea55 615 buffer[i] = dataWord >> 8;
mizuki_akaike 22:b2e90f18ea55 616 buffer[i + 1] = dataWord;
mizuki_akaike 22:b2e90f18ea55 617 }
mizuki_akaike 22:b2e90f18ea55 618
mizuki_akaike 22:b2e90f18ea55 619 //Read the CRC16 checksum for the data block
mizuki_akaike 22:b2e90f18ea55 620 crc = m_Spi.write(0xFFFF);
mizuki_akaike 22:b2e90f18ea55 621
mizuki_akaike 22:b2e90f18ea55 622 //Switch back to 8-bit frames
mizuki_akaike 22:b2e90f18ea55 623 m_Spi.format(8, 0);
mizuki_akaike 22:b2e90f18ea55 624 } else {
mizuki_akaike 22:b2e90f18ea55 625 //Read the data into the buffer
mizuki_akaike 22:b2e90f18ea55 626 for (int i = 0; i < length; i++)
mizuki_akaike 22:b2e90f18ea55 627 buffer[i] = m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 628
mizuki_akaike 22:b2e90f18ea55 629 //Read the CRC16 checksum for the data block
mizuki_akaike 22:b2e90f18ea55 630 crc = (m_Spi.write(0xFF) << 8);
mizuki_akaike 22:b2e90f18ea55 631 crc |= m_Spi.write(0xFF);
mizuki_akaike 22:b2e90f18ea55 632 }
mizuki_akaike 22:b2e90f18ea55 633
mizuki_akaike 22:b2e90f18ea55 634 //Return the validity of the CRC16 checksum (if enabled)
mizuki_akaike 22:b2e90f18ea55 635 return (!m_Crc || crc == SDCRC::crc16(buffer, length));
mizuki_akaike 22:b2e90f18ea55 636 }
mizuki_akaike 22:b2e90f18ea55 637
mizuki_akaike 22:b2e90f18ea55 638 char SDFileSystem::writeData(const char* buffer, char token)
mizuki_akaike 22:b2e90f18ea55 639 {
mizuki_akaike 22:b2e90f18ea55 640 //Calculate the CRC16 checksum for the data block (if enabled)
mizuki_akaike 22:b2e90f18ea55 641 unsigned short crc = (m_Crc) ? SDCRC::crc16(buffer, 512) : 0xFFFF;
mizuki_akaike 22:b2e90f18ea55 642
mizuki_akaike 22:b2e90f18ea55 643 //Wait for up to 500ms for the card to become ready
mizuki_akaike 22:b2e90f18ea55 644 if (!waitReady(500))
mizuki_akaike 22:b2e90f18ea55 645 return false;
mizuki_akaike 22:b2e90f18ea55 646
mizuki_akaike 22:b2e90f18ea55 647 //Send the start block token
mizuki_akaike 22:b2e90f18ea55 648 m_Spi.write(token);
mizuki_akaike 22:b2e90f18ea55 649
mizuki_akaike 22:b2e90f18ea55 650 //Check if large frames are enabled or not
mizuki_akaike 22:b2e90f18ea55 651 if (m_LargeFrames) {
mizuki_akaike 22:b2e90f18ea55 652 //Switch to 16-bit frames for better performance
mizuki_akaike 22:b2e90f18ea55 653 m_Spi.format(16, 0);
mizuki_akaike 22:b2e90f18ea55 654
mizuki_akaike 22:b2e90f18ea55 655 //Write the data block from the buffer
mizuki_akaike 22:b2e90f18ea55 656 for (int i = 0; i < 512; i += 2)
mizuki_akaike 22:b2e90f18ea55 657 m_Spi.write((buffer[i] << 8) | buffer[i + 1]);
mizuki_akaike 22:b2e90f18ea55 658
mizuki_akaike 22:b2e90f18ea55 659 //Send the CRC16 checksum for the data block
mizuki_akaike 22:b2e90f18ea55 660 m_Spi.write(crc);
mizuki_akaike 22:b2e90f18ea55 661
mizuki_akaike 22:b2e90f18ea55 662 //Switch back to 8-bit frames
mizuki_akaike 22:b2e90f18ea55 663 m_Spi.format(8, 0);
mizuki_akaike 22:b2e90f18ea55 664 } else {
mizuki_akaike 22:b2e90f18ea55 665 //Write the data block from the buffer
mizuki_akaike 22:b2e90f18ea55 666 for (int i = 0; i < 512; i++)
mizuki_akaike 22:b2e90f18ea55 667 m_Spi.write(buffer[i]);
mizuki_akaike 22:b2e90f18ea55 668
mizuki_akaike 22:b2e90f18ea55 669 //Send the CRC16 checksum for the data block
mizuki_akaike 22:b2e90f18ea55 670 m_Spi.write(crc >> 8);
mizuki_akaike 22:b2e90f18ea55 671 m_Spi.write(crc);
mizuki_akaike 22:b2e90f18ea55 672 }
mizuki_akaike 22:b2e90f18ea55 673
mizuki_akaike 22:b2e90f18ea55 674 //Return the data response token
mizuki_akaike 22:b2e90f18ea55 675 return (m_Spi.write(0xFF) & 0x1F);
mizuki_akaike 22:b2e90f18ea55 676 }
mizuki_akaike 22:b2e90f18ea55 677
mizuki_akaike 22:b2e90f18ea55 678 inline bool SDFileSystem::readBlock(char* buffer, unsigned int lba)
mizuki_akaike 22:b2e90f18ea55 679 {
mizuki_akaike 22:b2e90f18ea55 680 //Try to read the block up to 3 times
mizuki_akaike 22:b2e90f18ea55 681 for (int f = 0; f < 3; f++) {
mizuki_akaike 22:b2e90f18ea55 682 //Select the card, and wait for ready
mizuki_akaike 22:b2e90f18ea55 683 if(!select())
mizuki_akaike 22:b2e90f18ea55 684 break;
mizuki_akaike 22:b2e90f18ea55 685
mizuki_akaike 22:b2e90f18ea55 686 //Send CMD17(block) to read a single block
mizuki_akaike 22:b2e90f18ea55 687 if (writeCommand(CMD17, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 688 //Try to read the block, and deselect the card
mizuki_akaike 22:b2e90f18ea55 689 bool success = readData(buffer, 512);
mizuki_akaike 22:b2e90f18ea55 690 deselect();
mizuki_akaike 22:b2e90f18ea55 691
mizuki_akaike 22:b2e90f18ea55 692 //Return if successful
mizuki_akaike 22:b2e90f18ea55 693 if (success)
mizuki_akaike 22:b2e90f18ea55 694 return true;
mizuki_akaike 22:b2e90f18ea55 695 } else {
mizuki_akaike 22:b2e90f18ea55 696 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 697 break;
mizuki_akaike 22:b2e90f18ea55 698 }
mizuki_akaike 22:b2e90f18ea55 699 }
mizuki_akaike 22:b2e90f18ea55 700
mizuki_akaike 22:b2e90f18ea55 701 //The single block read failed
mizuki_akaike 22:b2e90f18ea55 702 deselect();
mizuki_akaike 22:b2e90f18ea55 703 return false;
mizuki_akaike 22:b2e90f18ea55 704 }
mizuki_akaike 22:b2e90f18ea55 705
mizuki_akaike 22:b2e90f18ea55 706 inline bool SDFileSystem::readBlocks(char* buffer, unsigned int lba, unsigned int count)
mizuki_akaike 22:b2e90f18ea55 707 {
mizuki_akaike 22:b2e90f18ea55 708 //Try to read each block up to 3 times
mizuki_akaike 22:b2e90f18ea55 709 for (int f = 0; f < 3;) {
mizuki_akaike 22:b2e90f18ea55 710 //Select the card, and wait for ready
mizuki_akaike 22:b2e90f18ea55 711 if(!select())
mizuki_akaike 22:b2e90f18ea55 712 break;
mizuki_akaike 22:b2e90f18ea55 713
mizuki_akaike 22:b2e90f18ea55 714 //Send CMD18(block) to read multiple blocks
mizuki_akaike 22:b2e90f18ea55 715 if (writeCommand(CMD18, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 716 //Try to read all of the data blocks
mizuki_akaike 22:b2e90f18ea55 717 do {
mizuki_akaike 22:b2e90f18ea55 718 //Read the next block, and break on errors
mizuki_akaike 22:b2e90f18ea55 719 if (!readData(buffer, 512)) {
mizuki_akaike 22:b2e90f18ea55 720 f++;
mizuki_akaike 22:b2e90f18ea55 721 break;
mizuki_akaike 22:b2e90f18ea55 722 }
mizuki_akaike 22:b2e90f18ea55 723
mizuki_akaike 22:b2e90f18ea55 724 //Update the variables
mizuki_akaike 22:b2e90f18ea55 725 lba++;
mizuki_akaike 22:b2e90f18ea55 726 buffer += 512;
mizuki_akaike 22:b2e90f18ea55 727 f = 0;
mizuki_akaike 22:b2e90f18ea55 728 } while (--count);
mizuki_akaike 22:b2e90f18ea55 729
mizuki_akaike 22:b2e90f18ea55 730 //Send CMD12(0x00000000) to stop the transmission
mizuki_akaike 22:b2e90f18ea55 731 if (writeCommand(CMD12, 0x00000000) != 0x00) {
mizuki_akaike 22:b2e90f18ea55 732 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 733 break;
mizuki_akaike 22:b2e90f18ea55 734 }
mizuki_akaike 22:b2e90f18ea55 735
mizuki_akaike 22:b2e90f18ea55 736 //Deselect the card, and return if successful
mizuki_akaike 22:b2e90f18ea55 737 deselect();
mizuki_akaike 22:b2e90f18ea55 738 if (count == 0)
mizuki_akaike 22:b2e90f18ea55 739 return true;
mizuki_akaike 22:b2e90f18ea55 740 } else {
mizuki_akaike 22:b2e90f18ea55 741 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 742 break;
mizuki_akaike 22:b2e90f18ea55 743 }
mizuki_akaike 22:b2e90f18ea55 744 }
mizuki_akaike 22:b2e90f18ea55 745
mizuki_akaike 22:b2e90f18ea55 746 //The multiple block read failed
mizuki_akaike 22:b2e90f18ea55 747 deselect();
mizuki_akaike 22:b2e90f18ea55 748 return false;
mizuki_akaike 22:b2e90f18ea55 749 }
mizuki_akaike 22:b2e90f18ea55 750
mizuki_akaike 22:b2e90f18ea55 751 inline bool SDFileSystem::writeBlock(const char* buffer, unsigned int lba)
mizuki_akaike 22:b2e90f18ea55 752 {
mizuki_akaike 22:b2e90f18ea55 753 //Try to write the block up to 3 times
mizuki_akaike 22:b2e90f18ea55 754 for (int f = 0; f < 3; f++) {
mizuki_akaike 22:b2e90f18ea55 755 //Select the card, and wait for ready
mizuki_akaike 22:b2e90f18ea55 756 if(!select())
mizuki_akaike 22:b2e90f18ea55 757 break;
mizuki_akaike 22:b2e90f18ea55 758
mizuki_akaike 22:b2e90f18ea55 759 //Send CMD24(block) to write a single block
mizuki_akaike 22:b2e90f18ea55 760 if (writeCommand(CMD24, (m_CardType == CARD_SDHC) ? lba : lba << 9) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 761 //Try to write the block, and deselect the card
mizuki_akaike 22:b2e90f18ea55 762 char token = writeData(buffer, 0xFE);
mizuki_akaike 22:b2e90f18ea55 763 deselect();
mizuki_akaike 22:b2e90f18ea55 764
mizuki_akaike 22:b2e90f18ea55 765 //Check the data response token
mizuki_akaike 22:b2e90f18ea55 766 if (token == 0x0A) {
mizuki_akaike 22:b2e90f18ea55 767 //A CRC error occured, try again
mizuki_akaike 22:b2e90f18ea55 768 continue;
mizuki_akaike 22:b2e90f18ea55 769 } else if (token == 0x0C) {
mizuki_akaike 22:b2e90f18ea55 770 //A write error occured, get out
mizuki_akaike 22:b2e90f18ea55 771 break;
mizuki_akaike 22:b2e90f18ea55 772 }
mizuki_akaike 22:b2e90f18ea55 773
mizuki_akaike 22:b2e90f18ea55 774 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
mizuki_akaike 22:b2e90f18ea55 775 if (m_WriteValidation) {
mizuki_akaike 22:b2e90f18ea55 776 unsigned int resp;
mizuki_akaike 22:b2e90f18ea55 777 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
mizuki_akaike 22:b2e90f18ea55 778 //Some manner of unrecoverable write error occured during programming, get out
mizuki_akaike 22:b2e90f18ea55 779 break;
mizuki_akaike 22:b2e90f18ea55 780 }
mizuki_akaike 22:b2e90f18ea55 781 }
mizuki_akaike 22:b2e90f18ea55 782
mizuki_akaike 22:b2e90f18ea55 783 //The data was written successfully
mizuki_akaike 22:b2e90f18ea55 784 return true;
mizuki_akaike 22:b2e90f18ea55 785 } else {
mizuki_akaike 22:b2e90f18ea55 786 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 787 break;
mizuki_akaike 22:b2e90f18ea55 788 }
mizuki_akaike 22:b2e90f18ea55 789 }
mizuki_akaike 22:b2e90f18ea55 790
mizuki_akaike 22:b2e90f18ea55 791 //The single block write failed
mizuki_akaike 22:b2e90f18ea55 792 deselect();
mizuki_akaike 22:b2e90f18ea55 793 return false;
mizuki_akaike 22:b2e90f18ea55 794 }
mizuki_akaike 22:b2e90f18ea55 795
mizuki_akaike 22:b2e90f18ea55 796 inline bool SDFileSystem::writeBlocks(const char* buffer, unsigned int lba, unsigned int count)
mizuki_akaike 22:b2e90f18ea55 797 {
mizuki_akaike 22:b2e90f18ea55 798 char token;
mizuki_akaike 22:b2e90f18ea55 799 const char* currentBuffer = buffer;
mizuki_akaike 22:b2e90f18ea55 800 unsigned int currentLba = lba;
mizuki_akaike 22:b2e90f18ea55 801 int currentCount = count;
mizuki_akaike 22:b2e90f18ea55 802
mizuki_akaike 22:b2e90f18ea55 803 //Try to write each block up to 3 times
mizuki_akaike 22:b2e90f18ea55 804 for (int f = 0; f < 3;) {
mizuki_akaike 22:b2e90f18ea55 805 //If this is an SD card, send ACMD23(count) to set the number of blocks to pre-erase
mizuki_akaike 22:b2e90f18ea55 806 if (m_CardType != CARD_MMC) {
mizuki_akaike 22:b2e90f18ea55 807 if (commandTransaction(ACMD23, currentCount) != 0x00) {
mizuki_akaike 22:b2e90f18ea55 808 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 809 break;
mizuki_akaike 22:b2e90f18ea55 810 }
mizuki_akaike 22:b2e90f18ea55 811 }
mizuki_akaike 22:b2e90f18ea55 812
mizuki_akaike 22:b2e90f18ea55 813 //Select the card, and wait for ready
mizuki_akaike 22:b2e90f18ea55 814 if(!select())
mizuki_akaike 22:b2e90f18ea55 815 break;
mizuki_akaike 22:b2e90f18ea55 816
mizuki_akaike 22:b2e90f18ea55 817 //Send CMD25(block) to write multiple blocks
mizuki_akaike 22:b2e90f18ea55 818 if (writeCommand(CMD25, (m_CardType == CARD_SDHC) ? currentLba : currentLba << 9) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 819 //Try to write all of the data blocks
mizuki_akaike 22:b2e90f18ea55 820 do {
mizuki_akaike 22:b2e90f18ea55 821 //Write the next block and break on errors
mizuki_akaike 22:b2e90f18ea55 822 token = writeData(currentBuffer, 0xFC);
mizuki_akaike 22:b2e90f18ea55 823 if (token != 0x05) {
mizuki_akaike 22:b2e90f18ea55 824 f++;
mizuki_akaike 22:b2e90f18ea55 825 break;
mizuki_akaike 22:b2e90f18ea55 826 }
mizuki_akaike 22:b2e90f18ea55 827
mizuki_akaike 22:b2e90f18ea55 828 //Update the variables
mizuki_akaike 22:b2e90f18ea55 829 currentBuffer += 512;
mizuki_akaike 22:b2e90f18ea55 830 f = 0;
mizuki_akaike 22:b2e90f18ea55 831 } while (--currentCount);
mizuki_akaike 22:b2e90f18ea55 832
mizuki_akaike 22:b2e90f18ea55 833 //Wait for up to 500ms for the card to finish processing the last block
mizuki_akaike 22:b2e90f18ea55 834 if (!waitReady(500))
mizuki_akaike 22:b2e90f18ea55 835 break;
mizuki_akaike 22:b2e90f18ea55 836
mizuki_akaike 22:b2e90f18ea55 837 //Finalize the transmission
mizuki_akaike 22:b2e90f18ea55 838 if (currentCount == 0) {
mizuki_akaike 22:b2e90f18ea55 839 //Send the stop tran token, and deselect the card
mizuki_akaike 22:b2e90f18ea55 840 m_Spi.write(0xFD);
mizuki_akaike 22:b2e90f18ea55 841 deselect();
mizuki_akaike 22:b2e90f18ea55 842
mizuki_akaike 22:b2e90f18ea55 843 //Send CMD13(0x00000000) to verify that the programming was successful if enabled
mizuki_akaike 22:b2e90f18ea55 844 if (m_WriteValidation) {
mizuki_akaike 22:b2e90f18ea55 845 unsigned int resp;
mizuki_akaike 22:b2e90f18ea55 846 if (commandTransaction(CMD13, 0x00000000, &resp) != 0x00 || resp != 0x00) {
mizuki_akaike 22:b2e90f18ea55 847 //Some manner of unrecoverable write error occured during programming, get out
mizuki_akaike 22:b2e90f18ea55 848 break;
mizuki_akaike 22:b2e90f18ea55 849 }
mizuki_akaike 22:b2e90f18ea55 850 }
mizuki_akaike 22:b2e90f18ea55 851
mizuki_akaike 22:b2e90f18ea55 852 //The data was written successfully
mizuki_akaike 22:b2e90f18ea55 853 return true;
mizuki_akaike 22:b2e90f18ea55 854 } else {
mizuki_akaike 22:b2e90f18ea55 855 //Send CMD12(0x00000000) to abort the transmission
mizuki_akaike 22:b2e90f18ea55 856 if (writeCommand(CMD12, 0x00000000) != 0x00) {
mizuki_akaike 22:b2e90f18ea55 857 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 858 break;
mizuki_akaike 22:b2e90f18ea55 859 }
mizuki_akaike 22:b2e90f18ea55 860
mizuki_akaike 22:b2e90f18ea55 861 //Deselect the card
mizuki_akaike 22:b2e90f18ea55 862 deselect();
mizuki_akaike 22:b2e90f18ea55 863
mizuki_akaike 22:b2e90f18ea55 864 //Check the error token
mizuki_akaike 22:b2e90f18ea55 865 if (token == 0x0A) {
mizuki_akaike 22:b2e90f18ea55 866 //Determine the number of well written blocks if possible
mizuki_akaike 22:b2e90f18ea55 867 unsigned int writtenBlocks = 0;
mizuki_akaike 22:b2e90f18ea55 868 if (m_CardType != CARD_MMC && select()) {
mizuki_akaike 22:b2e90f18ea55 869 //Send ACMD22(0x00000000) to get the number of well written blocks
mizuki_akaike 22:b2e90f18ea55 870 if (writeCommand(ACMD22, 0x00000000) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 871 //Read the data
mizuki_akaike 22:b2e90f18ea55 872 char acmdData[4];
mizuki_akaike 22:b2e90f18ea55 873 if (readData(acmdData, 4)) {
mizuki_akaike 22:b2e90f18ea55 874 //Extract the number of well written blocks
mizuki_akaike 22:b2e90f18ea55 875 writtenBlocks = acmdData[0] << 24;
mizuki_akaike 22:b2e90f18ea55 876 writtenBlocks |= acmdData[1] << 16;
mizuki_akaike 22:b2e90f18ea55 877 writtenBlocks |= acmdData[2] << 8;
mizuki_akaike 22:b2e90f18ea55 878 writtenBlocks |= acmdData[3];
mizuki_akaike 22:b2e90f18ea55 879 }
mizuki_akaike 22:b2e90f18ea55 880 }
mizuki_akaike 22:b2e90f18ea55 881 deselect();
mizuki_akaike 22:b2e90f18ea55 882 }
mizuki_akaike 22:b2e90f18ea55 883
mizuki_akaike 22:b2e90f18ea55 884 //Roll back the variables based on the number of well written blocks
mizuki_akaike 22:b2e90f18ea55 885 currentBuffer = buffer + (writtenBlocks << 9);
mizuki_akaike 22:b2e90f18ea55 886 currentLba = lba + writtenBlocks;
mizuki_akaike 22:b2e90f18ea55 887 currentCount = count - writtenBlocks;
mizuki_akaike 22:b2e90f18ea55 888
mizuki_akaike 22:b2e90f18ea55 889 //Try again
mizuki_akaike 22:b2e90f18ea55 890 continue;
mizuki_akaike 22:b2e90f18ea55 891 } else {
mizuki_akaike 22:b2e90f18ea55 892 //A write error occured, get out
mizuki_akaike 22:b2e90f18ea55 893 break;
mizuki_akaike 22:b2e90f18ea55 894 }
mizuki_akaike 22:b2e90f18ea55 895 }
mizuki_akaike 22:b2e90f18ea55 896 } else {
mizuki_akaike 22:b2e90f18ea55 897 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 898 break;
mizuki_akaike 22:b2e90f18ea55 899 }
mizuki_akaike 22:b2e90f18ea55 900 }
mizuki_akaike 22:b2e90f18ea55 901
mizuki_akaike 22:b2e90f18ea55 902 //The multiple block write failed
mizuki_akaike 22:b2e90f18ea55 903 deselect();
mizuki_akaike 22:b2e90f18ea55 904 return false;
mizuki_akaike 22:b2e90f18ea55 905 }
mizuki_akaike 22:b2e90f18ea55 906
mizuki_akaike 22:b2e90f18ea55 907 bool SDFileSystem::enableHighSpeedMode()
mizuki_akaike 22:b2e90f18ea55 908 {
mizuki_akaike 22:b2e90f18ea55 909 //Try to issue CMD6 up to 3 times
mizuki_akaike 22:b2e90f18ea55 910 for (int f = 0; f < 3; f++) {
mizuki_akaike 22:b2e90f18ea55 911 //Select the card, and wait for ready
mizuki_akaike 22:b2e90f18ea55 912 if(!select())
mizuki_akaike 22:b2e90f18ea55 913 break;
mizuki_akaike 22:b2e90f18ea55 914
mizuki_akaike 22:b2e90f18ea55 915 //Send CMD6(0x80FFFFF1) to change the access mode to high speed
mizuki_akaike 22:b2e90f18ea55 916 if (writeCommand(CMD6, 0x80FFFFF1) == 0x00) {
mizuki_akaike 22:b2e90f18ea55 917 //Read the 64B status data block
mizuki_akaike 22:b2e90f18ea55 918 char status[64];
mizuki_akaike 22:b2e90f18ea55 919 bool success = readData(status, 64);
mizuki_akaike 22:b2e90f18ea55 920 deselect();
mizuki_akaike 22:b2e90f18ea55 921 if (success) {
mizuki_akaike 22:b2e90f18ea55 922 //Return whether or not the operation was successful
mizuki_akaike 22:b2e90f18ea55 923 return ((status[16] & 0x0F) == 0x1);
mizuki_akaike 22:b2e90f18ea55 924 }
mizuki_akaike 22:b2e90f18ea55 925 } else {
mizuki_akaike 22:b2e90f18ea55 926 //The command failed, get out
mizuki_akaike 22:b2e90f18ea55 927 break;
mizuki_akaike 22:b2e90f18ea55 928 }
mizuki_akaike 22:b2e90f18ea55 929 }
mizuki_akaike 22:b2e90f18ea55 930
mizuki_akaike 22:b2e90f18ea55 931 //The operation failed 3 times
mizuki_akaike 22:b2e90f18ea55 932 deselect();
mizuki_akaike 22:b2e90f18ea55 933 return false;
mizuki_akaike 22:b2e90f18ea55 934 }