SDFileSystem library for FAT compatible

Dependencies:   FATFileSystem

Committer:
sameera0824
Date:
Thu Oct 13 10:51:33 2016 +0000
Revision:
0:583b9f0b91e7
adding SD

Who changed what in which revision?

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