A re-written SDFileSystem library with improved compatibility, CRC support, and card removal/replacement support.

Dependencies:   FATFileSystem

Dependents:   xadow_m0_SD_Hello roam_v1 roam_v2 Polytech_tours ... more

Committer:
neilt6
Date:
Fri Aug 15 17:54:13 2014 +0000
Revision:
12:eebddab6eff2
Parent:
11:67ddc53e3983
Child:
13:635147efa748
New switch types & minor improvements

Who changed what in which revision?

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