No change from original version.

Dependencies:   FATFileSystem

Dependents:   SDFile_Logger

Fork of SDFileSystem by Neil Thiessen

Committer:
neilt6
Date:
Thu Aug 14 22:27:07 2014 +0000
Revision:
11:67ddc53e3983
Parent:
10:395539a1481a
Child:
12:eebddab6eff2
Major performance improvements with custom FATFileSystem

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