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

Dependencies:   FATFileSystem

Fork of SDFileSystem by Neil Thiessen

Committer:
jaerts
Date:
Mon Dec 29 15:26:39 2014 +0000
Revision:
16:dca379d55382
Parent:
15:c9e938f6934f
Add support for no card detect switch

Who changed what in which revision?

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