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 Oct 27 17:02:05 2014 +0000
Revision:
15:c9e938f6934f
Parent:
13:635147efa748
Child:
16:c2c1f0b16380
Added code to enable the internal pull-up resistor on MISO

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