Amundson OCE 360 homework 7 SD card library

Dependencies:   FATFileSystem

Fork of SDFileSystem by Neil Thiessen

Committer:
bamundson
Date:
Sat Nov 03 19:11:15 2018 +0000
Revision:
27:70654d2bcff8
Parent:
25:923df4ee70c4
Amundson OCE 360 Homework 7, collect temperature and time data to be written and stored to an SD card. Controlled by switch input.

Who changed what in which revision?

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