A re-written SDFileSystem library with improved compatibility, CRC support, and card removal/replacement support.

Dependencies:   FATFileSystem

Dependents:   xadow_m0_SD_Hello roam_v1 roam_v2 Polytech_tours ... more

Committer:
neilt6
Date:
Mon Aug 29 15:05:27 2016 +0000
Revision:
26:e4d2567200db
Parent:
25:923df4ee70c4
Updated FATFileSystem

Who changed what in which revision?

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