Example of using the SDFileSystem library on a K64F to write data to files and also read data into dynamically created arrays.

Dependencies:   mbed

Committer:
eencae
Date:
Mon Feb 03 12:06:21 2020 +0000
Revision:
1:caceb9d9d17a
Updated Mbed library. Removed serial. Confirmed working Jan 2020.

Who changed what in which revision?

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