fat32

Dependencies:   FATFileSystem

Dependents:   MW771LP-2seam

Fork of SDFileSystem by Neil Thiessen

Committer:
vnemera
Date:
Fri Feb 17 16:43:38 2017 +0000
Revision:
22:d3fc9553df84
Parent:
21:d10a519c0910
1.4.4

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