Paul's baseline branch

Dependents:   Multi-FileSystem

Fork of SDFileSystem by David Smart

Committer:
neilt6
Date:
Tue Dec 08 16:02:44 2015 +0000
Revision:
20:2c1e8d442f68
Parent:
18:2286a4e7fa31
Child:
21:d10a519c0910
Improved card detection logic

Who changed what in which revision?

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