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:
Wed Jul 08 16:45:12 2015 +0000
Revision:
17:a47f74caa04e
Parent:
16:c2c1f0b16380
Child:
18:2286a4e7fa31
Internal data type changes

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