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 18 15:09:52 2014 +0000
Revision:
13:635147efa748
Parent:
12:eebddab6eff2
Child:
15:c9e938f6934f
Significant performance improvements with better busy wait logic

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